<commit_before>package client

import (
	"crypto"
	"fmt"
	"io"
	"math"

	tpmpb "github.com/google/go-tpm-tools/proto"
	"github.com/google/go-tpm/tpm2"
)

// NumPCRs is set to the spec minimum of 24, as that's all go-tpm supports.
const NumPCRs = 24

// We hard-code SHA256 as the policy session hash algorithms. Note that this
// differs from the PCR hash algorithm (which selects the bank of PCRs to use)
// and the Public area Name algorithm. We also chose this for compatibility with
// github.com/google/go-tpm/tpm2, as it hardcodes the nameAlg as SHA256 in
// several places. Two constants are used to avoid repeated conversions.
const (
	SessionHashAlg    = crypto.SHA256
	SessionHashAlgTpm = tpm2.AlgSHA256
)

// CertifyHashAlgTpm is the hard-coded algorithm used in certify PCRs.
const CertifyHashAlgTpm = tpm2.AlgSHA256

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// Get a list of selections corresponding to the TPM's implemented PCRs
func implementedPCRs(rw io.ReadWriter) ([]tpm2.PCRSelection, error) {
	caps, moreData, err := tpm2.GetCapability(rw, tpm2.CapabilityPCRs, math.MaxUint32, 0)
	if err != nil {
		return nil, fmt.Errorf("listing implemented PCR banks: %w", err)
	}
	if moreData {
		return nil, fmt.Errorf("extra data from GetCapability")
	}
	sels := make([]tpm2.PCRSelection, len(caps))
	for i, cap := range caps {
		sel, ok := cap.(tpm2.PCRSelection)
		if !ok {
			return nil, fmt.Errorf("unexpected data from GetCapability")
		}
		sels[i] = sel
	}
	return sels, nil
}

// ReadPCRs fetches all the PCR values specified in sel, making multiple calls
// to the TPM if necessary.
func ReadPCRs(rw io.ReadWriter, sel tpm2.PCRSelection) (*tpmpb.Pcrs, error) {
	pl := tpmpb.Pcrs{
		Hash: tpmpb.HashAlgo(sel.Hash),
		Pcrs: map[uint32][]byte{},
	}

	for i := 0; i < len(sel.PCRs); i += 8 {
		end := min(i+8, len(sel.PCRs))
		pcrSel := tpm2.PCRSelection{
			Hash: sel.Hash,
			PCRs: sel.PCRs[i:end],
		}

		pcrMap, err := tpm2.ReadPCRs(rw, pcrSel)
		if err != nil {
			return nil, err
		}

		for pcr, val := range pcrMap {
			pl.Pcrs[uint32(pcr)] = val
		}
	}

	return &pl, nil
}

// ReadAllPCRs fetches all the PCR values from all implemented PCR banks.
func ReadAllPCRs(rw io.ReadWriter) ([]*tpmpb.Pcrs, error) {
	sels, err := implementedPCRs(rw)
	if err != nil {
		return nil, err
	}

	allPcrs := make([]*tpmpb.Pcrs, len(sels))
	for i, sel := range sels {
		allPcrs[i], err = ReadPCRs(rw, sel)
		if err != nil {
			return nil, fmt.Errorf("reading bank %x PCRs: %w", sel.Hash, err)
		}
	}
	return allPcrs, nil
}

// SealCurrent seals data to the current specified PCR selection.
type SealCurrent struct{ tpm2.PCRSelection }

// SealTarget predicatively seals data to the given specified PCR values.
type SealTarget struct{ Pcrs *tpmpb.Pcrs }

// SealOpt specifies the PCR values that should be used for Seal().
type SealOpt interface {
	PCRsForSealing(rw io.ReadWriter) (*tpmpb.Pcrs, error)
}

// PCRsForSealing read from TPM and return the selected PCRs.
func (p SealCurrent) PCRsForSealing(rw io.ReadWriter) (*tpmpb.Pcrs, error) {
	if len(p.PCRSelection.PCRs) == 0 {
		panic("SealCurrent contains 0 PCRs")
	}
	return ReadPCRs(rw, p.PCRSelection)
}

// PCRsForSealing return the target PCRs.
func (p SealTarget) PCRsForSealing(_ io.ReadWriter) (*tpmpb.Pcrs, error) {
	if len(p.Pcrs.GetPcrs()) == 0 {
		panic("SealTarget contains 0 PCRs")
	}
	return p.Pcrs, nil
}

// CertifyCurrent certifies that a selection of current PCRs have the same value when sealing.
// Hash Algorithm in the selection should be CertifyHashAlgTpm.
type CertifyCurrent struct{ tpm2.PCRSelection }

// CertifyExpected certifies that the TPM had a specific set of PCR values when sealing.
// Hash Algorithm in the PCR proto should be CertifyHashAlgTpm.
type CertifyExpected struct{ Pcrs *tpmpb.Pcrs }

// CertifyOpt determines if the given PCR value can pass certification in Unseal().
type CertifyOpt interface {
	CertifyPCRs(rw io.ReadWriter, certified *tpmpb.Pcrs) error
}

// CertifyPCRs from CurrentPCRs will read PCR values from TPM and compare the digest.
func (p CertifyCurrent) CertifyPCRs(rw io.ReadWriter, pcrs *tpmpb.Pcrs) error {
	if len(p.PCRSelection.PCRs) == 0 {
		panic("CertifyCurrent contains 0 PCRs")
	}
	current, err := ReadPCRs(rw, p.PCRSelection)
	if err != nil {
		return err
	}
	return current.CheckIfSubsetOf(pcrs)
}

// CertifyPCRs will compare the digest with given expected PCRs values.
func (p CertifyExpected) CertifyPCRs(_ io.ReadWriter, pcrs *tpmpb.Pcrs) error {
	if len(p.Pcrs.GetPcrs()) == 0 {
		panic("CertifyExpected contains 0 PCRs")
	}
	return p.Pcrs.CheckIfSubsetOf(pcrs)
}

// FullPcrSel will return a full PCR selection based on the total PCR number
// of the TPM with the given hash algo.
func FullPcrSel(hash tpm2.Algorithm) tpm2.PCRSelection {
	sel := tpm2.PCRSelection{Hash: hash}
	for i := 0; i < NumPCRs; i++ {
		sel.PCRs = append(sel.PCRs, int(i))
	}
	return sel
}
<commit_msg>client: remove field name SealTarget and CertifyExpected<commit_after>package client

import (
	"crypto"
	"fmt"
	"io"
	"math"

	tpmpb "github.com/google/go-tpm-tools/proto"
	"github.com/google/go-tpm/tpm2"
)

// NumPCRs is set to the spec minimum of 24, as that's all go-tpm supports.
const NumPCRs = 24

// We hard-code SHA256 as the policy session hash algorithms. Note that this
// differs from the PCR hash algorithm (which selects the bank of PCRs to use)
// and the Public area Name algorithm. We also chose this for compatibility with
// github.com/google/go-tpm/tpm2, as it hardcodes the nameAlg as SHA256 in
// several places. Two constants are used to avoid repeated conversions.
const (
	SessionHashAlg    = crypto.SHA256
	SessionHashAlgTpm = tpm2.AlgSHA256
)

// CertifyHashAlgTpm is the hard-coded algorithm used in certify PCRs.
const CertifyHashAlgTpm = tpm2.AlgSHA256

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// Get a list of selections corresponding to the TPM's implemented PCRs
func implementedPCRs(rw io.ReadWriter) ([]tpm2.PCRSelection, error) {
	caps, moreData, err := tpm2.GetCapability(rw, tpm2.CapabilityPCRs, math.MaxUint32, 0)
	if err != nil {
		return nil, fmt.Errorf("listing implemented PCR banks: %w", err)
	}
	if moreData {
		return nil, fmt.Errorf("extra data from GetCapability")
	}
	sels := make([]tpm2.PCRSelection, len(caps))
	for i, cap := range caps {
		sel, ok := cap.(tpm2.PCRSelection)
		if !ok {
			return nil, fmt.Errorf("unexpected data from GetCapability")
		}
		sels[i] = sel
	}
	return sels, nil
}

// ReadPCRs fetches all the PCR values specified in sel, making multiple calls
// to the TPM if necessary.
func ReadPCRs(rw io.ReadWriter, sel tpm2.PCRSelection) (*tpmpb.Pcrs, error) {
	pl := tpmpb.Pcrs{
		Hash: tpmpb.HashAlgo(sel.Hash),
		Pcrs: map[uint32][]byte{},
	}

	for i := 0; i < len(sel.PCRs); i += 8 {
		end := min(i+8, len(sel.PCRs))
		pcrSel := tpm2.PCRSelection{
			Hash: sel.Hash,
			PCRs: sel.PCRs[i:end],
		}

		pcrMap, err := tpm2.ReadPCRs(rw, pcrSel)
		if err != nil {
			return nil, err
		}

		for pcr, val := range pcrMap {
			pl.Pcrs[uint32(pcr)] = val
		}
	}

	return &pl, nil
}

// ReadAllPCRs fetches all the PCR values from all implemented PCR banks.
func ReadAllPCRs(rw io.ReadWriter) ([]*tpmpb.Pcrs, error) {
	sels, err := implementedPCRs(rw)
	if err != nil {
		return nil, err
	}

	allPcrs := make([]*tpmpb.Pcrs, len(sels))
	for i, sel := range sels {
		allPcrs[i], err = ReadPCRs(rw, sel)
		if err != nil {
			return nil, fmt.Errorf("reading bank %x PCRs: %w", sel.Hash, err)
		}
	}
	return allPcrs, nil
}

// SealCurrent seals data to the current specified PCR selection.
type SealCurrent struct{ tpm2.PCRSelection }

// SealTarget predicatively seals data to the given specified PCR values.
type SealTarget struct{ *tpmpb.Pcrs }

// SealOpt specifies the PCR values that should be used for Seal().
type SealOpt interface {
	PCRsForSealing(rw io.ReadWriter) (*tpmpb.Pcrs, error)
}

// PCRsForSealing read from TPM and return the selected PCRs.
func (p SealCurrent) PCRsForSealing(rw io.ReadWriter) (*tpmpb.Pcrs, error) {
	if len(p.PCRSelection.PCRs) == 0 {
		panic("SealCurrent contains 0 PCRs")
	}
	return ReadPCRs(rw, p.PCRSelection)
}

// PCRsForSealing return the target PCRs.
func (p SealTarget) PCRsForSealing(_ io.ReadWriter) (*tpmpb.Pcrs, error) {
	if len(p.Pcrs.GetPcrs()) == 0 {
		panic("SealTarget contains 0 PCRs")
	}
	return p.Pcrs, nil
}

// CertifyCurrent certifies that a selection of current PCRs have the same value when sealing.
// Hash Algorithm in the selection should be CertifyHashAlgTpm.
type CertifyCurrent struct{ tpm2.PCRSelection }

// CertifyExpected certifies that the TPM had a specific set of PCR values when sealing.
// Hash Algorithm in the PCR proto should be CertifyHashAlgTpm.
type CertifyExpected struct{ *tpmpb.Pcrs }

// CertifyOpt determines if the given PCR value can pass certification in Unseal().
type CertifyOpt interface {
	CertifyPCRs(rw io.ReadWriter, certified *tpmpb.Pcrs) error
}

// CertifyPCRs from CurrentPCRs will read PCR values from TPM and compare the digest.
func (p CertifyCurrent) CertifyPCRs(rw io.ReadWriter, pcrs *tpmpb.Pcrs) error {
	if len(p.PCRSelection.PCRs) == 0 {
		panic("CertifyCurrent contains 0 PCRs")
	}
	current, err := ReadPCRs(rw, p.PCRSelection)
	if err != nil {
		return err
	}
	return current.CheckIfSubsetOf(pcrs)
}

// CertifyPCRs will compare the digest with given expected PCRs values.
func (p CertifyExpected) CertifyPCRs(_ io.ReadWriter, pcrs *tpmpb.Pcrs) error {
	if len(p.Pcrs.GetPcrs()) == 0 {
		panic("CertifyExpected contains 0 PCRs")
	}
	return p.Pcrs.CheckIfSubsetOf(pcrs)
}

// FullPcrSel will return a full PCR selection based on the total PCR number
// of the TPM with the given hash algo.
func FullPcrSel(hash tpm2.Algorithm) tpm2.PCRSelection {
	sel := tpm2.PCRSelection{Hash: hash}
	for i := 0; i < NumPCRs; i++ {
		sel.PCRs = append(sel.PCRs, int(i))
	}
	return sel
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/hyperhq/hyper/engine"
	"github.com/hyperhq/hyper/lib/promise"
	"github.com/hyperhq/hyper/utils"
	"github.com/hyperhq/runv/hypervisor/pod"

	gflag "github.com/jessevdk/go-flags"
)

// hyper run [OPTIONS] image [COMMAND] [ARGS...]
func (cli *HyperClient) HyperCmdRun(args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("%s ERROR: Can not accept the 'run' command without argument!\n", os.Args[0])
	}
	var opts struct {
		PodFile       string   `short:"p" long:"podfile" value-name:"\"\"" description:"Create and Run a pod based on the pod file"`
		K8s           string   `short:"k" long:"kubernetes" value-name:"\"\"" description:"Create and Run a pod based on the kubernetes pod file"`
		Yaml          bool     `short:"y" long:"yaml" default:"false" default-mask:"-" description:"Create a pod based on Yaml file"`
		Name          string   `long:"name" value-name:"\"\"" description:"Assign a name to the container"`
		Attach        bool     `long:"attach" default:"true" default-mask:"-" description:"Attach the stdin, stdout and stderr to the container"`
		Workdir       string   `long:"workdir" default:"/" value-name:"\"\"" default-mask:"-" description:"Working directory inside the container"`
		Tty           bool     `long:"tty" default:"true" default-mask:"-" description:"Allocate a pseudo-TTY"`
		Cpu           int      `long:"cpu" default:"1" value-name:"1" default-mask:"-" description:"CPU number for the VM"`
		Memory        int      `long:"memory" default:"128" value-name:"128" default-mask:"-" description:"Memory size (MB) for the VM"`
		Env           []string `long:"env" value-name:"[]" default-mask:"-" description:"Set environment variables"`
		EntryPoint    string   `long:"entrypoint" value-name:"\"\"" default-mask:"-" description:"Overwrite the default ENTRYPOINT of the image"`
		RestartPolicy string   `long:"restart" default:"never" value-name:"\"\"" default-mask:"-" description:"Restart policy to apply when a container exits (never, onFailure, always)"`
		Remove        bool     `long:"rm" default:"false" value-name:"" default-mask:"-" description:"Automatically remove the pod when it exits"`
		Portmap       []string `long:"publish" value-name:"[]" default-mask:"-" description:"Publish a container's port to the host, format: --publish [tcp/udp:]hostPort:containerPort"`
	}

	var parser = gflag.NewParser(&opts, gflag.Default|gflag.IgnoreUnknown)
	parser.Usage = "run [OPTIONS] IMAGE [COMMAND] [ARG...]\n\nCreate a pod, and launch a new VM to run the pod"
	args, err := parser.Parse()
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}
	if opts.PodFile != "" {
		if _, err := os.Stat(opts.PodFile); err != nil {
			return err
		}

		jsonbody, err := ioutil.ReadFile(opts.PodFile)
		if err != nil {
			return err
		}

		if opts.Yaml == true {
			jsonbody, err = cli.ConvertYamlToJson(jsonbody)
			if err != nil {
				return err
			}
		}
		t1 := time.Now()
		podId, err := cli.RunPod(string(jsonbody), opts.Remove)
		if err != nil {
			return err
		}
		fmt.Printf("POD id is %s\n", podId)
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
		return nil
	}
	if opts.K8s != "" {
		var (
			kpod    pod.KPod
			userpod *pod.UserPod
		)
		if _, err := os.Stat(opts.K8s); err != nil {
			return err
		}

		jsonbody, err := ioutil.ReadFile(opts.K8s)
		if err != nil {
			return err
		}
		if opts.Yaml == true {
			jsonbody, err = cli.ConvertYamlToJson(jsonbody)
			if err != nil {
				return err
			}
		}
		if err := json.Unmarshal(jsonbody, &kpod); err != nil {
			return err
		}
		userpod, err = kpod.Convert()
		if err != nil {
			return err
		}
		jsonbody, err = json.Marshal(*userpod)
		if err != nil {
			return err
		}
		t1 := time.Now()
		podId, err := cli.RunPod(string(jsonbody), opts.Remove)
		if err != nil {
			return err
		}
		fmt.Printf("POD id is %s\n", podId)
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
		return nil
	}

	if len(args) == 0 {
		return fmt.Errorf("%s: \"run\" requires a minimum of 1 argument, please provide the image.", os.Args[0])
	}
	var (
		image   = args[1]
		command = []string{}
		env     = []pod.UserEnvironmentVar{}
		ports   = []pod.UserContainerPort{}
		proto   string
		hPort   string
		cPort   string
	)
	if len(args) > 1 {
		command = args[2:]
	}
	if opts.Name == "" {
		fields := strings.Split(image, ":")
		if len(fields) < 2 {
			opts.Name = image + "-" + utils.RandStr(10, "number")
		} else {
			opts.Name = fields[0] + "-" + fields[1] + "-" + utils.RandStr(10, "number")
		}
	}
	if opts.Memory == 0 {
		opts.Memory = 128
	}
	if opts.Cpu == 0 {
		opts.Cpu = 1
	}
	for _, v := range opts.Env {
		if v == "" || !strings.Contains(v, "=") {
			continue
		}
		userEnv := pod.UserEnvironmentVar{
			Env:   v[:strings.Index(v, "=")],
			Value: v[strings.Index(v, "=")+1:],
		}
		env = append(env, userEnv)
	}

	for _, v := range opts.Portmap {
		port := pod.UserContainerPort{}
		fields := strings.Split(v, ":")
		if len(fields) < 2 {
			return fmt.Errorf("flag needs host port and container port: --publish")
		} else if len(fields) == 2 {
			proto = "tcp"
			hPort = fields[0]
			cPort = fields[1]
		} else {
			proto = fields[0]
			if proto != "tcp" && proto != "udp" {
				return fmt.Errorf("flag needs protocol(tcp or udp): --publish")
			}
			hPort = fields[1]
			cPort = fields[2]
		}

		port.Protocol = proto
		port.HostPort, err = strconv.Atoi(hPort)
		if err != nil {
			return fmt.Errorf("flag needs host port and container port: --publish")
		}
		port.ContainerPort, err = strconv.Atoi(cPort)
		if err != nil {
			return fmt.Errorf("flag needs host port and container port: --publish")
		}
		ports = append(ports, port)
	}

	var containerList = []pod.UserContainer{}
	var container = pod.UserContainer{
		Name:          opts.Name,
		Image:         image,
		Command:       command,
		Workdir:       opts.Workdir,
		Entrypoint:    []string{},
		Ports:         ports,
		Envs:          env,
		Volumes:       []pod.UserVolumeReference{},
		Files:         []pod.UserFileReference{},
		RestartPolicy: opts.RestartPolicy,
	}
	containerList = append(containerList, container)

	var userPod = &pod.UserPod{
		Name:       opts.Name,
		Containers: containerList,
		Resource:   pod.UserResource{Vcpu: opts.Cpu, Memory: opts.Memory},
		Files:      []pod.UserFile{},
		Volumes:    []pod.UserVolume{},
		Tty:        opts.Tty,
	}

	jsonString, _ := json.Marshal(userPod)
	podId, err := cli.RunPod(string(jsonString), opts.Remove)
	if err != nil {
		return err
	}
	fmt.Printf("POD id is %s\n", podId)
	// Get the container ID of this POD
	containerId, err := cli.GetContainerByPod(podId)
	if err != nil {
		return err
	}
	var (
		tag      = cli.GetTag()
		hijacked = make(chan io.Closer)
		errCh    chan error
	)
	v := url.Values{}
	v.Set("type", "container")
	v.Set("value", containerId)
	v.Set("tag", tag)

	// Block the return until the chan gets closed
	defer func() {
		// fmt.Printf("End of CmdExec(), Waiting for hijack to finish.\n")
		if _, ok := <-hijacked; ok {
			fmt.Printf("Hijack did not finish (chan still open)\n")
		}
	}()

	errCh = promise.Go(func() error {
		return cli.hijack("POST", "/attach?"+v.Encode(), true, cli.in, cli.out, cli.out, hijacked, nil, "")
	})

	if err := cli.monitorTtySize(podId, tag); err != nil {
		fmt.Printf("Monitor tty size fail for %s!\n", podId)
	}

	// Acknowledge the hijack before starting
	select {
	case closer := <-hijacked:
		// Make sure that hijack gets closed when returning. (result
		// in closing hijack chan and freeing server's goroutines.
		if closer != nil {
			defer closer.Close()
		}
	case err := <-errCh:
		if err != nil {
			fmt.Printf("Error hijack: %s", err.Error())
			return err
		}
	}

	if err := <-errCh; err != nil {
		fmt.Printf("Error hijack: %s", err.Error())
		return err
	}
	// fmt.Printf("Success to exec the command %s for POD %s!\n", command, podId)
	return nil
}

func (cli *HyperClient) GetContainerByPod(podId string) (string, error) {
	v := url.Values{}
	v.Set("item", "container")
	body, _, err := readBody(cli.call("GET", "/list?"+v.Encode(), nil, nil))
	if err != nil {
		return "", err
	}
	out := engine.NewOutput()
	remoteInfo, err := out.AddEnv()
	if err != nil {
		return "", err
	}

	if _, err := out.Write(body); err != nil {
		fmt.Printf("Error reading remote info: %s", err)
		return "", err
	}
	out.Close()
	var containerResponse = []string{}
	containerResponse = remoteInfo.GetList("cData")
	for _, c := range containerResponse {
		fields := strings.Split(c, ":")
		containerId := fields[0]
		if podId == fields[2] {
			return containerId, nil
		}
	}

	return "", fmt.Errorf("Container not found")
}
<commit_msg>generator the container's name when the image's name include the slash<commit_after>package client

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/hyperhq/hyper/engine"
	"github.com/hyperhq/hyper/lib/docker/pkg/namesgenerator"
	"github.com/hyperhq/hyper/lib/promise"
	"github.com/hyperhq/hyper/utils"
	"github.com/hyperhq/runv/hypervisor/pod"

	gflag "github.com/jessevdk/go-flags"
)

// hyper run [OPTIONS] image [COMMAND] [ARGS...]
func (cli *HyperClient) HyperCmdRun(args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("%s ERROR: Can not accept the 'run' command without argument!\n", os.Args[0])
	}
	var opts struct {
		PodFile       string   `short:"p" long:"podfile" value-name:"\"\"" description:"Create and Run a pod based on the pod file"`
		K8s           string   `short:"k" long:"kubernetes" value-name:"\"\"" description:"Create and Run a pod based on the kubernetes pod file"`
		Yaml          bool     `short:"y" long:"yaml" default:"false" default-mask:"-" description:"Create a pod based on Yaml file"`
		Name          string   `long:"name" value-name:"\"\"" description:"Assign a name to the container"`
		Attach        bool     `long:"attach" default:"true" default-mask:"-" description:"Attach the stdin, stdout and stderr to the container"`
		Workdir       string   `long:"workdir" default:"/" value-name:"\"\"" default-mask:"-" description:"Working directory inside the container"`
		Tty           bool     `long:"tty" default:"true" default-mask:"-" description:"Allocate a pseudo-TTY"`
		Cpu           int      `long:"cpu" default:"1" value-name:"1" default-mask:"-" description:"CPU number for the VM"`
		Memory        int      `long:"memory" default:"128" value-name:"128" default-mask:"-" description:"Memory size (MB) for the VM"`
		Env           []string `long:"env" value-name:"[]" default-mask:"-" description:"Set environment variables"`
		EntryPoint    string   `long:"entrypoint" value-name:"\"\"" default-mask:"-" description:"Overwrite the default ENTRYPOINT of the image"`
		RestartPolicy string   `long:"restart" default:"never" value-name:"\"\"" default-mask:"-" description:"Restart policy to apply when a container exits (never, onFailure, always)"`
		Remove        bool     `long:"rm" default:"false" value-name:"" default-mask:"-" description:"Automatically remove the pod when it exits"`
		Portmap       []string `long:"publish" value-name:"[]" default-mask:"-" description:"Publish a container's port to the host, format: --publish [tcp/udp:]hostPort:containerPort"`
	}

	var parser = gflag.NewParser(&opts, gflag.Default|gflag.IgnoreUnknown)
	parser.Usage = "run [OPTIONS] IMAGE [COMMAND] [ARG...]\n\nCreate a pod, and launch a new VM to run the pod"
	args, err := parser.Parse()
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}
	if opts.PodFile != "" {
		if _, err := os.Stat(opts.PodFile); err != nil {
			return err
		}

		jsonbody, err := ioutil.ReadFile(opts.PodFile)
		if err != nil {
			return err
		}

		if opts.Yaml == true {
			jsonbody, err = cli.ConvertYamlToJson(jsonbody)
			if err != nil {
				return err
			}
		}
		t1 := time.Now()
		podId, err := cli.RunPod(string(jsonbody), opts.Remove)
		if err != nil {
			return err
		}
		fmt.Printf("POD id is %s\n", podId)
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
		return nil
	}
	if opts.K8s != "" {
		var (
			kpod    pod.KPod
			userpod *pod.UserPod
		)
		if _, err := os.Stat(opts.K8s); err != nil {
			return err
		}

		jsonbody, err := ioutil.ReadFile(opts.K8s)
		if err != nil {
			return err
		}
		if opts.Yaml == true {
			jsonbody, err = cli.ConvertYamlToJson(jsonbody)
			if err != nil {
				return err
			}
		}
		if err := json.Unmarshal(jsonbody, &kpod); err != nil {
			return err
		}
		userpod, err = kpod.Convert()
		if err != nil {
			return err
		}
		jsonbody, err = json.Marshal(*userpod)
		if err != nil {
			return err
		}
		t1 := time.Now()
		podId, err := cli.RunPod(string(jsonbody), opts.Remove)
		if err != nil {
			return err
		}
		fmt.Printf("POD id is %s\n", podId)
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
		return nil
	}

	if len(args) == 0 {
		return fmt.Errorf("%s: \"run\" requires a minimum of 1 argument, please provide the image.", os.Args[0])
	}
	var (
		image   = args[1]
		command = []string{}
		env     = []pod.UserEnvironmentVar{}
		ports   = []pod.UserContainerPort{}
		proto   string
		hPort   string
		cPort   string
	)
	if len(args) > 1 {
		command = args[2:]
	}
	if opts.Name == "" {
		opts.Name = image
		fields := strings.Split(image, "/")
		if len(fields) > 1 {
			opts.Name = fields[len(fields)-1]
		}
		fields = strings.Split(opts.Name, ":")
		if len(fields) < 2 {
			opts.Name = opts.Name + "-" + utils.RandStr(10, "number")
		} else {
			opts.Name = fields[0] + "-" + fields[1] + "-" + utils.RandStr(10, "number")
		}

		validContainerNameChars := `[a-zA-Z0-9][a-zA-Z0-9_.-]`
		validContainerNamePattern := regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
		if !validContainerNamePattern.MatchString(opts.Name) {
			opts.Name = namesgenerator.GetRandomName(0)
		}
	}
	if opts.Memory == 0 {
		opts.Memory = 128
	}
	if opts.Cpu == 0 {
		opts.Cpu = 1
	}
	for _, v := range opts.Env {
		if v == "" || !strings.Contains(v, "=") {
			continue
		}
		userEnv := pod.UserEnvironmentVar{
			Env:   v[:strings.Index(v, "=")],
			Value: v[strings.Index(v, "=")+1:],
		}
		env = append(env, userEnv)
	}

	for _, v := range opts.Portmap {
		port := pod.UserContainerPort{}
		fields := strings.Split(v, ":")
		if len(fields) < 2 {
			return fmt.Errorf("flag needs host port and container port: --publish")
		} else if len(fields) == 2 {
			proto = "tcp"
			hPort = fields[0]
			cPort = fields[1]
		} else {
			proto = fields[0]
			if proto != "tcp" && proto != "udp" {
				return fmt.Errorf("flag needs protocol(tcp or udp): --publish")
			}
			hPort = fields[1]
			cPort = fields[2]
		}

		port.Protocol = proto
		port.HostPort, err = strconv.Atoi(hPort)
		if err != nil {
			return fmt.Errorf("flag needs host port and container port: --publish")
		}
		port.ContainerPort, err = strconv.Atoi(cPort)
		if err != nil {
			return fmt.Errorf("flag needs host port and container port: --publish")
		}
		ports = append(ports, port)
	}

	var containerList = []pod.UserContainer{}
	var container = pod.UserContainer{
		Name:          opts.Name,
		Image:         image,
		Command:       command,
		Workdir:       opts.Workdir,
		Entrypoint:    []string{},
		Ports:         ports,
		Envs:          env,
		Volumes:       []pod.UserVolumeReference{},
		Files:         []pod.UserFileReference{},
		RestartPolicy: opts.RestartPolicy,
	}
	containerList = append(containerList, container)

	var userPod = &pod.UserPod{
		Name:       opts.Name,
		Containers: containerList,
		Resource:   pod.UserResource{Vcpu: opts.Cpu, Memory: opts.Memory},
		Files:      []pod.UserFile{},
		Volumes:    []pod.UserVolume{},
		Tty:        opts.Tty,
	}

	jsonString, _ := json.Marshal(userPod)
	podId, err := cli.RunPod(string(jsonString), opts.Remove)
	if err != nil {
		return err
	}
	fmt.Printf("POD id is %s\n", podId)
	// Get the container ID of this POD
	containerId, err := cli.GetContainerByPod(podId)
	if err != nil {
		return err
	}
	var (
		tag      = cli.GetTag()
		hijacked = make(chan io.Closer)
		errCh    chan error
	)
	v := url.Values{}
	v.Set("type", "container")
	v.Set("value", containerId)
	v.Set("tag", tag)

	// Block the return until the chan gets closed
	defer func() {
		// fmt.Printf("End of CmdExec(), Waiting for hijack to finish.\n")
		if _, ok := <-hijacked; ok {
			fmt.Printf("Hijack did not finish (chan still open)\n")
		}
	}()

	errCh = promise.Go(func() error {
		return cli.hijack("POST", "/attach?"+v.Encode(), true, cli.in, cli.out, cli.out, hijacked, nil, "")
	})

	if err := cli.monitorTtySize(podId, tag); err != nil {
		fmt.Printf("Monitor tty size fail for %s!\n", podId)
	}

	// Acknowledge the hijack before starting
	select {
	case closer := <-hijacked:
		// Make sure that hijack gets closed when returning. (result
		// in closing hijack chan and freeing server's goroutines.
		if closer != nil {
			defer closer.Close()
		}
	case err := <-errCh:
		if err != nil {
			fmt.Printf("Error hijack: %s", err.Error())
			return err
		}
	}

	if err := <-errCh; err != nil {
		fmt.Printf("Error hijack: %s", err.Error())
		return err
	}
	// fmt.Printf("Success to exec the command %s for POD %s!\n", command, podId)
	return nil
}

func (cli *HyperClient) GetContainerByPod(podId string) (string, error) {
	v := url.Values{}
	v.Set("item", "container")
	body, _, err := readBody(cli.call("GET", "/list?"+v.Encode(), nil, nil))
	if err != nil {
		return "", err
	}
	out := engine.NewOutput()
	remoteInfo, err := out.AddEnv()
	if err != nil {
		return "", err
	}

	if _, err := out.Write(body); err != nil {
		fmt.Printf("Error reading remote info: %s", err)
		return "", err
	}
	out.Close()
	var containerResponse = []string{}
	containerResponse = remoteInfo.GetList("cData")
	for _, c := range containerResponse {
		fields := strings.Split(c, ":")
		containerId := fields[0]
		if podId == fields[2] {
			return containerId, nil
		}
	}

	return "", fmt.Errorf("Container not found")
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"github.com/coreos/fleet/schema"
	"github.com/juju/errgo"
	execPkg "os/exec"
)

const (
	FLEETCTL            = "fleetctl"
	ENDPOINT_OPTION     = "--endpoint"
	ENDPOINT_VALUE      = "http://172.17.42.1:4101"
	ETCD_PREFIX_OPTION  = "--etcd-key-prefix"
	DEFAULT_ETCD_PREFIX = "/_coreos.com/fleet/"
)

type ClientCLI struct {
	etcdPeer   string
	driver     string
	etcdPrefix string
}

func NewClientCLI() FleetClient {
	return &ClientCLI{
		etcdPeer: ENDPOINT_VALUE,
	}
}

func NewClientCLIWithPeer(etcdPeer string) FleetClient {
	return &ClientCLI{
		etcdPeer:   etcdPeer,
		driver:     "--driver=etcd",
		etcdPrefix: DEFAULT_ETCD_PREFIX,
	}
}

func NewClientCLIWithPeerAndPrefix(etcdPeer, etcdPrefix string) FleetClient {
	client := NewClientCLIWithPeer(etcdPeer)
	if etcdPrefix == "" {
		etcdPrefix = DEFAULT_ETCD_PREFIX
	}
	return &ClientCLI{
		etcdPeer:   etcdPeer,
		driver:     "--driver=etcd",
		etcdPrefix: etcdPrefix,
	}

	return client
}

func args(extras []string, required ...string) []string {
	return append(required, extras...)
}

func (this *ClientCLI) Submit(filePath ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(filePath, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "submit")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(filePath, ENDPOINT_OPTION, this.etcdPeer, "submit")...)
	}
	output, err := exec(cmd)
	if err != nil {
		fmt.Printf("Error in submit: %s %s\n", err, output)
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Unit(name string) (*schema.Unit, error) {
	return nil, fmt.Errorf("Method not implemented: ClientCLI.Unit")
}

func (this *ClientCLI) Start(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "start", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "start", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Stop(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "stop", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "stop", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Load(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "load", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "load", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Destroy(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "destroy")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "destroy")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}
<commit_msg>changed to fleet socket<commit_after>package client

import (
	"fmt"
	"github.com/coreos/fleet/schema"
	"github.com/juju/errgo"
	execPkg "os/exec"
)

const (
	FLEETCTL            = "fleetctl"
	ENDPOINT_OPTION     = "--endpoint"
	ENDPOINT_VALUE      = "file:///var/run/fleet.sock"
	ETCD_PREFIX_OPTION  = "--etcd-key-prefix"
	DEFAULT_ETCD_PREFIX = "/_coreos.com/fleet/"
)

type ClientCLI struct {
	etcdPeer   string
	driver     string
	etcdPrefix string
}

func NewClientCLI() FleetClient {
	return &ClientCLI{
		etcdPeer: ENDPOINT_VALUE,
	}
}

func NewClientCLIWithPeer(etcdPeer string) FleetClient {
	return &ClientCLI{
		etcdPeer:   etcdPeer,
		driver:     "--driver=etcd",
		etcdPrefix: DEFAULT_ETCD_PREFIX,
	}
}

func NewClientCLIWithPeerAndPrefix(etcdPeer, etcdPrefix string) FleetClient {
	client := NewClientCLIWithPeer(etcdPeer)
	if etcdPrefix == "" {
		etcdPrefix = DEFAULT_ETCD_PREFIX
	}
	return &ClientCLI{
		etcdPeer:   etcdPeer,
		driver:     "--driver=etcd",
		etcdPrefix: etcdPrefix,
	}

	return client
}

func args(extras []string, required ...string) []string {
	return append(required, extras...)
}

func (this *ClientCLI) Submit(filePath ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(filePath, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "submit")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(filePath, ENDPOINT_OPTION, this.etcdPeer, "submit")...)
	}
	output, err := exec(cmd)
	if err != nil {
		fmt.Printf("Error in submit: %s %s\n", err, output)
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Unit(name string) (*schema.Unit, error) {
	return nil, fmt.Errorf("Method not implemented: ClientCLI.Unit")
}

func (this *ClientCLI) Start(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "start", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "start", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Stop(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "stop", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "stop", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Load(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "load", "--no-block=true")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "load", "--no-block=true")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}

func (this *ClientCLI) Destroy(name ...string) error {
	var cmd *execPkg.Cmd

	if this.driver != "" {
		cmd = execPkg.Command(FLEETCTL, args(name, this.driver, ENDPOINT_OPTION, this.etcdPeer, ETCD_PREFIX_OPTION, this.etcdPrefix, "destroy")...)
	} else {
		cmd = execPkg.Command(FLEETCTL, args(name, ENDPOINT_OPTION, this.etcdPeer, "destroy")...)
	}
	_, err := exec(cmd)

	if err != nil {
		return errgo.Mask(err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
package main

import (
	"bytes"
	"fmt"
	"net/http"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

type LogUploader interface {
	Upload(api ApiRequester, server string, logs LogData) error
}

type LogData struct {
	deploymentID string
	Messages     []byte `json:"messages"`
}

type LogUploadClient struct {
}

func NewLogUploadClient() LogUploader {
	return &LogUploadClient{}
}

// Report status information to the backend
func (u *LogUploadClient) Upload(api ApiRequester, url string, logs LogData) error {
	req, err := makeLogUploadRequest(url, &logs)
	if err != nil {
		return errors.Wrapf(err, "failed to prepare log upload request")
	}

	r, err := api.Do(req)
	if err != nil {
		log.Error("failed to upload logs: ", err)
		return errors.Wrapf(err, "uploading logs failed")
	}

	// HTTP 204 No Content
	if r.StatusCode != http.StatusNoContent {
		log.Errorf("got unexpected HTTP status when uploading log: %v", r.StatusCode)
		return errors.Errorf("uploading logs failed, bad status %v", r.StatusCode)
	}
	log.Debugf("logs uploaded, response %v", r)

	return nil
}

func makeLogUploadRequest(server string, logs *LogData) (*http.Request, error) {
	path := fmt.Sprintf("/deployments/device/deployments/%s/log",
		logs.deploymentID)
	url := buildApiURL(server, path)

	hreq, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(logs.Messages))
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create log sending HTTP request")
	}

	hreq.Header.Add("Content-Type", "application/json")
	return hreq, nil
}
<commit_msg>client_log: close response body<commit_after>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
package main

import (
	"bytes"
	"fmt"
	"net/http"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

type LogUploader interface {
	Upload(api ApiRequester, server string, logs LogData) error
}

type LogData struct {
	deploymentID string
	Messages     []byte `json:"messages"`
}

type LogUploadClient struct {
}

func NewLogUploadClient() LogUploader {
	return &LogUploadClient{}
}

// Report status information to the backend
func (u *LogUploadClient) Upload(api ApiRequester, url string, logs LogData) error {
	req, err := makeLogUploadRequest(url, &logs)
	if err != nil {
		return errors.Wrapf(err, "failed to prepare log upload request")
	}

	r, err := api.Do(req)
	if err != nil {
		log.Error("failed to upload logs: ", err)
		return errors.Wrapf(err, "uploading logs failed")
	}

	defer r.Body.Close()

	// HTTP 204 No Content
	if r.StatusCode != http.StatusNoContent {
		log.Errorf("got unexpected HTTP status when uploading log: %v", r.StatusCode)
		return errors.Errorf("uploading logs failed, bad status %v", r.StatusCode)
	}
	log.Debugf("logs uploaded, response %v", r)

	return nil
}

func makeLogUploadRequest(server string, logs *LogData) (*http.Request, error) {
	path := fmt.Sprintf("/deployments/device/deployments/%s/log",
		logs.deploymentID)
	url := buildApiURL(server, path)

	hreq, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(logs.Messages))
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create log sending HTTP request")
	}

	hreq.Header.Add("Content-Type", "application/json")
	return hreq, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Tamás Gulácsi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package oracle

import (
	"fmt"
	"testing"
	"time"
)

func TestTable(t *testing.T) {
	conn := getConnection(t)
	if !conn.IsConnected() {
		t.FailNow()
	}
	defer conn.Close()
	cur := conn.NewCursor()
	defer cur.Close()
	if err := cur.Execute(`CREATE TABLE tst_goracle (
			F_int NUMBER(3), F_bigint NUMBER(20),
			F_real NUMBER(6,3), F_bigreal NUMBER(20,10),
			F_text VARCHAR2(1000), F_date DATE
		)`, nil, nil); err != nil {
		t.Skipf("Skipping table test, as cannot create tst_goracle: %v", err)
		return
	}
	defer cur.Execute("DROP TABLE tst_goracle", nil, nil)
	if !insert(t, cur, 1, "1234567890123456", 123.456,
		"123456789.123456789", "int64", time.Now()) {
		return
	}

	if !insert(t, cur, 2, "22345678901234567890", 223.456,
		"223456789.123456789", "big.Int", time.Now()) {
		return
	}
}

func insert(t *testing.T, cur *Cursor,
	small int, bigint string,
	notint float64, bigreal string,
	text string, date time.Time,
) bool {
	qry := fmt.Sprintf(`INSERT INTO tst_goracle
			(F_int, F_bigint, F_real, F_bigreal, F_text, F_date)
			VALUES (%d, %s, %3.3f, %s, '%s', TO_DATE('%s', 'YYYY-MM-DD HH24:MI:SS'))
			`, small, bigint, notint, bigreal, text, date.Format("2006-01-02 15:04:05"))
	if err := cur.Execute(qry, nil, nil); err != nil {
		t.Errorf("cannot insert into tst_goracle (%q): %v", qry, err)
		return false
	}
	if err := cur.Execute("SELECT * FROM tst_goracle WHERE F_int = :1", []interface{}{small}, nil); err != nil {
		t.Errorf("error selecting tst_goracle: %v", err)
		return false
	}
	row, err := cur.FetchOne()
	if err != nil {
		t.Errorf("error fetching row: %v", err)
		return false
	}
	t.Logf("row: %#v", row)

	return true
}
<commit_msg>table_test: issue #22: cannot reproduce ORA-22060, just ORA-22053<commit_after>/*
Copyright 2013 Tamás Gulácsi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package oracle

import (
	"fmt"
	"testing"
	"time"
)

func TestTable(t *testing.T) {
	conn := getConnection(t)
	if !conn.IsConnected() {
		t.FailNow()
	}
	defer conn.Close()
	cur := conn.NewCursor()
	defer cur.Close()
	if err := cur.Execute(`CREATE TABLE tst_goracle (
			F_int NUMBER(10,0), F_bigint NUMBER(20),
			F_real NUMBER(6,3), F_bigreal NUMBER(20,10),
			F_text VARCHAR2(1000), F_date DATE
		)`, nil, nil); err != nil {
		t.Skipf("Skipping table test, as cannot create tst_goracle: %v", err)
		return
	}
	defer cur.Execute("DROP TABLE tst_goracle", nil, nil)

	insert(t, cur, 1234567890, "1234567890123456", 123.456,
		"123456789.123456789", "int64", time.Now())

	insert(t, cur, 2, "22345678901234567890", 223.456,
		"223456789.123456789", "big.Int", time.Now())
}

func insert(t *testing.T, cur *Cursor,
	small int, bigint string,
	notint float64, bigreal string,
	text string, date time.Time,
) bool {
	qry := fmt.Sprintf(`INSERT INTO tst_goracle
			(F_int, F_bigint, F_real, F_bigreal, F_text, F_date)
			VALUES (%d, %s, %3.3f, %s, '%s', TO_DATE('%s', 'YYYY-MM-DD HH24:MI:SS'))
			`, small, bigint, notint, bigreal, text, date.Format("2006-01-02 15:04:05"))
	if err := cur.Execute(qry, nil, nil); err != nil {
		t.Errorf("cannot insert into tst_goracle (%q): %v", qry, err)
		return false
	}
	if err := cur.Execute("SELECT * FROM tst_goracle WHERE F_int = :1", []interface{}{small}, nil); err != nil {
		t.Errorf("error selecting tst_goracle: %v", err)
		return false
	}
	row, err := cur.FetchOne()
	if err != nil {
		t.Errorf("error fetching row: %v", err)
		return false
	}
	t.Logf("row: %#v", row)

	return true
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Evan Spendlove (@evanSpendlove)
//
// Client.go creates the client for connecting to, and making requests to, the
// gRPC server of Cloudprober.
//
// TODOs:
// TODO(#38) Add support for secure connection to RPC server with credentials, if supported by Cloudprober.
// TODO: Include details of these errors (addProbeFromConfig method) in the error message.

package cmd

import (
	"context"
	"fmt"
	"sync"

	"github.com/golang/glog"
	proberpb "github.com/google/cloudprober/prober/proto"
	cpprobes "github.com/google/cloudprober/probes"
	configpb "github.com/google/cloudprober/probes/proto"
	"google.golang.org/grpc"
)

type CloudproberClient struct {
	conn      *grpc.ClientConn           // Client connection for opening and closing the connection
	client    proberpb.CloudproberClient // Cloudprober gRPC client retained between RPC calls
	clientMux sync.Mutex                 // Mutex lock for making CloudproberClient safe for concurrent use
}

// NewClient creates, initialises and returns a new CloudproberClient.
// This is the correct way to create a new instance of CloudproberClient.
// Parameters:
// - rpcServer: Pass the rpcServer address and port as a string formatted as: "hostname:port", e.g. "localhost:1234"
// Returns:
// - error:
//	  - nil: No error occurred and the client was successfully initialised.
//	  - gRPC Error: See https://godoc.org/google.golang.org/grpc/codes for error codes.
//		-> See https://github.com/grpc/grpc-go/blob/d25c71b54334380ff1febd25d88064b36de44b3c/clientconn.go#L123
func NewClient(rpcServer string) (*CloudproberClient, error) {
	conn, err := grpc.Dial(rpcServer, grpc.WithInsecure())
	if err != nil {
		return nil, fmt.Errorf("GRPC_DIAL_ERROR: %v", err)
	}
	return &CloudproberClient{conn: conn, client: proberpb.NewCloudproberClient(conn)}, nil
}

// CloseConn is used for closing the client connection with the gRPC server.
// Returns:
// - error:
//	   - nil: No error occurred and the connection was successfully closed.
//	   - Code 1, ErrClientConnClosing: This operation is illegal because the client connection is already closing.
func (client *CloudproberClient) CloseConn() {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	err := client.conn.Close()
	if err != nil {
		glog.Errorf("Cloudprober gRPC client could not close connection, err: %v", err)
	}
}

// addProbeFromConfig adds a probe to Cloudprober via the gRPC client.
// Parameters:
// - probePb: - This probe config must be unmarshalled before being passed as an argument.
//			 - This probe type must be registered as an extension.
// Returns:
// TODO: Include details of these errors in the error message.
// - error:
//         - Code 3, InvalidArgument: probe config cannot be nil
//         - error parsing regexp [...]: the machine name for this probe to run on does not compile as a regexp.
//         - Code 6, AlreadyExists: probe [name] is already defined - the probe has already been added
//         - Code 2, Unknown:
//		- only one probe extension is allowed per probe, got %d extensions
//			-> More than one probe extension type has been registered using cpprobes.RegisterProbeType()
//		- no probe extension in probe config
//			-> The probe proto does not have an extension registered.
//		- no probes registered for the extension: [extension code]
//			-> The proto has a probe extension, but there is no probe extension registered matching that extension code.
//		- proto.GetExtension() error: extension missing, invalid, incomplete or proto cannot be extended.
//			-> The proto.SetExtension() method must be called and supplied with valid data.
//		- unregistered user defined probe: [probe name]
//			-> The probe type has not been registered as a user defined probe.
//		- unknown probe type: [probe type]
//			-> The probe type does not match any expected types (including user-defined and extension).
//		- probe.Init() error: an error occurred when the probe, created from the config passsed, was initialised.
//			-> There was a problem in the Init() function of the probe type passed.
//		- options.BuildProbeOptions() error: an error occurred when building the options for this probe from the config supplied.
//			-> The options could not be built from the config supplied.
func (client *CloudproberClient) addProbeFromConfig(ctx context.Context, probePb *configpb.ProbeDef) error {
	// No mutex locking handled here as this is a private method called by
	// a public method which handles locking.
	_, err := client.client.AddProbe(ctx, &proberpb.AddProbeRequest{ProbeConfig: probePb})
	return err
}

// RegisterAndAddProbe registers a probe type and adds the probe to Cloudprober to be run.
// Parameters:
// - probePb: - This probe config must be unmarshalled before being passed as an argument.
// Returns:
// - error:
//	      - See addProbeFromConfig errors.
func (client *CloudproberClient) RegisterAndAddProbe(extensionNumber int, ctx context.Context, probePb *configpb.ProbeDef, hermesProbeToAdd cpprobes.Probe) error {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	// First, register the probe as an extension with Cloudprober.
	cpprobes.RegisterProbeType(extensionNumber, func() cpprobes.Probe { return hermesProbeToAdd })

	// Add the probe to Cloudprober
	// The probe will be scheduled and run by Cloudprober
	// Adding a probe will consume the probe type registration.
	// If you want to add multiple probes, you must register and add each one individually.
	// Only one extension type can be registered at any given time.
	// If more are registered, Cloudprober will throw an error.
	return client.addProbeFromConfig(ctx, probePb)
}

// RemoveProbe removes a probe from Cloudprober, given the probe name (located in the probe config).
// An error will be returned if there is no active probe with this probe name.
// Parameters:
// - probeName: This must be the name of an active probe in Cloudprober.
// Returns:
// - error:
//	   - Code: 3, InvalidArgument: probeName is an empty string
//	   - Code: 5,  NotFound: cannot find a probe matching this probe name
func (client *CloudproberClient) RemoveProbe(probeName string) error {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	_, err := client.client.RemoveProbe(context.Background(), &proberpb.RemoveProbeRequest{ProbeName: &probeName})
	return err
}

// ListProbes() returns a list of active probes from Cloudprober.
// Returns:
// - ListProbesResponse: This is the list of active probes in Cloudprober.
//			 If this is empty, there are no active probes.
// - Error:
//	   - See Cloudprober ListProbes() RPC for details on an error.
func (client *CloudproberClient) ListProbes() (*proberpb.ListProbesResponse, error) {
	return client.client.ListProbes(context.Background(), &proberpb.ListProbesRequest{})
}
<commit_msg>Removed unnecessary comments.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Evan Spendlove (@evanSpendlove)
//
// Client.go creates the client for connecting to, and making requests to, the
// gRPC server of Cloudprober.
//
// TODOs:
// TODO(#38) Add support for secure connection to RPC server with credentials, if supported by Cloudprober.
// TODO: Include details of these errors (addProbeFromConfig method) in the error message.

package cmd

import (
	"context"
	"fmt"
	"sync"

	"github.com/golang/glog"
	proberpb "github.com/google/cloudprober/prober/proto"
	cpprobes "github.com/google/cloudprober/probes"
	configpb "github.com/google/cloudprober/probes/proto"
	"google.golang.org/grpc"
)

type CloudproberClient struct {
	conn      *grpc.ClientConn           // Client connection for opening and closing the connection
	client    proberpb.CloudproberClient // Cloudprober gRPC client retained between RPC calls
	clientMux sync.Mutex                 // Mutex lock for making CloudproberClient safe for concurrent use
}

// NewClient creates, initialises and returns a new CloudproberClient.
// This is the correct way to create a new instance of CloudproberClient.
// Parameters:
// - rpcServer: Pass the rpcServer address and port as a string formatted as: "hostname:port", e.g. "localhost:1234"
// Returns:
// - error:
//	  - nil: No error occurred and the client was successfully initialised.
//	  - gRPC Error: See https://godoc.org/google.golang.org/grpc/codes for error codes.
//		-> See https://github.com/grpc/grpc-go/blob/d25c71b54334380ff1febd25d88064b36de44b3c/clientconn.go#L123
func NewClient(rpcServer string) (*CloudproberClient, error) {
	conn, err := grpc.Dial(rpcServer, grpc.WithInsecure())
	if err != nil {
		return nil, fmt.Errorf("GRPC_DIAL_ERROR: %v", err)
	}
	return &CloudproberClient{conn: conn, client: proberpb.NewCloudproberClient(conn)}, nil
}

// CloseConn is used for closing the client connection with the gRPC server.
// Returns:
// - error:
//	   - nil: No error occurred and the connection was successfully closed.
//	   - Code 1, ErrClientConnClosing: This operation is illegal because the client connection is already closing.
func (client *CloudproberClient) CloseConn() {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	err := client.conn.Close()
	if err != nil {
		glog.Errorf("Cloudprober gRPC client could not close connection, err: %v", err)
	}
}

// addProbeFromConfig adds a probe to Cloudprober via the gRPC client.
// Parameters:
// - probePb: - This probe config must be unmarshalled before being passed as an argument.
//			 - This probe type must be registered as an extension.
// Returns:
// TODO: Include details of these errors in the error message.
// - error:
//         - Code 3, InvalidArgument: probe config cannot be nil
//         - error parsing regexp [...]: the machine name for this probe to run on does not compile as a regexp.
//         - Code 6, AlreadyExists: probe [name] is already defined - the probe has already been added
//         - Code 2, Unknown:
//		- only one probe extension is allowed per probe, got %d extensions
//			-> More than one probe extension type has been registered using cpprobes.RegisterProbeType()
//		- no probe extension in probe config
//			-> The probe proto does not have an extension registered.
//		- no probes registered for the extension: [extension code]
//			-> The proto has a probe extension, but there is no probe extension registered matching that extension code.
//		- proto.GetExtension() error: extension missing, invalid, incomplete or proto cannot be extended.
//			-> The proto.SetExtension() method must be called and supplied with valid data.
//		- unregistered user defined probe: [probe name]
//			-> The probe type has not been registered as a user defined probe.
//		- unknown probe type: [probe type]
//			-> The probe type does not match any expected types (including user-defined and extension).
//		- probe.Init() error: an error occurred when the probe, created from the config passsed, was initialised.
//			-> There was a problem in the Init() function of the probe type passed.
//		- options.BuildProbeOptions() error: an error occurred when building the options for this probe from the config supplied.
//			-> The options could not be built from the config supplied.
func (client *CloudproberClient) addProbeFromConfig(ctx context.Context, probePb *configpb.ProbeDef) error {
	// No mutex locking handled here as this is a private method called by
	// a public method which handles locking.
	_, err := client.client.AddProbe(ctx, &proberpb.AddProbeRequest{ProbeConfig: probePb})
	return err
}

// RegisterAndAddProbe registers a probe type and adds the probe to Cloudprober to be run.
// Parameters:
// - probePb: - This probe config must be unmarshalled before being passed as an argument.
// Returns:
// - error:
//	      - See addProbeFromConfig errors.
func (client *CloudproberClient) RegisterAndAddProbe(extensionNumber int, ctx context.Context, probePb *configpb.ProbeDef, hermesProbeToAdd cpprobes.Probe) error {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	cpprobes.RegisterProbeType(extensionNumber, func() cpprobes.Probe { return hermesProbeToAdd })

	// Only one extension type per proto config can be registered at any given time.
	// If more are registered, Cloudprober will throw an error.
	return client.addProbeFromConfig(ctx, probePb)
}

// RemoveProbe removes a probe from Cloudprober, given the probe name (located in the probe config).
// An error will be returned if there is no active probe with this probe name.
// Parameters:
// - probeName: This must be the name of an active probe in Cloudprober.
// Returns:
// - error:
//	   - Code: 3, InvalidArgument: probeName is an empty string
//	   - Code: 5,  NotFound: cannot find a probe matching this probe name
func (client *CloudproberClient) RemoveProbe(probeName string) error {
	client.clientMux.Lock()
	defer client.clientMux.Unlock()

	_, err := client.client.RemoveProbe(context.Background(), &proberpb.RemoveProbeRequest{ProbeName: &probeName})
	return err
}

// ListProbes() returns a list of active probes from Cloudprober.
// Returns:
// - ListProbesResponse: This is the list of active probes in Cloudprober.
//			 If this is empty, there are no active probes.
// - Error:
//	   - See Cloudprober ListProbes() RPC for details on an error.
func (client *CloudproberClient) ListProbes() (*proberpb.ListProbesResponse, error) {
	return client.client.ListProbes(context.Background(), &proberpb.ListProbesRequest{})
}
<|endoftext|>


<commit_before>// Copyright © 2016 mgIT GmbH <office@mgit.at>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"log"
	"math"
	"strings"

	"github.com/mgit-at/arti/store"

	"github.com/spf13/viper"
)

const (
	_          = iota
	KB float64 = 1 << (10 * iota)
	MB
	GB
	TB
	PB
)

var (
	artifactName    string
	artifactVersion string
)

func selectStore(nameAndPath string) store.Store {
	stores := viper.Sub("stores")
	if stores == nil {
		log.Fatal("no stores specified!")
	}

	np := strings.SplitN(nameAndPath, "/", 2)
	if len(np) < 2 {
		np = append(np, "")
	}
	cfg := stores.Sub(np[0])
	if cfg == nil {
		log.Fatalln("no such store:", np[0])
	}

	tmp := viper.Get("stores.minio.location-asdf")
	log.Println("%s", tmp)

	cfg.SetEnvPrefix("arti_stores__" + np[0] + "_")
	cfg.SetEnvKeyReplacer(strings.NewReplacer(".", "__", "-", "_"))
	cfg.AutomaticEnv()
	s, err := store.NewStore(cfg, np[1])
	if err != nil {
		log.Fatalln("unable to initialize store:", err)
	}
	//	log.Printf("using store(type: %T): %+v", s, s)
	return s
}

func logn(n, b float64) float64 {
	return math.Log(n) / math.Log(b)
}

func humanizeBytes(size int64) (float64, string) {
	e := math.Floor(logn(float64(size), 1024))
	switch e {
	case 0:
		return float64(size), ""
	case 1:
		return float64(size) / KB, "k"
	case 2:
		return float64(size) / MB, "M"
	case 3:
		return float64(size) / GB, "G"
	case 4:
		return float64(size) / TB, "T"
	default:
		return float64(size) / PB, "P"
	}
}
<commit_msg>removed superfluous debug output<commit_after>// Copyright © 2016 mgIT GmbH <office@mgit.at>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"log"
	"math"
	"strings"

	"github.com/mgit-at/arti/store"

	"github.com/spf13/viper"
)

const (
	_          = iota
	KB float64 = 1 << (10 * iota)
	MB
	GB
	TB
	PB
)

var (
	artifactName    string
	artifactVersion string
)

func selectStore(nameAndPath string) store.Store {
	stores := viper.Sub("stores")
	if stores == nil {
		log.Fatal("no stores specified!")
	}

	np := strings.SplitN(nameAndPath, "/", 2)
	if len(np) < 2 {
		np = append(np, "")
	}
	cfg := stores.Sub(np[0])
	if cfg == nil {
		log.Fatalln("no such store:", np[0])
	}

	cfg.SetEnvPrefix("arti_stores__" + np[0] + "_")
	cfg.SetEnvKeyReplacer(strings.NewReplacer(".", "__", "-", "_"))
	cfg.AutomaticEnv()
	s, err := store.NewStore(cfg, np[1])
	if err != nil {
		log.Fatalln("unable to initialize store:", err)
	}
	//	log.Printf("using store(type: %T): %+v", s, s)
	return s
}

func logn(n, b float64) float64 {
	return math.Log(n) / math.Log(b)
}

func humanizeBytes(size int64) (float64, string) {
	e := math.Floor(logn(float64(size), 1024))
	switch e {
	case 0:
		return float64(size), ""
	case 1:
		return float64(size) / KB, "k"
	case 2:
		return float64(size) / MB, "M"
	case 3:
		return float64(size) / GB, "G"
	case 4:
		return float64(size) / TB, "T"
	default:
		return float64(size) / PB, "P"
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/spf13/cobra"
)

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Get and set configuration in Consul for Docker containers.",
	PreRun: func(cmd *cobra.Command, args []string) {
		checkConfigFlags()
		LoadConfig()
	},
	Long: `Get and set configuration in Consul for Docker containers.`,
	Run:  startConfig,
}

func startConfig(cmd *cobra.Command, args []string) {

}

func checkConfigFlags() {
	Log("Checking flags", "info")
}

func init() {
	RootCmd.AddCommand(configCmd)
}
<commit_msg>Just testing the Consul functions.<commit_after>// +build linux darwin freebsd

package cmd

import (
	"github.com/spf13/cobra"
)

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Get and set configuration in Consul for Docker containers.",
	PreRun: func(cmd *cobra.Command, args []string) {
		checkConfigFlags()
		LoadConfig()
	},
	Long: `Get and set configuration in Consul for Docker containers.`,
	Run:  startConfig,
}

func startConfig(cmd *cobra.Command, args []string) {
	consul, err := ConsulSetup()
	if err != nil {
		Log("Fatal Consul setup problem.", "info")
	}
	if ConsulSet(consul, "testing", "the-value") {
		Log("Set the value at testing", "info")
	}
	value, err := ConsulGet(consul, "testing")
	if value == "" {
		Log("Nothing at that key.", "info")
	}
	if ConsulDel(consul, "testing") {
		Log("Removed the value at testing", "info")
	}
}

func checkConfigFlags() {
	Log("Checking flags", "info")
}

func init() {
	RootCmd.AddCommand(configCmd)
}
<|endoftext|>


<commit_before>package cmd

import "fmt"

type config struct {
	Endpoint   string
	Apikey     string
	Editor     string
	ProjectID  int
	Projects   map[int]string
	Trackers   []string
	Priorities []string
	Template   string
}

func (c *config) getProjetID(name string) (int, error) {
	for k, v := range c.Projects {
		if v == name {
			return k, nil
		}
	}
	// project_id は 1 から始まる（と思われる）。
	return 0, fmt.Errorf("%s is invalid priority", name)
}

var cfg config

var cfgFilePath string
<commit_msg>エラーメッセージの内容が間違っていた<commit_after>package cmd

import "fmt"

type config struct {
	Endpoint   string
	Apikey     string
	Editor     string
	ProjectID  int
	Projects   map[int]string
	Trackers   []string
	Priorities []string
	Template   string
}

func (c *config) getProjetID(name string) (int, error) {
	for k, v := range c.Projects {
		if v == name {
			return k, nil
		}
	}
	// project_id は 1 から始まる（と思われる）。
	return 0, fmt.Errorf("%s is invalid project", name)
}

var cfg config

var cfgFilePath string
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	nerrors "errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/errors"
	"github.com/filebrowser/filebrowser/v2/settings"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func init() {
	rootCmd.AddCommand(configCmd)
}

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Configuration management utility",
	Long:  `Configuration management utility.`,
	Args:  cobra.NoArgs,
}

func addConfigFlags(flags *pflag.FlagSet) {
	addServerFlags(flags)
	addUserFlags(flags)
	flags.BoolP("signup", "s", false, "allow users to signup")
	flags.String("shell", "", "shell command to which other commands should be appended")

	flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
	flags.String("auth.header", "", "HTTP header for auth.method=proxy")

	flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
	flags.String("recaptcha.key", "", "ReCaptcha site key")
	flags.String("recaptcha.secret", "", "ReCaptcha secret")

	flags.String("branding.name", "", "replace 'File Browser' by this name")
	flags.String("branding.files", "", "path to directory with images and custom styles")
	flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
}

func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther) {
	method := settings.AuthMethod(mustGetString(flags, "auth.method"))

	var defaultAuther map[string]interface{}
	if len(defaults) > 0 {
		if hasAuth := defaults[0]; hasAuth != true {
			for _, arg := range defaults {
				switch def := arg.(type) {
				case *settings.Settings:
					method = settings.AuthMethod(def.AuthMethod)
				case auth.Auther:
					ms, err := json.Marshal(def)
					checkErr(err)
					json.Unmarshal(ms, &defaultAuther)
				}
			}
		}
	}

	var auther auth.Auther
	if method == auth.MethodProxyAuth {
		header := mustGetString(flags, "auth.header")

		if header == "" {
			header = defaultAuther["header"].(string)
		}

		if header == "" {
			checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
		}

		auther = &auth.ProxyAuth{Header: header}
	}

	if method == auth.MethodNoAuth {
		auther = &auth.NoAuth{}
	}

	if method == auth.MethodJSONAuth {
		jsonAuth := &auth.JSONAuth{}
		host := mustGetString(flags, "recaptcha.host")
		key := mustGetString(flags, "recaptcha.key")
		secret := mustGetString(flags, "recaptcha.secret")

		if key == "" {
			kmap := defaultAuther["recaptcha"].(map[string]interface{})
			key = kmap["key"].(string)
		}

		if secret == "" {
			smap := defaultAuther["recaptcha"].(map[string]interface{})
			secret = smap["secret"].(string)
		}

		if key == "" || secret == "" {
			checkErr(nerrors.New("you must set the flag 'recaptcha.key' and 'recaptcha.secret' for method 'json'"))
		}

		jsonAuth.ReCaptcha = &auth.ReCaptcha{
			Host:   host,
			Key:    key,
			Secret: secret,
		}

		auther = jsonAuth
	}

	if auther == nil {
		panic(errors.ErrInvalidAuthMethod)
	}

	return method, auther
}

func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
	fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
	fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
	fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
	fmt.Fprintln(w, "\nBranding:")
	fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
	fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
	fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
	fmt.Fprintln(w, "\nServer:")
	fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
	fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
	fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
	fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
	fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
	fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
	fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
	fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
	fmt.Fprintln(w, "\nDefaults:")
	fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
	fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
	fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
	fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
	fmt.Fprintf(w, "\tSorting:\n")
	fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
	fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
	fmt.Fprintf(w, "\tPermissions:\n")
	fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
	fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
	fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
	fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
	fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
	fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
	fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
	fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
	w.Flush()

	b, err := json.MarshalIndent(auther, "", "  ")
	checkErr(err)
	fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
}
<commit_msg>Check if keys exist in map. Fixes: #736<commit_after>package cmd

import (
	"encoding/json"
	nerrors "errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/errors"
	"github.com/filebrowser/filebrowser/v2/settings"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func init() {
	rootCmd.AddCommand(configCmd)
}

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Configuration management utility",
	Long:  `Configuration management utility.`,
	Args:  cobra.NoArgs,
}

func addConfigFlags(flags *pflag.FlagSet) {
	addServerFlags(flags)
	addUserFlags(flags)
	flags.BoolP("signup", "s", false, "allow users to signup")
	flags.String("shell", "", "shell command to which other commands should be appended")

	flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
	flags.String("auth.header", "", "HTTP header for auth.method=proxy")

	flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
	flags.String("recaptcha.key", "", "ReCaptcha site key")
	flags.String("recaptcha.secret", "", "ReCaptcha secret")

	flags.String("branding.name", "", "replace 'File Browser' by this name")
	flags.String("branding.files", "", "path to directory with images and custom styles")
	flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
}

func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther) {
	method := settings.AuthMethod(mustGetString(flags, "auth.method"))

	var defaultAuther map[string]interface{}
	if len(defaults) > 0 {
		if hasAuth := defaults[0]; hasAuth != true {
			for _, arg := range defaults {
				switch def := arg.(type) {
				case *settings.Settings:
					method = settings.AuthMethod(def.AuthMethod)
				case auth.Auther:
					ms, err := json.Marshal(def)
					checkErr(err)
					json.Unmarshal(ms, &defaultAuther)
				}
			}
		}
	}

	var auther auth.Auther
	if method == auth.MethodProxyAuth {
		header := mustGetString(flags, "auth.header")

		if header == "" {
			header = defaultAuther["header"].(string)
		}

		if header == "" {
			checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
		}

		auther = &auth.ProxyAuth{Header: header}
	}

	if method == auth.MethodNoAuth {
		auther = &auth.NoAuth{}
	}

	if method == auth.MethodJSONAuth {
		jsonAuth := &auth.JSONAuth{}
		host := mustGetString(flags, "recaptcha.host")
		key := mustGetString(flags, "recaptcha.key")
		secret := mustGetString(flags, "recaptcha.secret")

		if key == "" {
			if kmap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
				key = kmap["key"].(string)
			}
		}

		if secret == "" {
			if smap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
				secret = smap["secret"].(string)
			}
		}

		if key != "" && secret != "" {
			jsonAuth.ReCaptcha = &auth.ReCaptcha{
				Host:   host,
				Key:    key,
				Secret: secret,
			}
		}
		auther = jsonAuth
	}

	if auther == nil {
		panic(errors.ErrInvalidAuthMethod)
	}

	return method, auther
}

func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
	fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
	fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
	fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
	fmt.Fprintln(w, "\nBranding:")
	fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
	fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
	fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
	fmt.Fprintln(w, "\nServer:")
	fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
	fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
	fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
	fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
	fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
	fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
	fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
	fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
	fmt.Fprintln(w, "\nDefaults:")
	fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
	fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
	fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
	fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
	fmt.Fprintf(w, "\tSorting:\n")
	fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
	fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
	fmt.Fprintf(w, "\tPermissions:\n")
	fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
	fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
	fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
	fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
	fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
	fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
	fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
	fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
	w.Flush()

	b, err := json.MarshalIndent(auther, "", "  ")
	checkErr(err)
	fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
}
<|endoftext|>


<commit_before>package cmd

import (
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	datacenter string
	osTemplate string
	cpu        int
	memory     float64
	disksize   int
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "roles to assign to the host via grain and d42 [eg: kubernetes-master]")
	deployCmd.Flags().StringVarP(&datacenter, "datacenter", "d", "", "Datacenter to assign to the host via grain [eg: us-east]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, ubuntu_16.04]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().IntVarP(&cpu, "cpu", "", 0, "CPU to assign to the host [eg: 1]")
	deployCmd.Flags().Float64VarP(&memory, "memory", "", 0, "Memory to assign to the host [eg: 32]")
	deployCmd.Flags().IntVarP(&disksize, "disksize", "", 0, "DiskSize to assign to the host [eg: 200]")

	deployCmd.MarkFlagRequired("profile")
	deployCmd.MarkFlagRequired("template")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the mega profile using vmware as a provider:

$ pepper deploy -p vmware-uat-mega -t Ubuntu web03

Are we understanding how this works?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r kubernetes-master kubernetes01 kubernetes02 kubernetes03

We can also define a roles and datacenter via grains

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r kubernetes-master -d us-east kubernetes01 kubernetes02 kubernetes03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			logrus.Fatal("You didn't specify a profile.")
		} else if osTemplate == "" {
			logrus.Fatal("You didn't specify an OS template.")
		} else if len(args) == 0 {
			logrus.Fatal("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					logrus.Fatalf("can't read device42 config: %v", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					logrus.Fatalf("unable to retrieve next IP from device42: %v", err)
				}
				vsphere.IPAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						logrus.Warnf("unable to delete device from device42: %v", err)
					}
					logrus.Fatalf("unable to create device in device42: %v", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(vsphere.IPAddress, host); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to reserve an IP in device42: %v", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to update custom fields in device42 (i.e. roles): %v", err)
				}
			}
			switch platform {
			case "vmware":
				var config vsphere.ProfileConfig

				vsphere.Platform = platform
				vsphere.Environment = environment
				vsphere.InstanceType = instancetype
				vsphere.Template = osTemplate
				vsphere.Role = roles
				vsphere.Datacenter = datacenter

				if err := config.Prepare(); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to read the vmware environment file: %v", err)
				}

				if cpu > 0 {
					config.CPU = cpu
				} else if memory > 0 {
					config.Memory = memory
				} else if disksize > 0 {
					config.DiskSize = disksize
				}

				if err := config.Generate(); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to generate the vmware profile from template: %v", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to provision the vmware host with salt-cloud: %v", err)
				}
			default:
				logrus.Fatalf("I don't recognize this platform!")
			}
		}
		logrus.Info("Success!")
	},
}
<commit_msg>Fix if conditional for custom resource amounts<commit_after>package cmd

import (
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	datacenter string
	osTemplate string
	cpu        int
	memory     float64
	disksize   int
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "roles to assign to the host via grain and d42 [eg: kubernetes-master]")
	deployCmd.Flags().StringVarP(&datacenter, "datacenter", "d", "", "Datacenter to assign to the host via grain [eg: us-east]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, ubuntu_16.04]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().IntVarP(&cpu, "cpu", "", 0, "CPU to assign to the host [eg: 1]")
	deployCmd.Flags().Float64VarP(&memory, "memory", "", 0, "Memory to assign to the host [eg: 32]")
	deployCmd.Flags().IntVarP(&disksize, "disksize", "", 0, "DiskSize to assign to the host [eg: 200]")

	deployCmd.MarkFlagRequired("profile")
	deployCmd.MarkFlagRequired("template")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the mega profile using vmware as a provider:

$ pepper deploy -p vmware-uat-mega -t Ubuntu web03

Are we understanding how this works?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r kubernetes-master kubernetes01 kubernetes02 kubernetes03

We can also define a roles and datacenter via grains

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r kubernetes-master -d us-east kubernetes01 kubernetes02 kubernetes03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			logrus.Fatal("You didn't specify a profile.")
		} else if osTemplate == "" {
			logrus.Fatal("You didn't specify an OS template.")
		} else if len(args) == 0 {
			logrus.Fatal("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					logrus.Fatalf("can't read device42 config: %v", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					logrus.Fatalf("unable to retrieve next IP from device42: %v", err)
				}
				vsphere.IPAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						logrus.Warnf("unable to delete device from device42: %v", err)
					}
					logrus.Fatalf("unable to create device in device42: %v", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(vsphere.IPAddress, host); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to reserve an IP in device42: %v", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to update custom fields in device42 (i.e. roles): %v", err)
				}
			}
			switch platform {
			case "vmware":
				var config vsphere.ProfileConfig

				vsphere.Platform = platform
				vsphere.Environment = environment
				vsphere.InstanceType = instancetype
				vsphere.Template = osTemplate
				vsphere.Role = roles
				vsphere.Datacenter = datacenter

				if err := config.Prepare(); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to read the vmware environment file: %v", err)
				}

				if cpu > 0 {
					config.CPU = cpu
				}
				if memory > 0 {
					config.Memory = memory
				}
				if disksize > 0 {
					config.DiskSize = disksize
				}

				if err := config.Generate(); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to generate the vmware profile from template: %v", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.CleanDeviceAndIP(vsphere.IPAddress, host); err != nil {
						logrus.Warnf("unable to delete device or remove the device association from the IP in device42: %v", err)
					}
					logrus.Fatalf("unable to provision the vmware host with salt-cloud: %v", err)
				}
			default:
				logrus.Fatalf("I don't recognize this platform!")
			}
		}
		logrus.Info("Success!")
	},
}
<|endoftext|>