func listHostOnlyAdapters(vbox VBoxManager) (map[string]*hostOnlyNetwork, error) {
	out, err := vbox.vbmOut("list", "hostonlyifs")
	if err != nil {
		return nil, err
	}

	byName := map[string]*hostOnlyNetwork{}
	byIP := map[string]*hostOnlyNetwork{}
	n := &hostOnlyNetwork{}

	err = parseKeyValues(out, reColonLine, func(key, val string) error {
		switch key {
		case "Name":
			n.Name = val
		case "GUID":
			n.GUID = val
		case "DHCP":
			n.DHCP = (val != "Disabled")
		case "IPAddress":
			n.IPv4.IP = net.ParseIP(val)
		case "NetworkMask":
			n.IPv4.Mask = parseIPv4Mask(val)
		case "HardwareAddress":
			mac, err := net.ParseMAC(val)
			if err != nil {
				return err
			}
			n.HwAddr = mac
		case "MediumType":
			n.Medium = val
		case "Status":
			n.Status = val
		case "VBoxNetworkName":
			n.NetworkName = val

			if _, present := byName[n.NetworkName]; present {
				return fmt.Errorf("VirtualBox is configured with multiple host-only adapters with the same name %q. Please remove one", n.NetworkName)
			}
			byName[n.NetworkName] = n

			if len(n.IPv4.IP) != 0 {
				if _, present := byIP[n.IPv4.IP.String()]; present {
					return fmt.Errorf("VirtualBox is configured with multiple host-only adapters with the same IP %q. Please remove one", n.IPv4.IP)
				}
				byIP[n.IPv4.IP.String()] = n
			}

			n = &hostOnlyNetwork{}
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return byName, nil
}

func listHostOnlyAdapters ( vbox VBoxManager ) ( map [ string ] * hostOnlyNetwork , error ) { out , err := vbox . vbmOut ( " " , " " ) if err != nil { return nil , err } byName := map [ string ] * hostOnlyNetwork { } byIP := map [ string ] * hostOnlyNetwork { } n := & hostOnlyNetwork { } err = parseKeyValues ( out , reColonLine , func ( key , val string ) error { switch key { case " " : n . Name = val case " " : n . GUID = val case " " : n . DHCP = ( val != " " ) case " " : n . IPv4 . IP = net . ParseIP ( val ) case " " : n . IPv4 . Mask = parseIPv4Mask ( val ) case " " : mac , err := net . ParseMAC ( val ) if err != nil { return err } n . HwAddr = mac case " " : n . Medium = val case " " : n . Status = val case " " : n . NetworkName = val if _ , present := byName [ n . NetworkName ] ; present { return fmt . Errorf ( " " , n . NetworkName ) } byName [ n . NetworkName ] = n if len ( n . IPv4 . IP ) != 0 { if _ , present := byIP [ n . IPv4 . IP . String ( ) ] ; present { return fmt . Errorf ( " " , n . IPv4 . IP ) } byIP [ n . IPv4 . IP . String ( ) ] = n } n = & hostOnlyNetwork { } } return nil } ) if err != nil { return nil , err } return byName , nil }

// listHostOnlyAdapters gets all host-only adapters in a  map keyed by NetworkName.

listHostOnlyAdapters gets all host - only adapters in a map keyed by NetworkName .


func removeOrphanDHCPServers(vbox VBoxManager) error {
	dhcps, err := listDHCPServers(vbox)
	if err != nil {
		return err
	}

	if len(dhcps) == 0 {
		return nil
	}

	log.Debug("Removing orphan DHCP servers...")

	nets, err := listHostOnlyAdapters(vbox)
	if err != nil {
		return err
	}

	for name := range dhcps {
		if strings.HasPrefix(name, dhcpPrefix) {
			if _, present := nets[name]; !present {
				if err := vbox.vbm("dhcpserver", "remove", "--netname", name); err != nil {
					log.Warnf("Unable to remove orphan dhcp server %q: %s", name, err)
				}
			}
		}
	}

	return nil
}

func removeOrphanDHCPServers ( vbox VBoxManager ) error { dhcps , err := listDHCPServers ( vbox ) if err != nil { return err } if len ( dhcps ) == 0 { return nil } log . Debug ( " " ) nets , err := listHostOnlyAdapters ( vbox ) if err != nil { return err } for name := range dhcps { if strings . HasPrefix ( name , dhcpPrefix ) { if _ , present := nets [ name ] ; ! present { if err := vbox . vbm ( " " , " " , " " , name ) ; err != nil { log . Warnf ( " " , name , err ) } } } } return nil }

// removeOrphanDHCPServers removed the DHCP servers linked to no host-only adapter

removeOrphanDHCPServers removed the DHCP servers linked to no host - only adapter


func addHostOnlyDHCPServer(ifname string, d dhcpServer, vbox VBoxManager) error {
	name := dhcpPrefix + ifname

	dhcps, err := listDHCPServers(vbox)
	if err != nil {
		return err
	}

	// On some platforms (OSX), creating a host-only adapter adds a default dhcpserver,
	// while on others (Windows?) it does not.
	command := "add"
	if dhcp, ok := dhcps[name]; ok {
		command = "modify"
		if (dhcp.IPv4.IP.Equal(d.IPv4.IP)) && (dhcp.IPv4.Mask.String() == d.IPv4.Mask.String()) && (dhcp.LowerIP.Equal(d.LowerIP)) && (dhcp.UpperIP.Equal(d.UpperIP)) && (dhcp.Enabled == d.Enabled) {
			// dhcp is up to date
			return nil
		}
	}

	args := []string{"dhcpserver", command,
		"--netname", name,
		"--ip", d.IPv4.IP.String(),
		"--netmask", net.IP(d.IPv4.Mask).String(),
		"--lowerip", d.LowerIP.String(),
		"--upperip", d.UpperIP.String(),
	}
	if d.Enabled {
		args = append(args, "--enable")
	} else {
		args = append(args, "--disable")
	}

	if runtime.GOOS == "windows" {
		log.Warn("Windows might ask for the permission to configure a dhcp server. Sometimes, such confirmation window is minimized in the taskbar.")
	}

	return vbox.vbm(args...)
}

// addHostOnlyDHCPServer adds a DHCP server to a host-only network.

addHostOnlyDHCPServer adds a DHCP server to a host - only network .


func listDHCPServers(vbox VBoxManager) (map[string]*dhcpServer, error) {
	out, err := vbox.vbmOut("list", "dhcpservers")
	if err != nil {
		return nil, err
	}

	m := map[string]*dhcpServer{}
	dhcp := &dhcpServer{}

	err = parseKeyValues(out, reColonLine, func(key, val string) error {
		switch key {
		case "NetworkName":
			dhcp = &dhcpServer{}
			m[val] = dhcp
			dhcp.NetworkName = val
		case "IP":
			dhcp.IPv4.IP = net.ParseIP(val)
		case "upperIPAddress":
			dhcp.UpperIP = net.ParseIP(val)
		case "lowerIPAddress":
			dhcp.LowerIP = net.ParseIP(val)
		case "NetworkMask":
			dhcp.IPv4.Mask = parseIPv4Mask(val)
		case "Enabled":
			dhcp.Enabled = (val == "Yes")
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return m, nil
}

func listDHCPServers ( vbox VBoxManager ) ( map [ string ] * dhcpServer , error ) { out , err := vbox . vbmOut ( " " , " " ) if err != nil { return nil , err } m := map [ string ] * dhcpServer { } dhcp := & dhcpServer { } err = parseKeyValues ( out , reColonLine , func ( key , val string ) error { switch key { case " " : dhcp = & dhcpServer { } m [ val ] = dhcp dhcp . NetworkName = val case " " : dhcp . IPv4 . IP = net . ParseIP ( val ) case " " : dhcp . UpperIP = net . ParseIP ( val ) case " " : dhcp . LowerIP = net . ParseIP ( val ) case " " : dhcp . IPv4 . Mask = parseIPv4Mask ( val ) case " " : dhcp . Enabled = ( val == " " ) } return nil } ) if err != nil { return nil , err } return m , nil }

// listDHCPServers lists all DHCP server settings in a map keyed by DHCP.NetworkName.

listDHCPServers lists all DHCP server settings in a map keyed by DHCP . NetworkName .


func checkIPNetCollision(hostonly *net.IPNet, hostIfaces map[string]*net.IPNet) (bool, error) {
	for _, ifaceNet := range hostIfaces {
		if hostonly.IP.Equal(ifaceNet.IP.Mask(ifaceNet.Mask)) {
			return true, nil
		}
	}
	return false, nil
}

func checkIPNetCollision ( hostonly * net . IPNet , hostIfaces map [ string ] * net . IPNet ) ( bool , error ) { for _ , ifaceNet := range hostIfaces { if hostonly . IP . Equal ( ifaceNet . IP . Mask ( ifaceNet . Mask ) ) { return true , nil } } return false , nil }

// checkIPNetCollision returns true if any host interfaces conflict with the host-only network mask passed as a parameter.
// This works with IPv4 or IPv6 ip addresses.

checkIPNetCollision returns true if any host interfaces conflict with the host - only network mask passed as a parameter . This works with IPv4 or IPv6 ip addresses .


func NewDriverNotSupported(driverName, hostName, storePath string) Driver {
	return &DriverNotSupported{
		BaseDriver: &BaseDriver{
			MachineName: hostName,
			StorePath:   storePath,
		},
		Name: driverName,
	}
}

func NewDriverNotSupported ( driverName , hostName , storePath string ) Driver { return & DriverNotSupported { BaseDriver : & BaseDriver { MachineName : hostName , StorePath : storePath , } , Name : driverName , } }

// NewDriverNotSupported creates a placeholder Driver that replaces
// a driver that is not supported on a given platform. eg fusion on linux.

NewDriverNotSupported creates a placeholder Driver that replaces a driver that is not supported on a given platform . eg fusion on linux .


func (c *RPCClientDriver) DriverName() string {
	driverName, err := c.rpcStringCall(DriverNameMethod)
	if err != nil {
		log.Warnf("Error attempting call to get driver name: %s", err)
	}

	return driverName
}

func ( c * RPCClientDriver ) DriverName ( ) string { driverName , err := c . rpcStringCall ( DriverNameMethod ) if err != nil { log . Warnf ( " " , err ) } return driverName }

// DriverName returns the name of the driver


func MustBeRunning(d Driver) error {
	s, err := d.GetState()
	if err != nil {
		return err
	}

	if s != state.Running {
		return ErrHostIsNotRunning
	}

	return nil
}

func MustBeRunning ( d Driver ) error { s , err := d . GetState ( ) if err != nil { return err } if s != state . Running { return ErrHostIsNotRunning } return nil }

// MustBeRunning will return an error if the machine is not in a running state.

MustBeRunning will return an error if the machine is not in a running state .


func NewDriver(hostName, storePath string) drivers.Driver {
	return &Driver{
		EnginePort: engine.DefaultPort,
		BaseDriver: &drivers.BaseDriver{
			MachineName: hostName,
			StorePath:   storePath,
		},
	}
}

func NewDriver ( hostName , storePath string ) drivers . Driver { return & Driver { EnginePort : engine . DefaultPort , BaseDriver : & drivers . BaseDriver { MachineName : hostName , StorePath : storePath , } , } }

// NewDriver creates and returns a new instance of the driver


func migrateStringToSlice(value string, values []string) (result []string) {
	if value != "" {
		result = append(result, value)
	}
	result = append(result, values...)
	return
}

func migrateStringToSlice ( value string , values [ ] string ) ( result [ ] string ) { if value != " " { result = append ( result , value ) } result = append ( result , values ... ) return }

// Support migrating single string Driver fields to slices.

Support migrating single string Driver fields to slices .


func DockerClient(dockerHost DockerHost) (*dockerclient.DockerClient, error) {
	url, err := dockerHost.URL()
	if err != nil {
		return nil, err
	}

	tlsConfig, err := cert.ReadTLSConfig(url, dockerHost.AuthOptions())
	if err != nil {
		return nil, fmt.Errorf("Unable to read TLS config: %s", err)
	}

	return dockerclient.NewDockerClient(url, tlsConfig)
}

func DockerClient ( dockerHost DockerHost ) ( * dockerclient . DockerClient , error ) { url , err := dockerHost . URL ( ) if err != nil { return nil , err } tlsConfig , err := cert . ReadTLSConfig ( url , dockerHost . AuthOptions ( ) ) if err != nil { return nil , fmt . Errorf ( " " , err ) } return dockerclient . NewDockerClient ( url , tlsConfig ) }

// DockerClient creates a docker client for a given host.

DockerClient creates a docker client for a given host .


func CreateContainer(dockerHost DockerHost, config *dockerclient.ContainerConfig, name string) error {
	docker, err := DockerClient(dockerHost)
	if err != nil {
		return err
	}

	if err = docker.PullImage(config.Image, nil); err != nil {
		return fmt.Errorf("Unable to pull image: %s", err)
	}

	var authConfig *dockerclient.AuthConfig
	containerID, err := docker.CreateContainer(config, name, authConfig)
	if err != nil {
		return fmt.Errorf("Error while creating container: %s", err)
	}

	if err = docker.StartContainer(containerID, &config.HostConfig); err != nil {
		return fmt.Errorf("Error while starting container: %s", err)
	}

	return nil
}

func CreateContainer ( dockerHost DockerHost , config * dockerclient . ContainerConfig , name string ) error { docker , err := DockerClient ( dockerHost ) if err != nil { return err } if err = docker . PullImage ( config . Image , nil ) ; err != nil { return fmt . Errorf ( " " , err ) } var authConfig * dockerclient . AuthConfig containerID , err := docker . CreateContainer ( config , name , authConfig ) if err != nil { return fmt . Errorf ( " " , err ) } if err = docker . StartContainer ( containerID , & config . HostConfig ) ; err != nil { return fmt . Errorf ( " " , err ) } return nil }

// CreateContainer creates a docker container.

CreateContainer creates a docker container .


func (a AzureClient) cleanupResourceIfExists(r cleanupResource) error {
	f := r.LogFields()
	log.Info(fmt.Sprintf("Attempting to clean up %s resource...", r.ResourceType()), f)
	err := r.Get(a)
	if exists, err := checkResourceExistsFromError(err); err != nil {
		return err
	} else if !exists {
		log.Debug(fmt.Sprintf("%s resource does not exist. Skipping.", r.ResourceType()), f)
		return nil
	}

	if !r.HasAttachedResources() {
		log.Debug(fmt.Sprintf("%s does not have any attached dependent resource.", r.ResourceType()), f)
		log.Info(fmt.Sprintf("Removing %s resource...", r.ResourceType()), f)
		return r.Delete(a)
	}
	log.Info(fmt.Sprintf("%s is still in use by other resources, skipping removal.", r.ResourceType()), f)
	return nil
}

func ( a AzureClient ) cleanupResourceIfExists ( r cleanupResource ) error { f := r . LogFields ( ) log . Info ( fmt . Sprintf ( " " , r . ResourceType ( ) ) , f ) err := r . Get ( a ) if exists , err := checkResourceExistsFromError ( err ) ; err != nil { return err } else if ! exists { log . Debug ( fmt . Sprintf ( " " , r . ResourceType ( ) ) , f ) return nil } if ! r . HasAttachedResources ( ) { log . Debug ( fmt . Sprintf ( " " , r . ResourceType ( ) ) , f ) log . Info ( fmt . Sprintf ( " " , r . ResourceType ( ) ) , f ) return r . Delete ( a ) } log . Info ( fmt . Sprintf ( " " , r . ResourceType ( ) ) , f ) return nil }

// cleanupResourceIfExists checks if the resource exists, if it does and it
// does not have any attached resources, then deletes the resource. If the
// resource does not exist or is not eligible for cleanup, returns nil. If an
// error is encountered, returns the error.

cleanupResourceIfExists checks if the resource exists if it does and it does not have any attached resources then deletes the resource . If the resource does not exist or is not eligible for cleanup returns nil . If an error is encountered returns the error .


func NewDriver(machineName, storePath string) drivers.Driver {
	return &Driver{
		InstanceProfile:  defaultInstanceProfile,
		DiskSize:         defaultDiskSize,
		Image:            defaultImage,
		AvailabilityZone: defaultAvailabilityZone,
		BaseDriver: &drivers.BaseDriver{
			MachineName: machineName,
			StorePath:   storePath,
		},
	}
}

func NewDriver ( machineName , storePath string ) drivers . Driver { return & Driver { InstanceProfile : defaultInstanceProfile , DiskSize : defaultDiskSize , Image : defaultImage , AvailabilityZone : defaultAvailabilityZone , BaseDriver : & drivers . BaseDriver { MachineName : machineName , StorePath : storePath , } , } }

// NewDriver creates a Driver with the specified machineName and storePath.

NewDriver creates a Driver with the specified machineName and storePath .


func (d *Driver) GetSSHUsername() string {
	if d.SSHUser == "" {
		name := strings.ToLower(d.Image)

		if strings.Contains(name, "ubuntu") {
			return "ubuntu"
		}
		if strings.Contains(name, "centos") {
			return "centos"
		}
		if strings.Contains(name, "redhat") {
			return "cloud-user"
		}
		if strings.Contains(name, "fedora") {
			return "fedora"
		}
		if strings.Contains(name, "coreos") {
			return "core"
		}
		if strings.Contains(name, "debian") {
			return "debian"
		}
		return defaultSSHUser
	}

	return d.SSHUser
}

func ( d * Driver ) GetSSHUsername ( ) string { if d . SSHUser == " " { name := strings . ToLower ( d . Image ) if strings . Contains ( name , " " ) { return " " } if strings . Contains ( name , " " ) { return " " } if strings . Contains ( name , " " ) { return " " } if strings . Contains ( name , " " ) { return " " } if strings . Contains ( name , " " ) { return " " } if strings . Contains ( name , " " ) { return " " } return defaultSSHUser } return d . SSHUser }

// GetSSHUsername returns the username to use with SSH


func (d *Driver) Start() error {
	cs := d.client()
	_, err := cs.RequestWithContext(context.TODO(), &egoscale.StartVirtualMachine{
		ID: d.ID,
	})

	return err
}

func ( d * Driver ) Start ( ) error { cs := d . client ( ) _ , err := cs . RequestWithContext ( context . TODO ( ) , & egoscale . StartVirtualMachine { ID : d . ID , } ) return err }

// Start starts the existing VM instance.


func (d *Driver) Stop() error {
	cs := d.client()
	_, err := cs.RequestWithContext(context.TODO(), &egoscale.StopVirtualMachine{
		ID: d.ID,
	})

	return err
}

func ( d * Driver ) Stop ( ) error { cs := d . client ( ) _ , err := cs . RequestWithContext ( context . TODO ( ) , & egoscale . StopVirtualMachine { ID : d . ID , } ) return err }


func (d *Driver) Restart() error {
	cs := d.client()
	_, err := cs.RequestWithContext(context.TODO(), &egoscale.RebootVirtualMachine{
		ID: d.ID,
	})

	return err
}

func ( d * Driver ) Restart ( ) error { cs := d . client ( ) _ , err := cs . RequestWithContext ( context . TODO ( ) , & egoscale . RebootVirtualMachine { ID : d . ID , } ) return err }

// Restart reboots the existing VM instance.

Restart reboots the existing VM instance .


func (d *Driver) Remove() error {
	client := d.client()

	// Destroy the SSH key from CloudStack
	if d.KeyPair != "" {
		key := &egoscale.SSHKeyPair{Name: d.KeyPair}
		if err := client.DeleteWithContext(context.TODO(), key); err != nil {
			return err
		}
	}

	// Destroy the virtual machine
	if d.ID != "" {
		vm := &egoscale.VirtualMachine{ID: d.ID}
		if err := client.DeleteWithContext(context.TODO(), vm); err != nil {
			return err
		}
	}

	log.Infof("The Anti-Affinity group and Security group were not removed")

	return nil
}

func
(
d
*
Driver
)
Remove
(
)
error
{
client
:=
d
.
client
(
)
// Destroy the SSH key from CloudStack
if
d
.
KeyPair
!=
"
"
{
key
:=
&
egoscale
.
SSHKeyPair
{
Name
:
d
.
KeyPair
}
if
err
:=
client
.
DeleteWithContext
(
context
.
TODO
(
)
,
key
)
;
err
!=
{
return
err
}
}
// Destroy the virtual machine
if
d
.
ID
!=
"
"
{
vm
:=
&
egoscale
.
VirtualMachine
{
ID
:
d
.
ID
}
if
err
:=
client
.
DeleteWithContext
(
context
.
TODO
(
)
,
vm
)
;
err
!=
{
return
err
}
}
log
.
Infof
(
"
"
)
return
}

// Remove destroys the VM instance and the associated SSH key.

Remove destroys the VM instance and the associated SSH key .


func (d *Driver) getCloudInit() ([]byte, error) {
	var err error
	if d.UserDataFile != "" {
		d.UserData, err = ioutil.ReadFile(d.UserDataFile)
	}

	return d.UserData, err
}

func ( d * Driver ) getCloudInit ( ) ( [ ] byte , error ) { var err error if d . UserDataFile != " " { d . UserData , err = ioutil . ReadFile ( d . UserDataFile ) } return d . UserData , err }

// Build a cloud-init user data string that will install and run
// docker.

Build a cloud - init user data string that will install and run docker .


func (xcg *X509CertGenerator) GenerateCACertificate(certFile, keyFile, org string, bits int) error {
	template, err := xcg.newCertificate(org)
	if err != nil {
		return err
	}

	template.IsCA = true
	template.KeyUsage |= x509.KeyUsageCertSign
	template.KeyUsage |= x509.KeyUsageKeyEncipherment
	template.KeyUsage |= x509.KeyUsageKeyAgreement

	priv, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return err
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
	if err != nil {
		return err
	}

	certOut, err := os.Create(certFile)
	if err != nil {
		return err
	}

	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()

	keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err

	}

	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()

	return nil
}

func ( xcg * X509CertGenerator ) GenerateCACertificate ( certFile , keyFile , org string , bits int ) error { template , err := xcg . newCertificate ( org ) if err != nil { return err } template . IsCA = true template . KeyUsage |= x509 . KeyUsageCertSign template . KeyUsage |= x509 . KeyUsageKeyEncipherment template . KeyUsage |= x509 . KeyUsageKeyAgreement priv , err := rsa . GenerateKey ( rand . Reader , bits ) if err != nil { return err } derBytes , err := x509 . CreateCertificate ( rand . Reader , template , template , & priv . PublicKey , priv ) if err != nil { return err } certOut , err := os . Create ( certFile ) if err != nil { return err } pem . Encode ( certOut , & pem . Block { Type : " " , Bytes : derBytes } ) certOut . Close ( ) keyOut , err := os . OpenFile ( keyFile , os . O_WRONLY | os . O_CREATE | os . O_TRUNC , 0600 ) if err != nil { return err } pem . Encode ( keyOut , & pem . Block { Type : " " , Bytes : x509 . MarshalPKCS1PrivateKey ( priv ) } ) keyOut . Close ( ) return nil }

// GenerateCACertificate generates a new certificate authority from the specified org
// and bit size and stores the resulting certificate and key file
// in the arguments.

GenerateCACertificate generates a new certificate authority from the specified org and bit size and stores the resulting certificate and key file in the arguments .


func (xcg *X509CertGenerator) GenerateCert(opts *Options) error {
	template, err := xcg.newCertificate(opts.Org)
	if err != nil {
		return err
	}
	// client
	if len(opts.Hosts) == 1 && opts.Hosts[0] == "" {
		template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
		template.KeyUsage = x509.KeyUsageDigitalSignature
	} else { // server
		template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
		if opts.SwarmMaster {
			// Extend the Swarm master's server certificate
			// permissions to also be able to connect to downstream
			// nodes as a client.
			template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageClientAuth)
		}
		for _, h := range opts.Hosts {
			if ip := net.ParseIP(h); ip != nil {
				template.IPAddresses = append(template.IPAddresses, ip)
			} else {
				template.DNSNames = append(template.DNSNames, h)
			}
		}
	}

	tlsCert, err := tls.LoadX509KeyPair(opts.CAFile, opts.CAKeyFile)
	if err != nil {
		return err
	}

	priv, err := rsa.GenerateKey(rand.Reader, opts.Bits)
	if err != nil {
		return err
	}

	x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
	if err != nil {
		return err
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, template, x509Cert, &priv.PublicKey, tlsCert.PrivateKey)
	if err != nil {
		return err
	}

	certOut, err := os.Create(opts.CertFile)
	if err != nil {
		return err
	}

	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()

	keyOut, err := os.OpenFile(opts.KeyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()

	return nil
}

// GenerateCert generates a new certificate signed using the provided
// certificate authority files and stores the result in the certificate
// file and key provided.  The provided host names are set to the
// appropriate certificate fields.

GenerateCert generates a new certificate signed using the provided certificate authority files and stores the result in the certificate file and key provided . The provided host names are set to the appropriate certificate fields .


func (xcg *X509CertGenerator) ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) {
	caCertPath := authOptions.CaCertPath
	clientCertPath := authOptions.ClientCertPath
	clientKeyPath := authOptions.ClientKeyPath

	log.Debugf("Reading CA certificate from %s", caCertPath)
	caCert, err := ioutil.ReadFile(caCertPath)
	if err != nil {
		return nil, err
	}

	log.Debugf("Reading client certificate from %s", clientCertPath)
	clientCert, err := ioutil.ReadFile(clientCertPath)
	if err != nil {
		return nil, err
	}

	log.Debugf("Reading client key from %s", clientKeyPath)
	clientKey, err := ioutil.ReadFile(clientKeyPath)
	if err != nil {
		return nil, err
	}

	return xcg.getTLSConfig(caCert, clientCert, clientKey, false)
}

func ( xcg * X509CertGenerator ) ReadTLSConfig ( addr string , authOptions * auth . Options ) ( * tls . Config , error ) { caCertPath := authOptions . CaCertPath clientCertPath := authOptions . ClientCertPath clientKeyPath := authOptions . ClientKeyPath log . Debugf ( " " , caCertPath ) caCert , err := ioutil . ReadFile ( caCertPath ) if err != nil { return nil , err } log . Debugf ( " " , clientCertPath ) clientCert , err := ioutil . ReadFile ( clientCertPath ) if err != nil { return nil , err } log . Debugf ( " " , clientKeyPath ) clientKey , err := ioutil . ReadFile ( clientKeyPath ) if err != nil { return nil , err } return xcg . getTLSConfig ( caCert , clientCert , clientKey , false ) }

// ReadTLSConfig reads the tls config for a machine.

ReadTLSConfig reads the tls config for a machine .


func (xcg *X509CertGenerator) ValidateCertificate(addr string, authOptions *auth.Options) (bool, error) {
	tlsConfig, err := xcg.ReadTLSConfig(addr, authOptions)
	if err != nil {
		return false, err
	}

	dialer := &net.Dialer{
		Timeout: time.Second * 20,
	}

	_, err = tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
	if err != nil {
		return false, err
	}

	return true, nil
}

func ( xcg * X509CertGenerator ) ValidateCertificate ( addr string , authOptions * auth . Options ) ( bool , error ) { tlsConfig , err := xcg . ReadTLSConfig ( addr , authOptions ) if err != nil { return false , err } dialer := & net . Dialer { Timeout : time . Second * 20 , } _ , err = tls . DialWithDialer ( dialer , " " , addr , tlsConfig ) if err != nil { return false , err } return true , nil }

// ValidateCertificate validate the certificate installed on the vm.

ValidateCertificate validate the certificate installed on the vm .


func (d *Driver) IsVTXDisabled() bool {
	if cpuid.HasFeature(cpuid.VMX) || cpuid.HasFeature(cpuid.SVM) {
		return false
	}

	return true
}

func ( d * Driver ) IsVTXDisabled ( ) bool { if cpuid . HasFeature ( cpuid . VMX ) || cpuid . HasFeature ( cpuid . SVM ) { return false } return true }

// IsVTXDisabled checks if VT-x is disabled in the CPU.

IsVTXDisabled checks if VT - x is disabled in the CPU .


func NewVBoxManager() *VBoxCmdManager {
	return &VBoxCmdManager{
		runCmd: func(cmd *exec.Cmd) error { return cmd.Run() },
	}
}

func NewVBoxManager ( ) * VBoxCmdManager { return & VBoxCmdManager { runCmd : func ( cmd * exec . Cmd ) error { return cmd . Run ( ) } , } }

// NewVBoxManager creates a VBoxManager instance.

NewVBoxManager creates a VBoxManager instance .


func driverPath(driverName string) string {
	for _, coreDriver := range CoreDrivers {
		if coreDriver == driverName {
			if CurrentBinaryIsDockerMachine {
				return os.Args[0]
			}

			return "docker-machine"
		}
	}

	return fmt.Sprintf("docker-machine-driver-%s", driverName)
}

func driverPath ( driverName string ) string { for _ , coreDriver := range CoreDrivers { if coreDriver == driverName { if CurrentBinaryIsDockerMachine { return os . Args [ 0 ] } return " " } } return fmt . Sprintf ( " " , driverName ) }

// driverPath finds the path of a driver binary by its name.
//  + If the driver is a core driver, there is no separate driver binary. We reuse current binary if it's `docker-machine`
// or we assume `docker-machine` is in the PATH.
//  + If the driver is NOT a core driver, then the separate binary must be in the PATH and it's name must be
// `docker-machine-driver-driverName`

driverPath finds the path of a driver binary by its name . + If the driver is a core driver there is no separate driver binary . We reuse current binary if it s docker - machine or we assume docker - machine is in the PATH . + If the driver is NOT a core driver then the separate binary must be in the PATH and it s name must be docker - machine - driver - driverName


func AuthenticateDeviceFlow(env azure.Environment, subscriptionID string) (*azure.ServicePrincipalToken, error) {
	// First we locate the tenant ID of the subscription as we store tokens per
	// tenant (which could have multiple subscriptions)
	tenantID, err := loadOrFindTenantID(env, subscriptionID)
	if err != nil {
		return nil, err
	}
	oauthCfg, err := env.OAuthConfigForTenant(tenantID)
	if err != nil {
		return nil, fmt.Errorf("Failed to obtain oauth config for azure environment: %v", err)
	}

	tokenPath := tokenCachePath(tenantID)
	saveToken := mkTokenCallback(tokenPath)
	saveTokenCallback := func(t azure.Token) error {
		log.Debug("Azure token expired. Saving the refreshed token...")
		return saveToken(t)
	}
	f := logutil.Fields{"path": tokenPath}

	appID, ok := appIDs[env.Name]
	if !ok {
		return nil, fmt.Errorf("docker-machine application not set up for Azure environment %q", env.Name)
	}
	scope := getScope(env)

	// Lookup the token cache file for an existing token.
	spt, err := tokenFromFile(*oauthCfg, tokenPath, appID, scope, saveTokenCallback)
	if err != nil {
		return nil, err
	}
	if spt != nil {
		log.Debug("Auth token found in file.", f)

		// NOTE(ahmetalpbalkan): The token file we found might be containing an
		// expired access_token. In that case, the first call to Azure SDK will
		// attempt to refresh the token using refresh_token –which might have
		// expired[1], in that case we will get an error and we shall remove the
		// token file and initiate token flow again so that the user would not
		// need removing the token cache file manually.
		//
		// [1]: for device flow auth, the expiration date of refresh_token is
		//      not returned in AAD /token response, we just know it is 14
		//      days. Therefore user’s token will go stale every 14 days and we
		//      will delete the token file, re-initiate the device flow. Service
		//      Principal Account tokens are not subject to this limitation.
		log.Debug("Validating the token.")
		if err := validateToken(env, spt); err != nil {
			log.Debug(fmt.Sprintf("Error: %v", err))
			log.Debug(fmt.Sprintf("Deleting %s", tokenPath))
			if err := os.RemoveAll(tokenPath); err != nil {
				return nil, fmt.Errorf("Error deleting stale token file: %v", err)
			}
		} else {
			log.Debug("Token works.")
			return spt, nil
		}
	}

	log.Debug("Obtaining a token.", f)
	spt, err = deviceFlowAuth(*oauthCfg, appID, scope)
	if err != nil {
		return nil, err
	}
	log.Debug("Obtained a token.")
	if err := saveToken(spt.Token); err != nil {
		log.Error("Error occurred saving token to cache file.")
		return nil, err
	}
	return spt, nil
}

// AuthenticateDeviceFlow fetches a token from the local file cache or initiates a consent
// flow and waits for token to be obtained. Obtained token is stored in a file cache for
// future use and refreshing.

AuthenticateDeviceFlow fetches a token from the local file cache or initiates a consent flow and waits for token to be obtained . Obtained token is stored in a file cache for future use and refreshing .


func AuthenticateServicePrincipal(env azure.Environment, subscriptionID, spID, spPassword string) (*azure.ServicePrincipalToken, error) {
	tenantID, err := loadOrFindTenantID(env, subscriptionID)
	if err != nil {
		return nil, err
	}
	oauthCfg, err := env.OAuthConfigForTenant(tenantID)
	if err != nil {
		return nil, fmt.Errorf("Failed to obtain oauth config for azure environment: %v", err)
	}

	spt, err := azure.NewServicePrincipalToken(*oauthCfg, spID, spPassword, getScope(env))
	if err != nil {
		return nil, fmt.Errorf("Failed to create service principal token: %+v", err)
	}
	return spt, nil
}

func AuthenticateServicePrincipal ( env azure . Environment , subscriptionID , spID , spPassword string ) ( * azure . ServicePrincipalToken , error ) { tenantID , err := loadOrFindTenantID ( env , subscriptionID ) if err != nil { return nil , err } oauthCfg , err := env . OAuthConfigForTenant ( tenantID ) if err != nil { return nil , fmt . Errorf ( " " , err ) } spt , err := azure . NewServicePrincipalToken ( * oauthCfg , spID , spPassword , getScope ( env ) ) if err != nil { return nil , fmt . Errorf ( " " , err ) } return spt , nil }

// AuthenticateServicePrincipal uses given service principal credentials to return a
// service principal token. Generated token is not stored in a cache file or refreshed.

AuthenticateServicePrincipal uses given service principal credentials to return a service principal token . Generated token is not stored in a cache file or refreshed .


func tokenFromFile(oauthCfg azure.OAuthConfig, tokenPath, clientID, resource string,
	callback azure.TokenRefreshCallback) (*azure.ServicePrincipalToken, error) {
	log.Debug("Loading auth token from file", logutil.Fields{"path": tokenPath})
	if _, err := os.Stat(tokenPath); err != nil {
		if os.IsNotExist(err) { // file not found
			return nil, nil
		}
		return nil, err
	}

	token, err := azure.LoadToken(tokenPath)
	if err != nil {
		return nil, fmt.Errorf("Failed to load token from file: %v", err)
	}

	spt, err := azure.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token, callback)
	if err != nil {
		return nil, fmt.Errorf("Error constructing service principal token: %v", err)
	}
	return spt, nil
}

func
tokenFromFile
(
oauthCfg
azure
.
OAuthConfig
,
tokenPath
,
clientID
,
resource
string
,
callback
azure
.
TokenRefreshCallback
)
(
*
azure
.
ServicePrincipalToken
,
error
)
{
log
.
Debug
(
"
"
,
logutil
.
Fields
{
"
"
:
tokenPath
}
)
if
_
,
err
:=
os
.
Stat
(
tokenPath
)
;
err
!=
{
if
os
.
IsNotExist
(
err
)
{
// file not found
return
,
}
return
,
err
}
token
,
err
:=
azure
.
LoadToken
(
tokenPath
)
if
err
!=
{
return
,
fmt
.
Errorf
(
"
"
,
err
)
}
spt
,
err
:=
azure
.
NewServicePrincipalTokenFromManualToken
(
oauthCfg
,
clientID
,
resource
,
*
token
,
callback
)
if
err
!=
{
return
,
fmt
.
Errorf
(
"
"
,
err
)
}
return
spt
,
}

// tokenFromFile returns a token from the specified file if it is found, otherwise
// returns nil. Any error retrieving or creating the token is returned as an error.

tokenFromFile returns a token from the specified file if it is found otherwise returns nil . Any error retrieving or creating the token is returned as an error .


func deviceFlowAuth(oauthCfg azure.OAuthConfig, clientID, resource string) (*azure.ServicePrincipalToken, error) {
	cl := oauthClient()
	deviceCode, err := azure.InitiateDeviceAuth(&cl, oauthCfg, clientID, resource)
	if err != nil {
		return nil, fmt.Errorf("Failed to start device auth: %v", err)
	}
	log.Debug("Retrieved device code.", logutil.Fields{
		"expires_in": to.Int64(deviceCode.ExpiresIn),
		"interval":   to.Int64(deviceCode.Interval),
	})

	// Example message: “To sign in, open https://aka.ms/devicelogin and enter
	// the code 0000000 to authenticate.”
	log.Infof("Microsoft Azure: %s", to.String(deviceCode.Message))

	token, err := azure.WaitForUserCompletion(&cl, deviceCode)
	if err != nil {
		return nil, fmt.Errorf("Failed to complete device auth: %v", err)
	}

	spt, err := azure.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token)
	if err != nil {
		return nil, fmt.Errorf("Error constructing service principal token: %v", err)
	}
	return spt, nil
}

// deviceFlowAuth prints a message to the screen for user to take action to
// consent application on a browser and in the meanwhile the authentication
// endpoint is polled until user gives consent, denies or the flow times out.
// Returned token must be saved.

deviceFlowAuth prints a message to the screen for user to take action to consent application on a browser and in the meanwhile the authentication endpoint is polled until user gives consent denies or the flow times out . Returned token must be saved .


func tokenCachePath(tenantID string) string {
	return filepath.Join(azureCredsPath(), fmt.Sprintf("%s.json", tenantID))
}

func tokenCachePath ( tenantID string ) string { return filepath . Join ( azureCredsPath ( ) , fmt . Sprintf ( " " , tenantID ) ) }

// tokenCachePath returns the full path the OAuth 2.0 token should be saved at
// for given tenant ID.

tokenCachePath returns the full path the OAuth 2 . 0 token should be saved at for given tenant ID .


func tenantIDPath(subscriptionID string) string {
	return filepath.Join(azureCredsPath(), fmt.Sprintf("%s.tenantid", subscriptionID))
}

func tenantIDPath ( subscriptionID string ) string { return filepath . Join ( azureCredsPath ( ) , fmt . Sprintf ( " " , subscriptionID ) ) }

// tenantIDPath returns the full path the tenant ID for the given subscription
// should be saved at.f

tenantIDPath returns the full path the tenant ID for the given subscription should be saved at . f


func mkTokenCallback(path string) azure.TokenRefreshCallback {
	return func(t azure.Token) error {
		if err := azure.SaveToken(path, 0600, t); err != nil {
			return err
		}
		log.Debug("Saved token to file.")
		return nil
	}
}

func mkTokenCallback ( path string ) azure . TokenRefreshCallback { return func ( t azure . Token ) error { if err := azure . SaveToken ( path , 0600 , t ) ; err != nil { return err } log . Debug ( " " ) return nil } }

// mkTokenCallback returns a callback function that can be used to save the
// token initially or register to the Azure SDK to be called when the token is
// refreshed.

mkTokenCallback returns a callback function that can be used to save the token initially or register to the Azure SDK to be called when the token is refreshed .


func NewFmtMachineLogger() MachineLogger {
	return &FmtMachineLogger{
		outWriter: os.Stdout,
		errWriter: os.Stderr,
		debug:     false,
		history:   NewHistoryRecorder(),
	}
}

func NewFmtMachineLogger ( ) MachineLogger { return & FmtMachineLogger { outWriter : os . Stdout , errWriter : os . Stderr , debug : false , history : NewHistoryRecorder ( ) , } }

// NewFmtMachineLogger creates a MachineLogger implementation used by the drivers


func newComputeUtil(driver *Driver) (*ComputeUtil, error) {
	client, err := google.DefaultClient(oauth2.NoContext, raw.ComputeScope)
	if err != nil {
		return nil, err
	}

	service, err := raw.New(client)
	if err != nil {
		return nil, err
	}

	return &ComputeUtil{
		zone:              driver.Zone,
		instanceName:      driver.MachineName,
		userName:          driver.SSHUser,
		project:           driver.Project,
		diskTypeURL:       driver.DiskType,
		address:           driver.Address,
		network:           driver.Network,
		subnetwork:        driver.Subnetwork,
		preemptible:       driver.Preemptible,
		useInternalIP:     driver.UseInternalIP,
		useInternalIPOnly: driver.UseInternalIPOnly,
		service:           service,
		zoneURL:           apiURL + driver.Project + "/zones/" + driver.Zone,
		globalURL:         apiURL + driver.Project + "/global",
		SwarmMaster:       driver.SwarmMaster,
		SwarmHost:         driver.SwarmHost,
		openPorts:         driver.OpenPorts,
	}, nil
}

func newComputeUtil ( driver * Driver ) ( * ComputeUtil , error ) { client , err := google . DefaultClient ( oauth2 . NoContext , raw . ComputeScope ) if err != nil { return nil , err } service , err := raw . New ( client ) if err != nil { return nil , err } return & ComputeUtil { zone : driver . Zone , instanceName : driver . MachineName , userName : driver . SSHUser , project : driver . Project , diskTypeURL : driver . DiskType , address : driver . Address , network : driver . Network , subnetwork : driver . Subnetwork , preemptible : driver . Preemptible , useInternalIP : driver . UseInternalIP , useInternalIPOnly : driver . UseInternalIPOnly , service : service , zoneURL : apiURL + driver . Project + " " + driver . Zone , globalURL : apiURL + driver . Project + " " , SwarmMaster : driver . SwarmMaster , SwarmHost : driver . SwarmHost , openPorts : driver . OpenPorts , } , nil }

// NewComputeUtil creates and initializes a ComputeUtil.

NewComputeUtil creates and initializes a ComputeUtil .


func (c *ComputeUtil) disk() (*raw.Disk, error) {
	return c.service.Disks.Get(c.project, c.zone, c.diskName()).Do()
}

func ( c * ComputeUtil ) disk ( ) ( * raw . Disk , error ) { return c . service . Disks . Get ( c . project , c . zone , c . diskName ( ) ) . Do ( ) }

// disk returns the persistent disk attached to the vm.

disk returns the persistent disk attached to the vm .


func (c *ComputeUtil) deleteDisk() error {
	disk, _ := c.disk()
	if disk == nil {
		return nil
	}

	log.Infof("Deleting disk.")
	op, err := c.service.Disks.Delete(c.project, c.zone, c.diskName()).Do()
	if err != nil {
		return err
	}

	log.Infof("Waiting for disk to delete.")
	return c.waitForRegionalOp(op.Name)
}

func ( c * ComputeUtil ) deleteDisk ( ) error { disk , _ := c . disk ( ) if disk == nil { return nil } log . Infof ( " " ) op , err := c . service . Disks . Delete ( c . project , c . zone , c . diskName ( ) ) . Do ( ) if err != nil { return err } log . Infof ( " " ) return c . waitForRegionalOp ( op . Name ) }

// deleteDisk deletes the persistent disk.

deleteDisk deletes the persistent disk .


func (c *ComputeUtil) staticAddress() (string, error) {
	// is the address a name?
	isName, err := regexp.MatchString("[a-z]([-a-z0-9]*[a-z0-9])?", c.address)
	if err != nil {
		return "", err
	}

	if !isName {
		return c.address, nil
	}

	// resolve the address by name
	externalAddress, err := c.service.Addresses.Get(c.project, c.region(), c.address).Do()
	if err != nil {
		return "", err
	}

	return externalAddress.Address, nil
}

func
(
c
*
ComputeUtil
)
staticAddress
(
)
(
string
,
error
)
{
// is the address a name?
isName
,
err
:=
regexp
.
MatchString
(
"
"
,
c
.
address
)
if
err
!=
{
return
"
"
,
err
}
if
!
isName
{
return
c
.
address
,
}
// resolve the address by name
externalAddress
,
err
:=
c
.
service
.
Addresses
.
Get
(
c
.
project
,
c
.
region
(
)
,
c
.
address
)
.
Do
(
)
if
err
!=
{
return
"
"
,
err
}
return
externalAddress
.
Address
,
}

// staticAddress returns the external static IP address.

staticAddress returns the external static IP address .


func (c *ComputeUtil) openFirewallPorts(d *Driver) error {
	log.Infof("Opening firewall ports")

	create := false
	rule, _ := c.firewallRule()
	if rule == nil {
		create = true
		rule = &raw.Firewall{
			Name:         firewallRule,
			Allowed:      []*raw.FirewallAllowed{},
			SourceRanges: []string{"0.0.0.0/0"},
			TargetTags:   []string{firewallTargetTag},
			Network:      c.globalURL + "/networks/" + d.Network,
		}
	}

	portsUsed, err := c.portsUsed()
	if err != nil {
		return err
	}

	missingPorts := missingOpenedPorts(rule, portsUsed)
	if len(missingPorts) == 0 {
		return nil
	}
	for proto, ports := range missingPorts {
		rule.Allowed = append(rule.Allowed, &raw.FirewallAllowed{
			IPProtocol: proto,
			Ports:      ports,
		})
	}

	var op *raw.Operation
	if create {
		op, err = c.service.Firewalls.Insert(c.project, rule).Do()
	} else {
		op, err = c.service.Firewalls.Update(c.project, firewallRule, rule).Do()
	}

	if err != nil {
		return err
	}

	return c.waitForGlobalOp(op.Name)
}

func ( c * ComputeUtil ) openFirewallPorts ( d * Driver ) error { log . Infof ( " " ) create := false rule , _ := c . firewallRule ( ) if rule == nil { create = true rule = & raw . Firewall { Name : firewallRule , Allowed : [ ] * raw . FirewallAllowed { } , SourceRanges : [ ] string { " " } , TargetTags : [ ] string { firewallTargetTag } , Network : c . globalURL + " " + d . Network , } } portsUsed , err := c . portsUsed ( ) if err != nil { return err } missingPorts := missingOpenedPorts ( rule , portsUsed ) if len ( missingPorts ) == 0 { return nil } for proto , ports := range missingPorts { rule . Allowed = append ( rule . Allowed , & raw . FirewallAllowed { IPProtocol : proto , Ports : ports , } ) } var op * raw . Operation if create { op , err = c . service . Firewalls . Insert ( c . project , rule ) . Do ( ) } else { op , err = c . service . Firewalls . Update ( c . project , firewallRule , rule ) . Do ( ) } if err != nil { return err } return c . waitForGlobalOp ( op . Name ) }

// openFirewallPorts configures the firewall to open docker and swarm ports.

openFirewallPorts configures the firewall to open docker and swarm ports .


func (c *ComputeUtil) instance() (*raw.Instance, error) {
	return c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
}

func ( c * ComputeUtil ) instance ( ) ( * raw . Instance , error ) { return c . service . Instances . Get ( c . project , c . zone , c . instanceName ) . Do ( ) }


func (c *ComputeUtil) configureInstance(d *Driver) error {
	log.Infof("Configuring instance")

	instance, err := c.instance()
	if err != nil {
		return err
	}

	if err := c.addFirewallTag(instance); err != nil {
		return err
	}

	return c.uploadSSHKey(instance, d.GetSSHKeyPath())
}

func ( c * ComputeUtil ) configureInstance ( d * Driver ) error { log . Infof ( " " ) instance , err := c . instance ( ) if err != nil { return err } if err := c . addFirewallTag ( instance ) ; err != nil { return err } return c . uploadSSHKey ( instance , d . GetSSHKeyPath ( ) ) }

// configureInstance configures an existing instance for use with Docker Machine.

configureInstance configures an existing instance for use with Docker Machine .


func (c *ComputeUtil) addFirewallTag(instance *raw.Instance) error {
	log.Infof("Adding tag for the firewall rule")

	tags := instance.Tags
	for _, tag := range tags.Items {
		if tag == firewallTargetTag {
			return nil
		}
	}

	tags.Items = append(tags.Items, firewallTargetTag)

	op, err := c.service.Instances.SetTags(c.project, c.zone, instance.Name, tags).Do()
	if err != nil {
		return err
	}

	return c.waitForRegionalOp(op.Name)
}

func ( c * ComputeUtil ) addFirewallTag ( instance * raw . Instance ) error { log . Infof ( " " ) tags := instance . Tags for _ , tag := range tags . Items { if tag == firewallTargetTag { return nil } } tags . Items = append ( tags . Items , firewallTargetTag ) op , err := c . service . Instances . SetTags ( c . project , c . zone , instance . Name , tags ) . Do ( ) if err != nil { return err } return c . waitForRegionalOp ( op . Name ) }

// addFirewallTag adds a tag to the instance to match the firewall rule.

addFirewallTag adds a tag to the instance to match the firewall rule .


func (c *ComputeUtil) uploadSSHKey(instance *raw.Instance, sshKeyPath string) error {
	log.Infof("Uploading SSH Key")

	sshKey, err := ioutil.ReadFile(sshKeyPath + ".pub")
	if err != nil {
		return err
	}

	metaDataValue := fmt.Sprintf("%s:%s %s\n", c.userName, strings.TrimSpace(string(sshKey)), c.userName)

	op, err := c.service.Instances.SetMetadata(c.project, c.zone, c.instanceName, &raw.Metadata{
		Fingerprint: instance.Metadata.Fingerprint,
		Items: []*raw.MetadataItems{
			{
				Key:   "sshKeys",
				Value: &metaDataValue,
			},
		},
	}).Do()

	return c.waitForRegionalOp(op.Name)
}

func ( c * ComputeUtil ) uploadSSHKey ( instance * raw . Instance , sshKeyPath string ) error { log . Infof ( " " ) sshKey , err := ioutil . ReadFile ( sshKeyPath + " " ) if err != nil { return err } metaDataValue := fmt . Sprintf ( " \n " , c . userName , strings . TrimSpace ( string ( sshKey ) ) , c . userName ) op , err := c . service . Instances . SetMetadata ( c . project , c . zone , c . instanceName , & raw . Metadata { Fingerprint : instance . Metadata . Fingerprint , Items : [ ] * raw . MetadataItems { { Key : " " , Value : & metaDataValue , } , } , } ) . Do ( ) return c . waitForRegionalOp ( op . Name ) }

// uploadSSHKey updates the instance metadata with the given ssh key.

uploadSSHKey updates the instance metadata with the given ssh key .


func parseTags(d *Driver) []string {
	tags := []string{firewallTargetTag}

	if d.Tags != "" {
		tags = append(tags, strings.Split(d.Tags, ",")...)
	}

	return tags
}

func parseTags ( d * Driver ) [ ] string { tags := [ ] string { firewallTargetTag } if d . Tags != " " { tags = append ( tags , strings . Split ( d . Tags , " " ) ... ) } return tags }

// parseTags computes the tags for the instance.

parseTags computes the tags for the instance .


func (c *ComputeUtil) startInstance() error {
	op, err := c.service.Instances.Start(c.project, c.zone, c.instanceName).Do()
	if err != nil {
		return err
	}

	log.Infof("Waiting for instance to start.")
	return c.waitForRegionalOp(op.Name)
}

func ( c * ComputeUtil ) startInstance ( ) error { op , err := c . service . Instances . Start ( c . project , c . zone , c . instanceName ) . Do ( ) if err != nil { return err } log . Infof ( " " ) return c . waitForRegionalOp ( op . Name ) }


func (c *ComputeUtil) waitForOp(opGetter func() (*raw.Operation, error)) error {
	for {
		op, err := opGetter()
		if err != nil {
			return err
		}

		log.Debugf("Operation %q status: %s", op.Name, op.Status)
		if op.Status == "DONE" {
			if op.Error != nil {
				return fmt.Errorf("Operation error: %v", *op.Error.Errors[0])
			}
			break
		}
		time.Sleep(1 * time.Second)
	}
	return nil
}

func ( c * ComputeUtil ) waitForOp ( opGetter func ( ) ( * raw . Operation , error ) ) error { for { op , err := opGetter ( ) if err != nil { return err } log . Debugf ( " " , op . Name , op . Status ) if op . Status == " " { if op . Error != nil { return fmt . Errorf ( " " , * op . Error . Errors [ 0 ] ) } break } time . Sleep ( 1 * time . Second ) } return nil }

// waitForOp waits for the operation to finish.

waitForOp waits for the operation to finish .


func (c *ComputeUtil) waitForRegionalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.ZoneOperations.Get(c.project, c.zone, name).Do()
	})
}

func ( c * ComputeUtil ) waitForRegionalOp ( name string ) error { return c . waitForOp ( func ( ) ( * raw . Operation , error ) { return c . service . ZoneOperations . Get ( c . project , c . zone , name ) . Do ( ) } ) }

// waitForRegionalOp waits for the regional operation to finish.

waitForRegionalOp waits for the regional operation to finish .


func (c *ComputeUtil) waitForGlobalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.GlobalOperations.Get(c.project, name).Do()
	})
}

func ( c * ComputeUtil ) waitForGlobalOp ( name string ) error { return c . waitForOp ( func ( ) ( * raw . Operation , error ) { return c . service . GlobalOperations . Get ( c . project , name ) . Do ( ) } ) }

// waitForGlobalOp waits for the global operation to finish.

waitForGlobalOp waits for the global operation to finish .


func (c *ComputeUtil) ip() (string, error) {
	instance, err := c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
	if err != nil {
		return "", unwrapGoogleError(err)
	}

	nic := instance.NetworkInterfaces[0]
	if c.useInternalIP {
		return nic.NetworkIP, nil
	}
	return nic.AccessConfigs[0].NatIP, nil
}

func ( c * ComputeUtil ) ip ( ) ( string , error ) { instance , err := c . service . Instances . Get ( c . project , c . zone , c . instanceName ) . Do ( ) if err != nil { return " " , unwrapGoogleError ( err ) } nic := instance . NetworkInterfaces [ 0 ] if c . useInternalIP { return nic . NetworkIP , nil } return nic . AccessConfigs [ 0 ] . NatIP , nil }

// ip retrieves and returns the external IP address of the instance.

ip retrieves and returns the external IP address of the instance .


func cmdOutput(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)
	log.Debugf("COMMAND: %v %v", name, strings.Join(args, " "))

	stdout, err := cmd.Output()
	if err != nil {
		return "", err
	}

	log.Debugf("STDOUT:\n{\n%v}", string(stdout))

	return string(stdout), nil
}

func cmdOutput ( name string , args ... string ) ( string , error ) { cmd := exec . Command ( name , args ... ) log . Debugf ( " " , name , strings . Join ( args , " " ) ) stdout , err := cmd . Output ( ) if err != nil { return " " , err } log . Debugf ( " \n \n " , string ( stdout ) ) return string ( stdout ) , nil }

// cmdOutput runs a shell command and returns its output.

cmdOutput runs a shell command and returns its output .


func setVmwareCmd(cmd string) string {
	if path, err := exec.LookPath(cmd); err == nil {
		return path
	}
	return filepath.Join("/Applications/VMware Fusion.app/Contents/Library/", cmd)
}

func setVmwareCmd ( cmd string ) string { if path , err := exec . LookPath ( cmd ) ; err == nil { return path } return filepath . Join ( " " , cmd ) }

// detect the vmrun and vmware-vdiskmanager cmds' path if needed

detect the vmrun and vmware - vdiskmanager cmds path if needed


func (a AzureClient) RegisterResourceProviders(namespaces ...string) error {
	l, err := a.providersClient().List(nil, "")
	if err != nil {
		return err
	}
	if l.Value == nil {
		return errors.New("resource providers list is returned as nil")
	}

	m := make(map[string]bool)
	for _, p := range *l.Value {
		m[strings.ToLower(to.String(p.Namespace))] = to.String(p.RegistrationState) == "Registered"
	}

	for _, ns := range namespaces {
		registered, ok := m[strings.ToLower(ns)]
		if !ok {
			return fmt.Errorf("unknown resource provider %q", ns)
		}
		if registered {
			log.Debugf("Already registered for %q", ns)
		} else {
			log.Info("Registering subscription to resource provider.", logutil.Fields{
				"ns":   ns,
				"subs": a.subscriptionID,
			})
			if _, err := a.providersClient().Register(ns); err != nil {
				return err
			}
		}
	}
	return nil
}

func ( a AzureClient ) RegisterResourceProviders ( namespaces ... string ) error { l , err := a . providersClient ( ) . List ( nil , " " ) if err != nil { return err } if l . Value == nil { return errors . New ( " " ) } m := make ( map [ string ] bool ) for _ , p := range * l . Value { m [ strings . ToLower ( to . String ( p . Namespace ) ) ] = to . String ( p . RegistrationState ) == " " } for _ , ns := range namespaces { registered , ok := m [ strings . ToLower ( ns ) ] if ! ok { return fmt . Errorf ( " " , ns ) } if registered { log . Debugf ( " " , ns ) } else { log . Info ( " " , logutil . Fields { " " : ns , " " : a . subscriptionID , } ) if _ , err := a . providersClient ( ) . Register ( ns ) ; err != nil { return err } } } return nil }

// RegisterResourceProviders registers current subscription to the specified
// resource provider namespaces if they are not already registered. Namespaces
// are case-insensitive.

RegisterResourceProviders registers current subscription to the specified resource provider namespaces if they are not already registered . Namespaces are case - insensitive .


func (a AzureClient) CreateResourceGroup(name, location string) error {
	if ok, err := a.resourceGroupExists(name); err != nil {
		return err
	} else if ok {
		log.Infof("Resource group %q already exists.", name)
		return nil
	}

	log.Info("Creating resource group.", logutil.Fields{
		"name":     name,
		"location": location})
	_, err := a.resourceGroupsClient().CreateOrUpdate(name,
		resources.ResourceGroup{
			Location: to.StringPtr(location),
		})
	return err
}

func ( a AzureClient ) CreateResourceGroup ( name , location string ) error { if ok , err := a . resourceGroupExists ( name ) ; err != nil { return err } else if ok { log . Infof ( " " , name ) return nil } log . Info ( " " , logutil . Fields { " " : name , " " : location } ) _ , err := a . resourceGroupsClient ( ) . CreateOrUpdate ( name , resources . ResourceGroup { Location : to . StringPtr ( location ) , } ) return err }

// CreateResourceGroup creates a Resource Group if not exists


func (a AzureClient) CleanupVirtualNetworkIfExists(resourceGroup, name string) error {
	return a.cleanupResourceIfExists(&vnetCleanup{rg: resourceGroup, name: name})
}

func ( a AzureClient ) CleanupVirtualNetworkIfExists ( resourceGroup , name string ) error { return a . cleanupResourceIfExists ( & vnetCleanup { rg : resourceGroup , name : name } ) }

// CleanupVirtualNetworkIfExists removes a subnet if there are no subnets
// attached to it. Note that this method is not safe for multiple concurrent
// writers, in case of races, deployment of a machine could fail or resource
// might not be cleaned up.

CleanupVirtualNetworkIfExists removes a subnet if there are no subnets attached to it . Note that this method is not safe for multiple concurrent writers in case of races deployment of a machine could fail or resource might not be cleaned up .


func (a AzureClient) CreateSubnet(ctx *DeploymentContext, resourceGroup, virtualNetwork, name, subnetPrefix string) error {
	subnet, err := a.GetSubnet(resourceGroup, virtualNetwork, name)
	if err == nil {
		log.Info("Subnet already exists.")
		ctx.SubnetID = to.String(subnet.ID)
		return err
	}

	// If the subnet is not found, create it
	if err.(autorest.DetailedError).StatusCode == 404 {
		log.Info("Configuring subnet.", logutil.Fields{
			"name": name,
			"vnet": virtualNetwork,
			"cidr": subnetPrefix})
		_, err = a.subnetsClient().CreateOrUpdate(resourceGroup, virtualNetwork, name,
			network.Subnet{
				Properties: &network.SubnetPropertiesFormat{
					AddressPrefix: to.StringPtr(subnetPrefix),
				},
			}, nil)

		if err != nil {
			return err
		}

		subnet, err = a.subnetsClient().Get(resourceGroup, virtualNetwork, name, "")
		ctx.SubnetID = to.String(subnet.ID)
		return err
	}

	log.Warn("Create subnet operation error %v: ", err)
	return err

}

// CreateSubnet creates or updates a subnet if it does not already exist.

CreateSubnet creates or updates a subnet if it does not already exist .


func (a AzureClient) CleanupAvailabilitySetIfExists(resourceGroup, name string) error {
	return a.cleanupResourceIfExists(&avSetCleanup{rg: resourceGroup, name: name})
}

func ( a AzureClient ) CleanupAvailabilitySetIfExists ( resourceGroup , name string ) error { return a . cleanupResourceIfExists ( & avSetCleanup { rg : resourceGroup , name : name } ) }

// CleanupAvailabilitySetIfExists removes an availability set if there are no
// virtual machines attached to it. Note that this method is not safe for
// multiple concurrent writers, in case of races, deployment of a machine could
// fail or resource might not be cleaned up.

CleanupAvailabilitySetIfExists removes an availability set if there are no virtual machines attached to it . Note that this method is not safe for multiple concurrent writers in case of races deployment of a machine could fail or resource might not be cleaned up .


func (a AzureClient) GetPublicIPAddress(resourceGroup, name string, useFqdn bool) (string, error) {
	f := logutil.Fields{"name": name}
	log.Debug("Querying public IP address.", f)
	ip, err := a.publicIPAddressClient().Get(resourceGroup, name, "")
	if err != nil {
		return "", err
	}
	if ip.Properties == nil {
		log.Debug("publicIP.Properties is nil. Could not determine IP address", f)
		return "", nil
	}

	if useFqdn { // return FQDN value on public IP
		log.Debug("Will attempt to return FQDN.", f)
		if ip.Properties.DNSSettings == nil || ip.Properties.DNSSettings.Fqdn == nil {
			return "", errors.New("FQDN not found on public IP address")
		}
		return to.String(ip.Properties.DNSSettings.Fqdn), nil
	}
	return to.String(ip.Properties.IPAddress), nil
}

func
(
a
AzureClient
)
GetPublicIPAddress
(
resourceGroup
,
name
string
,
useFqdn
bool
)
(
string
,
error
)
{
f
:=
logutil
.
Fields
{
"
"
:
name
}
log
.
Debug
(
"
"
,
f
)
ip
,
err
:=
a
.
publicIPAddressClient
(
)
.
Get
(
resourceGroup
,
name
,
"
"
)
if
err
!=
{
return
"
"
,
err
}
if
ip
.
Properties
==
{
log
.
Debug
(
"
"
,
f
)
return
"
"
,
}
if
useFqdn
{
// return FQDN value on public IP
log
.
Debug
(
"
"
,
f
)
if
ip
.
Properties
.
DNSSettings
==
||
ip
.
Properties
.
DNSSettings
.
Fqdn
==
{
return
"
"
,
errors
.
New
(
"
"
)
}
return
to
.
String
(
ip
.
Properties
.
DNSSettings
.
Fqdn
)
,
}
return
to
.
String
(
ip
.
Properties
.
IPAddress
)
,
}

// GetPublicIPAddress attempts to get public IP address from the Public IP
// resource. If IP address is not allocated yet, returns empty string. If
// useFqdn is set to true, the a FQDN hostname will be returned.

GetPublicIPAddress attempts to get public IP address from the Public IP resource . If IP address is not allocated yet returns empty string . If useFqdn is set to true the a FQDN hostname will be returned .


func (a AzureClient) GetPrivateIPAddress(resourceGroup, name string) (string, error) {
	f := logutil.Fields{"name": name}
	log.Debug("Querying network interface.", f)
	nic, err := a.networkInterfacesClient().Get(resourceGroup, name, "")
	if err != nil {
		return "", err
	}
	if nic.Properties == nil || nic.Properties.IPConfigurations == nil ||
		len(*nic.Properties.IPConfigurations) == 0 {
		log.Debug("No IPConfigurations found on NIC", f)
		return "", nil
	}
	return to.String((*nic.Properties.IPConfigurations)[0].Properties.PrivateIPAddress), nil
}

func ( a AzureClient ) GetPrivateIPAddress ( resourceGroup , name string ) ( string , error ) { f := logutil . Fields { " " : name } log . Debug ( " " , f ) nic , err := a . networkInterfacesClient ( ) . Get ( resourceGroup , name , " " ) if err != nil { return " " , err } if nic . Properties == nil || nic . Properties . IPConfigurations == nil || len ( * nic . Properties . IPConfigurations ) == 0 { log . Debug ( " " , f ) return " " , nil } return to . String ( ( * nic . Properties . IPConfigurations ) [ 0 ] . Properties . PrivateIPAddress ) , nil }

// GetPrivateIPAddress attempts to retrieve private IP address of the specified
// network interface name.  If IP address is not allocated yet, returns empty
// string.

GetPrivateIPAddress attempts to retrieve private IP address of the specified network interface name . If IP address is not allocated yet returns empty string .


func deleteResourceIfExists(resourceType, name string, getFunc func() error, deleteFunc func() (autorest.Response, error)) error {
	f := logutil.Fields{"name": name}
	log.Debug(fmt.Sprintf("Querying if %s exists.", resourceType), f)
	if exists, err := checkResourceExistsFromError(getFunc()); err != nil {
		return err
	} else if !exists {
		log.Info(fmt.Sprintf("%s does not exist. Skipping.", resourceType), f)
		return nil
	}
	log.Info(fmt.Sprintf("Removing %s resource.", resourceType), f)
	_, err := deleteFunc()
	return err
}

func deleteResourceIfExists ( resourceType , name string , getFunc func ( ) error , deleteFunc func ( ) ( autorest . Response , error ) ) error { f := logutil . Fields { " " : name } log . Debug ( fmt . Sprintf ( " " , resourceType ) , f ) if exists , err := checkResourceExistsFromError ( getFunc ( ) ) ; err != nil { return err } else if ! exists { log . Info ( fmt . Sprintf ( " " , resourceType ) , f ) return nil } log . Info ( fmt . Sprintf ( " " , resourceType ) , f ) _ , err := deleteFunc ( ) return err }

// deleteResourceIfExists is an utility method to determine if a resource exists
// from the error returned from its Get response. If so, deletes it. name is
// used only for logging purposes.

deleteResourceIfExists is an utility method to determine if a resource exists from the error returned from its Get response . If so deletes it . name is used only for logging purposes .


func (a AzureClient) waitVMPowerState(resourceGroup, name string, goalState VMPowerState, timeout time.Duration) error {
	// NOTE(ahmetalpbalkan): Azure APIs for Start and Stop are actually async
	// operations on which our SDK blocks and does polling until the operation
	// is complete.
	//
	// By the time the issued power cycle operation is complete, the VM will be
	// already in the goal PowerState. Hence, this method will return in the
	// first check, however there is no harm in being defensive.
	log.Debug("Waiting until VM reaches goal power state.", logutil.Fields{
		"vm":        name,
		"goalState": goalState,
		"timeout":   timeout,
	})

	chErr := make(chan error)
	go func(ch chan error) {
		for {
			select {
			case <-ch:
				// channel closed
				return
			default:
				state, err := a.GetVirtualMachinePowerState(resourceGroup, name)
				if err != nil {
					ch <- err
					return
				}
				if state != goalState {
					log.Debug(fmt.Sprintf("Waiting %v...", powerStatePollingInterval),
						logutil.Fields{
							"goalState": goalState,
							"state":     state,
						})
					time.Sleep(powerStatePollingInterval)
				} else {
					log.Debug("Reached goal power state.",
						logutil.Fields{"state": state})
					ch <- nil
					return
				}
			}
		}
	}(chErr)

	select {
	case <-time.After(timeout):
		close(chErr)
		return fmt.Errorf("Waiting for goal state %q timed out after %v", goalState, timeout)
	case err := <-chErr:
		return err
	}
}

// waitVMPowerState polls the Virtual Machine instance view until it reaches the
// specified goal power state or times out. If checking for virtual machine
// state fails or waiting times out, an error is returned.

waitVMPowerState polls the Virtual Machine instance view until it reaches the specified goal power state or times out . If checking for virtual machine state fails or waiting times out an error is returned .


func checkResourceExistsFromError(err error) (bool, error) {
	if err == nil {
		return true, nil
	}
	v, ok := err.(autorest.DetailedError)
	if ok && v.StatusCode == http.StatusNotFound {
		return false, nil
	}
	return false, v
}

func checkResourceExistsFromError ( err error ) ( bool , error ) { if err == nil { return true , nil } v , ok := err . ( autorest . DetailedError ) if ok && v . StatusCode == http . StatusNotFound { return false , nil } return false , v }

// checkExistsFromError inspects an error and returns a true if err is nil,
// false if error is an autorest.Error with StatusCode=404 and will return the
// error back if error is another status code or another type of error.

checkExistsFromError inspects an error and returns a true if err is nil false if error is an autorest . Error with StatusCode = 404 and will return the error back if error is another status code or another type of error .


func osDiskStorageBlobURL(account *storage.AccountProperties, vmName string) string {
	containerURL := osDiskStorageContainerURL(account, vmName) // has trailing slash
	blobName := fmt.Sprintf(fmtOSDiskBlobName, vmName)
	return containerURL + blobName
}

func
osDiskStorageBlobURL
(
account
*
storage
.
AccountProperties
,
vmName
string
)
string
{
containerURL
:=
osDiskStorageContainerURL
(
account
,
vmName
)
// has trailing slash
blobName
:=
fmt
.
Sprintf
(
fmtOSDiskBlobName
,
vmName
)
return
containerURL
+
blobName
}

// osDiskStorageBlobURL gives the full url of the VHD blob where the OS disk for
// the given VM should be stored.

osDiskStorageBlobURL gives the full url of the VHD blob where the OS disk for the given VM should be stored .


func osDiskStorageContainerURL(account *storage.AccountProperties, vmName string) string {
	return fmt.Sprintf("%s%s/", to.String(account.PrimaryEndpoints.Blob), osDiskStorageContainerName(vmName))
}

func osDiskStorageContainerURL ( account * storage . AccountProperties , vmName string ) string { return fmt . Sprintf ( " " , to . String ( account . PrimaryEndpoints . Blob ) , osDiskStorageContainerName ( vmName ) ) }

// osDiskStorageContainerURL crafts a URL with a trailing slash pointing
// to the full Azure Blob Container URL for given VM name.

osDiskStorageContainerURL crafts a URL with a trailing slash pointing to the full Azure Blob Container URL for given VM name .


func NewKeyPair() (keyPair *KeyPair, err error) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, ErrKeyGeneration
	}

	if err := priv.Validate(); err != nil {
		return nil, ErrValidation
	}

	privDer := x509.MarshalPKCS1PrivateKey(priv)

	pubSSH, err := gossh.NewPublicKey(&priv.PublicKey)
	if err != nil {
		return nil, ErrPublicKey
	}

	return &KeyPair{
		PrivateKey: privDer,
		PublicKey:  gossh.MarshalAuthorizedKey(pubSSH),
	}, nil
}

func NewKeyPair ( ) ( keyPair * KeyPair , err error ) { priv , err := rsa . GenerateKey ( rand . Reader , 2048 ) if err != nil { return nil , ErrKeyGeneration } if err := priv . Validate ( ) ; err != nil { return nil , ErrValidation } privDer := x509 . MarshalPKCS1PrivateKey ( priv ) pubSSH , err := gossh . NewPublicKey ( & priv . PublicKey ) if err != nil { return nil , ErrPublicKey } return & KeyPair { PrivateKey : privDer , PublicKey : gossh . MarshalAuthorizedKey ( pubSSH ) , } , nil }

// NewKeyPair generates a new SSH keypair
// This will return a private & public key encoded as DER.

NewKeyPair generates a new SSH keypair This will return a private & public key encoded as DER .


func (kp *KeyPair) Fingerprint() string {
	b, _ := base64.StdEncoding.DecodeString(string(kp.PublicKey))
	h := md5.New()

	io.WriteString(h, string(b))

	return fmt.Sprintf("%x", h.Sum(nil))
}

func ( kp * KeyPair ) Fingerprint ( ) string { b , _ := base64 . StdEncoding . DecodeString ( string ( kp . PublicKey ) ) h := md5 . New ( ) io . WriteString ( h , string ( b ) ) return fmt . Sprintf ( " " , h . Sum ( nil ) ) }

// Fingerprint calculates the fingerprint of the public key


func GenerateSSHKey(path string) error {
	if _, err := os.Stat(path); err != nil {
		if !os.IsNotExist(err) {
			return fmt.Errorf("Desired directory for SSH keys does not exist: %s", err)
		}

		kp, err := NewKeyPair()
		if err != nil {
			return fmt.Errorf("Error generating key pair: %s", err)
		}

		if err := kp.WriteToFile(path, fmt.Sprintf("%s.pub", path)); err != nil {
			return fmt.Errorf("Error writing keys to file(s): %s", err)
		}
	}

	return nil
}

func GenerateSSHKey ( path string ) error { if _ , err := os . Stat ( path ) ; err != nil { if ! os . IsNotExist ( err ) { return fmt . Errorf ( " " , err ) } kp , err := NewKeyPair ( ) if err != nil { return fmt . Errorf ( " " , err ) } if err := kp . WriteToFile ( path , fmt . Sprintf ( " " , path ) ) ; err != nil { return fmt . Errorf ( " " , err ) } } return nil }

// GenerateSSHKey generates SSH keypair based on path of the private key
// The public key would be generated to the same path with ".pub" added

GenerateSSHKey generates SSH keypair based on path of the private key The public key would be generated to the same path with . pub added


func loadOrFindTenantID(env azure.Environment, subscriptionID string) (string, error) {
	var tenantID string

	log.Debug("Looking up AAD Tenant ID.", logutil.Fields{
		"subs": subscriptionID})

	// Load from cache
	fp := tenantIDPath(subscriptionID)
	b, err := ioutil.ReadFile(fp)
	if err == nil {
		tenantID = strings.TrimSpace(string(b))
		log.Debugf("Tenant ID loaded from file: %s", fp)
	} else if os.IsNotExist(err) {
		log.Debugf("Tenant ID file not found: %s", fp)
	} else {
		return "", fmt.Errorf("Failed to load tenant ID file: %v", err)
	}

	// Handle cache miss
	if tenantID == "" {
		log.Debug("Making API call to find tenant ID")
		t, err := findTenantID(env, subscriptionID)
		if err != nil {
			return "", err
		}
		tenantID = t

		// Cache the result
		if err := saveTenantID(fp, tenantID); err != nil {
			return "", fmt.Errorf("Failed to save tenant ID: %v", err)
		}
		log.Debugf("Cached tenant ID to file: %s", fp)
	}
	log.Debug("Found AAD Tenant ID.", logutil.Fields{
		"tenant": tenantID,
		"subs":   subscriptionID})
	return tenantID, nil
}

func
loadOrFindTenantID
(
env
azure
.
Environment
,
subscriptionID
string
)
(
string
,
error
)
{
var
tenantID
string
log
.
Debug
(
"
"
,
logutil
.
Fields
{
"
"
:
subscriptionID
}
)
// Load from cache
fp
:=
tenantIDPath
(
subscriptionID
)
b
,
err
:=
ioutil
.
ReadFile
(
fp
)
if
err
==
{
tenantID
=
strings
.
TrimSpace
(
string
(
b
)
)
log
.
Debugf
(
"
"
,
fp
)
}
else
if
os
.
IsNotExist
(
err
)
{
log
.
Debugf
(
"
"
,
fp
)
}
else
{
return
"
"
,
fmt
.
Errorf
(
"
"
,
err
)
}
// Handle cache miss
if
tenantID
==
"
"
{
log
.
Debug
(
"
"
)
t
,
err
:=
findTenantID
(
env
,
subscriptionID
)
if
err
!=
{
return
"
"
,
err
}
tenantID
=
t
// Cache the result
if
err
:=
saveTenantID
(
fp
,
tenantID
)
;
err
!=
{
return
"
"
,
fmt
.
Errorf
(
"
"
,
err
)
}
log
.
Debugf
(
"
"
,
fp
)
}
log
.
Debug
(
"
"
,
logutil
.
Fields
{
"
"
:
tenantID
,
"
"
:
subscriptionID
}
)
return
tenantID
,
}

// loadOrFindTenantID figures out the AAD tenant ID of the subscription by first
// looking at the cache file, if not exists, makes a network call to load it and
// cache it for future use.

loadOrFindTenantID figures out the AAD tenant ID of the subscription by first looking at the cache file if not exists makes a network call to load it and cache it for future use .


func findTenantID(env azure.Environment, subscriptionID string) (string, error) {
	const hdrKey = "WWW-Authenticate"
	c := subscriptionsClient(env.ResourceManagerEndpoint)

	// we expect this request to fail (err != nil), but we are only interested
	// in headers, so surface the error if the Response is not present (i.e.
	// network error etc)
	subs, err := c.Get(subscriptionID)
	if subs.Response.Response == nil {
		return "", fmt.Errorf("Request failed: %v", err)
	}

	// Expecting 401 StatusUnauthorized here, just read the header
	if subs.StatusCode != http.StatusUnauthorized {
		return "", fmt.Errorf("Unexpected response from Get Subscription: %v", err)
	}
	hdr := subs.Header.Get(hdrKey)
	if hdr == "" {
		return "", fmt.Errorf("Header %v not found in Get Subscription response", hdrKey)
	}

	// Example value for hdr:
	//   Bearer authorization_uri="https://login.windows.net/996fe9d1-6171-40aa-945b-4c64b63bf655", error="invalid_token", error_description="The authentication failed because of missing 'Authorization' header."
	r := regexp.MustCompile(`authorization_uri=".*/([0-9a-f\-]+)"`)
	m := r.FindStringSubmatch(hdr)
	if m == nil {
		return "", fmt.Errorf("Could not find the tenant ID in header: %s %q", hdrKey, hdr)
	}
	return m[1], nil
}

// findTenantID figures out the AAD tenant ID of the subscription by making an
// unauthenticated request to the Get Subscription Details endpoint and parses
// the value from WWW-Authenticate header.

findTenantID figures out the AAD tenant ID of the subscription by making an unauthenticated request to the Get Subscription Details endpoint and parses the value from WWW - Authenticate header .


func saveTenantID(path string, tenantID string) error {
	var perm os.FileMode = 0600

	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
		return fmt.Errorf("Failed to create directory %s: %v", dir, err)
	}

	f, err := ioutil.TempFile(dir, "tenantid")
	if err != nil {
		return fmt.Errorf("Failed to create temp file: %v", err)
	}
	defer f.Close()

	fp := f.Name()
	if _, err := f.Write([]byte(tenantID)); err != nil {
		return fmt.Errorf("Failed to write tenant ID to file: %v", err)
	}
	f.Close()

	// atomic move by rename
	if err := os.Rename(fp, path); err != nil {
		return fmt.Errorf("Failed to rename file. src=%s dst=%s error=%v", fp, path, err)
	}
	if err := os.Chmod(path, perm); err != nil {
		return fmt.Errorf("Failed to chmod the file %s: %v", path, err)
	}
	return nil
}

func
saveTenantID
(
path
string
,
tenantID
string
)
error
{
var
perm
os
.
FileMode
=
0600
dir
:=
filepath
.
Dir
(
path
)
if
err
:=
os
.
MkdirAll
(
dir
,
os
.
ModePerm
)
;
err
!=
{
return
fmt
.
Errorf
(
"
"
,
dir
,
err
)
}
f
,
err
:=
ioutil
.
TempFile
(
dir
,
"
"
)
if
err
!=
{
return
fmt
.
Errorf
(
"
"
,
err
)
}
defer
f
.
Close
(
)
fp
:=
f
.
Name
(
)
if
_
,
err
:=
f
.
Write
(
[
]
byte
(
tenantID
)
)
;
err
!=
{
return
fmt
.
Errorf
(
"
"
,
err
)
}
f
.
Close
(
)
// atomic move by rename
if
err
:=
os
.
Rename
(
fp
,
path
)
;
err
!=
{
return
fmt
.
Errorf
(
"
"
,
fp
,
path
,
err
)
}
if
err
:=
os
.
Chmod
(
path
,
perm
)
;
err
!=
{
return
fmt
.
Errorf
(
"
"
,
path
,
err
)
}
return
}

// saveTenantID performs an atomic write to the path with given tenantID contents.

saveTenantID performs an atomic write to the path with given tenantID contents .


func (r *BugsnagCrashReporter) Send(err CrashError) error {
	if r.noReportFileExist() || r.apiKey == noreportAPIKey {
		log.Debug("Opting out of crash reporting.")
		return nil
	}

	if r.apiKey == "" {
		return errors.New("no api key has been set")
	}

	bugsnag.Configure(bugsnag.Configuration{
		APIKey: r.apiKey,
		// XXX we need to abuse bugsnag metrics to get the OS/ARCH information as a usable filter
		// Can do that with either "stage" or "hostname"
		ReleaseStage:    fmt.Sprintf("%s (%s)", runtime.GOOS, runtime.GOARCH),
		ProjectPackages: []string{"github.com/docker/machine/[^v]*"},
		AppVersion:      version.FullVersion(),
		Synchronous:     true,
		PanicHandler:    func() {},
		Logger:          new(logger),
	})

	metaData := bugsnag.MetaData{}

	metaData.Add("app", "compiler", fmt.Sprintf("%s (%s)", runtime.Compiler, runtime.Version()))
	metaData.Add("device", "os", runtime.GOOS)
	metaData.Add("device", "arch", runtime.GOARCH)

	detectRunningShell(&metaData)
	detectUname(&metaData)
	detectOSVersion(&metaData)
	addFile(err.LogFilePath, &metaData)

	var buffer bytes.Buffer
	for _, message := range log.History() {
		buffer.WriteString(message + "\n")
	}
	metaData.Add("history", "trace", buffer.String())

	return bugsnag.Notify(err.Cause, metaData, bugsnag.SeverityError, bugsnag.Context{String: err.Context}, bugsnag.ErrorClass{Name: fmt.Sprintf("%s/%s", err.DriverName, err.Command)})
}

// Send sends a crash report to bugsnag via an http call.

Send sends a crash report to bugsnag via an http call .


func (d *SerialDriver) Create() error {
	d.Lock()
	defer d.Unlock()
	return d.Driver.Create()
}

func ( d * SerialDriver ) Create ( ) error { d . Lock ( ) defer d . Unlock ( ) return d . Driver . Create ( ) }

// Create a host using the driver's config


func (d *SerialDriver) DriverName() string {
	d.Lock()
	defer d.Unlock()
	return d.Driver.DriverName()
}

func ( d * SerialDriver ) DriverName ( ) string { d . Lock ( ) defer d . Unlock ( ) return d . Driver . DriverName ( ) }

// DriverName returns the name of the driver as it is registered


func (d *SerialDriver) GetCreateFlags() []mcnflag.Flag {
	d.Lock()
	defer d.Unlock()
	return d.Driver.GetCreateFlags()
}

func ( d * SerialDriver ) GetCreateFlags ( ) [ ] mcnflag . Flag { d . Lock ( ) defer d . Unlock ( ) return d . Driver . GetCreateFlags ( ) }

// GetCreateFlags returns the mcnflag.Flag slice representing the flags
// that can be set, their descriptions and defaults.

GetCreateFlags returns the mcnflag . Flag slice representing the flags that can be set their descriptions and defaults .


func (d *SerialDriver) GetMachineName() string {
	d.Lock()
	defer d.Unlock()
	return d.Driver.GetMachineName()
}

func ( d * SerialDriver ) GetMachineName ( ) string { d . Lock ( ) defer d . Unlock ( ) return d . Driver . GetMachineName ( ) }

// GetMachineName returns the name of the machine


func (d *SerialDriver) GetSSHHostname() (string, error) {
	d.Lock()
	defer d.Unlock()
	return d.Driver.GetSSHHostname()
}

func ( d * SerialDriver ) GetSSHHostname ( ) ( string , error ) { d . Lock ( ) defer d . Unlock ( ) return d . Driver . GetSSHHostname ( ) }

// GetSSHHostname returns hostname for use with ssh


func (d *SerialDriver) GetSSHKeyPath() string {
	d.Lock()
	defer d.Unlock()
	return d.Driver.GetSSHKeyPath()
}

func ( d * SerialDriver ) GetSSHKeyPath ( ) string { d . Lock ( ) defer d . Unlock ( ) return d . Driver . GetSSHKeyPath ( ) }

// GetSSHKeyPath returns key path for use with ssh


func (d *SerialDriver) GetSSHUsername() string {
	d.Lock()
	defer d.Unlock()
	return d.Driver.GetSSHUsername()
}

func ( d * SerialDriver ) GetSSHUsername ( ) string { d . Lock ( ) defer d . Unlock ( ) return d . Driver . GetSSHUsername ( ) }

// GetSSHUsername returns username for use with ssh


func (d *SerialDriver) Kill() error {
	d.Lock()
	defer d.Unlock()
	return d.Driver.Kill()
}

func ( d * SerialDriver ) Kill ( ) error { d . Lock ( ) defer d . Unlock ( ) return d . Driver . Kill ( ) }


func (d *SerialDriver) Remove() error {
	d.Lock()
	defer d.Unlock()
	return d.Driver.Remove()
}

func ( d * SerialDriver ) Remove ( ) error { d . Lock ( ) defer d . Unlock ( ) return d . Driver . Remove ( ) }


func (d *SerialDriver) Start() error {
	d.Lock()
	defer d.Unlock()
	return d.Driver.Start()
}

func ( d * SerialDriver ) Start ( ) error { d . Lock ( ) defer d . Unlock ( ) return d . Driver . Start ( ) }


func (d *SerialDriver) Stop() error {
	d.Lock()
	defer d.Unlock()
	return d.Driver.Stop()
}

func ( d * SerialDriver ) Stop ( ) error { d . Lock ( ) defer d . Unlock ( ) return d . Driver . Stop ( ) }


func MigrateHostV0ToHostV1(hostV0 *V0) *V1 {
	hostV1 := &V1{
		Driver:     hostV0.Driver,
		DriverName: hostV0.DriverName,
	}

	hostV1.HostOptions = &OptionsV1{}
	hostV1.HostOptions.EngineOptions = &engine.Options{
		TLSVerify:  true,
		InstallURL: "https://get.docker.com",
	}
	hostV1.HostOptions.SwarmOptions = &swarm.Options{
		Address:   "",
		Discovery: hostV0.SwarmDiscovery,
		Host:      hostV0.SwarmHost,
		Master:    hostV0.SwarmMaster,
	}
	hostV1.HostOptions.AuthOptions = &AuthOptionsV1{
		StorePath:            hostV0.StorePath,
		CaCertPath:           hostV0.CaCertPath,
		CaCertRemotePath:     "",
		ServerCertPath:       hostV0.ServerCertPath,
		ServerKeyPath:        hostV0.ServerKeyPath,
		ClientKeyPath:        hostV0.ClientKeyPath,
		ServerCertRemotePath: "",
		ServerKeyRemotePath:  "",
		PrivateKeyPath:       hostV0.PrivateKeyPath,
		ClientCertPath:       hostV0.ClientCertPath,
	}

	return hostV1
}

func MigrateHostV0ToHostV1 ( hostV0 * V0 ) * V1 { hostV1 := & V1 { Driver : hostV0 . Driver , DriverName : hostV0 . DriverName , } hostV1 . HostOptions = & OptionsV1 { } hostV1 . HostOptions . EngineOptions = & engine . Options { TLSVerify : true , InstallURL : " " , } hostV1 . HostOptions . SwarmOptions = & swarm . Options { Address : " " , Discovery : hostV0 . SwarmDiscovery , Host : hostV0 . SwarmHost , Master : hostV0 . SwarmMaster , } hostV1 . HostOptions . AuthOptions = & AuthOptionsV1 { StorePath : hostV0 . StorePath , CaCertPath : hostV0 . CaCertPath , CaCertRemotePath : " " , ServerCertPath : hostV0 . ServerCertPath , ServerKeyPath : hostV0 . ServerKeyPath , ClientKeyPath : hostV0 . ClientKeyPath , ServerCertRemotePath : " " , ServerKeyRemotePath : " " , PrivateKeyPath : hostV0 . PrivateKeyPath , ClientCertPath : hostV0 . ClientCertPath , } return hostV1 }

// In the 0.1.0 => 0.2.0 transition, the JSON representation of
// machines changed from a "flat" to a more "nested" structure
// for various options and configuration settings.  To preserve
// compatibility with existing machines, these migration functions
// have been introduced.  They preserve backwards compat at the expense
// of some duplicated information.
// MigrateHostV0ToHostV1 validates host config and modifies if needed
// this is used for configuration updates

In the 0 . 1 . 0 = > 0 . 2 . 0 transition the JSON representation of machines changed from a flat to a more nested structure for various options and configuration settings . To preserve compatibility with existing machines these migration functions have been introduced . They preserve backwards compat at the expense of some duplicated information . MigrateHostV0ToHostV1 validates host config and modifies if needed this is used for configuration updates


func MigrateHostMetadataV0ToHostMetadataV1(m *MetadataV0) *Metadata {
	hostMetadata := &Metadata{}
	hostMetadata.DriverName = m.DriverName
	hostMetadata.HostOptions.EngineOptions = &engine.Options{}
	hostMetadata.HostOptions.AuthOptions = &auth.Options{
		StorePath:            m.StorePath,
		CaCertPath:           m.CaCertPath,
		CaCertRemotePath:     "",
		ServerCertPath:       m.ServerCertPath,
		ServerKeyPath:        m.ServerKeyPath,
		ClientKeyPath:        "",
		ServerCertRemotePath: "",
		ServerKeyRemotePath:  "",
		CaPrivateKeyPath:     m.PrivateKeyPath,
		ClientCertPath:       m.ClientCertPath,
	}

	hostMetadata.ConfigVersion = m.ConfigVersion

	return hostMetadata
}

func MigrateHostMetadataV0ToHostMetadataV1 ( m * MetadataV0 ) * Metadata { hostMetadata := & Metadata { } hostMetadata . DriverName = m . DriverName hostMetadata . HostOptions . EngineOptions = & engine . Options { } hostMetadata . HostOptions . AuthOptions = & auth . Options { StorePath : m . StorePath , CaCertPath : m . CaCertPath , CaCertRemotePath : " " , ServerCertPath : m . ServerCertPath , ServerKeyPath : m . ServerKeyPath , ClientKeyPath : " " , ServerCertRemotePath : " " , ServerKeyRemotePath : " " , CaPrivateKeyPath : m . PrivateKeyPath , ClientCertPath : m . ClientCertPath , } hostMetadata . ConfigVersion = m . ConfigVersion return hostMetadata }

// MigrateHostMetadataV0ToHostMetadataV1 fills nested host metadata and modifies if needed
// this is used for configuration updates

MigrateHostMetadataV0ToHostMetadataV1 fills nested host metadata and modifies if needed this is used for configuration updates


func getNameAndItsPpid(pid int) (exefile string, parentid int, err error) {
	pe, err := getProcessEntry(pid)
	if err != nil {
		return "", 0, err
	}

	name := syscall.UTF16ToString(pe.ExeFile[:])
	return name, int(pe.ParentProcessID), nil
}

func getNameAndItsPpid ( pid int ) ( exefile string , parentid int , err error ) { pe , err := getProcessEntry ( pid ) if err != nil { return " " , 0 , err } name := syscall . UTF16ToString ( pe . ExeFile [ : ] ) return name , int ( pe . ParentProcessID ) , nil }

// getNameAndItsPpid returns the exe file name its parent process id.

getNameAndItsPpid returns the exe file name its parent process id .


func NewDriver(machineName string, storePath string) *Driver {
	return &Driver{
		Zone:           defaultZone,
		DiskType:       defaultDiskType,
		DiskSize:       defaultDiskSize,
		MachineType:    defaultMachineType,
		MachineImage:   defaultImageName,
		Network:        defaultNetwork,
		Subnetwork:     defaultSubnetwork,
		ServiceAccount: defaultServiceAccount,
		Scopes:         defaultScopes,
		BaseDriver: &drivers.BaseDriver{
			SSHUser:     defaultUser,
			MachineName: machineName,
			StorePath:   storePath,
		},
	}
}

func NewDriver ( machineName string , storePath string ) * Driver { return & Driver { Zone : defaultZone , DiskType : defaultDiskType , DiskSize : defaultDiskSize , MachineType : defaultMachineType , MachineImage : defaultImageName , Network : defaultNetwork , Subnetwork : defaultSubnetwork , ServiceAccount : defaultServiceAccount , Scopes : defaultScopes , BaseDriver : & drivers . BaseDriver { SSHUser : defaultUser , MachineName : machineName , StorePath : storePath , } , } }

// NewDriver creates a Driver with the specified storePath.

NewDriver creates a Driver with the specified storePath .


func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
	d.Project = flags.String("google-project")
	if d.Project == "" {
		return errors.New("no Google Cloud Project name specified (--google-project)")
	}

	d.Zone = flags.String("google-zone")
	d.UseExisting = flags.Bool("google-use-existing")
	if !d.UseExisting {
		d.MachineType = flags.String("google-machine-type")
		d.MachineImage = flags.String("google-machine-image")
		d.MachineImage = strings.TrimPrefix(d.MachineImage, "https://www.googleapis.com/compute/v1/projects/")
		d.DiskSize = flags.Int("google-disk-size")
		d.DiskType = flags.String("google-disk-type")
		d.Address = flags.String("google-address")
		d.Network = flags.String("google-network")
		d.Subnetwork = flags.String("google-subnetwork")
		d.Preemptible = flags.Bool("google-preemptible")
		d.UseInternalIP = flags.Bool("google-use-internal-ip") || flags.Bool("google-use-internal-ip-only")
		d.UseInternalIPOnly = flags.Bool("google-use-internal-ip-only")
		d.ServiceAccount = flags.String("google-service-account")
		d.Scopes = flags.String("google-scopes")
		d.Tags = flags.String("google-tags")
		d.OpenPorts = flags.StringSlice("google-open-port")
	}
	d.SSHUser = flags.String("google-username")
	d.SSHPort = 22
	d.SetSwarmConfigFromFlags(flags)

	return nil
}

func ( d * Driver ) SetConfigFromFlags ( flags drivers . DriverOptions ) error { d . Project = flags . String ( " " ) if d . Project == " " { return errors . New ( " " ) } d . Zone = flags . String ( " " ) d . UseExisting = flags . Bool ( " " ) if ! d . UseExisting { d . MachineType = flags . String ( " " ) d . MachineImage = flags . String ( " " ) d . MachineImage = strings . TrimPrefix ( d . MachineImage , " " ) d . DiskSize = flags . Int ( " " ) d . DiskType = flags . String ( " " ) d . Address = flags . String ( " " ) d . Network = flags . String ( " " ) d . Subnetwork = flags . String ( " " ) d . Preemptible = flags . Bool ( " " ) d . UseInternalIP = flags . Bool ( " " ) || flags . Bool ( " " ) d . UseInternalIPOnly = flags . Bool ( " " ) d . ServiceAccount = flags . String ( " " ) d . Scopes = flags . String ( " " ) d . Tags = flags . String ( " " ) d . OpenPorts = flags . StringSlice ( " " ) } d . SSHUser = flags . String ( " " ) d . SSHPort = 22 d . SetSwarmConfigFromFlags ( flags ) return nil }

// SetConfigFromFlags initializes the driver based on the command line flags.

SetConfigFromFlags initializes the driver based on the command line flags .


func (d *Driver) PreCreateCheck() error {
	c, err := newComputeUtil(d)
	if err != nil {
		return err
	}

	// Check that the project exists. It will also check the credentials
	// at the same time.
	log.Infof("Check that the project exists")

	if _, err = c.service.Projects.Get(d.Project).Do(); err != nil {
		return fmt.Errorf("Project with ID %q not found. %v", d.Project, err)
	}

	// Check if the instance already exists. There will be an error if the instance
	// doesn't exist, so just check instance for nil.
	log.Infof("Check if the instance already exists")

	instance, _ := c.instance()
	if d.UseExisting {
		if instance == nil {
			return fmt.Errorf("unable to find instance %q in zone %q", d.MachineName, d.Zone)
		}
	} else {
		if instance != nil {
			return fmt.Errorf("instance %q already exists in zone %q", d.MachineName, d.Zone)
		}
	}

	return nil
}

// PreCreateCheck is called to enforce pre-creation steps

PreCreateCheck is called to enforce pre - creation steps


func (d *Driver) Create() error {
	log.Infof("Generating SSH Key")

	if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return err
	}

	log.Infof("Creating host...")

	c, err := newComputeUtil(d)
	if err != nil {
		return err
	}

	if err := c.openFirewallPorts(d); err != nil {
		return err
	}

	if d.UseExisting {
		return c.configureInstance(d)
	}
	return c.createInstance(d)
}

func ( d * Driver ) Create ( ) error { log . Infof ( " " ) if err := ssh . GenerateSSHKey ( d . GetSSHKeyPath ( ) ) ; err != nil { return err } log . Infof ( " " ) c , err := newComputeUtil ( d ) if err != nil { return err } if err := c . openFirewallPorts ( d ) ; err != nil { return err } if d . UseExisting { return c . configureInstance ( d ) } return c . createInstance ( d ) }

// Create creates a GCE VM instance acting as a docker host.

Create creates a GCE VM instance acting as a docker host .


func (d *Driver) GetIP() (string, error) {
	c, err := newComputeUtil(d)
	if err != nil {
		return "", err
	}

	ip, err := c.ip()
	if err != nil {
		return "", err
	}
	if ip == "" {
		return "", drivers.ErrHostIsNotRunning
	}

	return ip, nil
}

func ( d * Driver ) GetIP ( ) ( string , error ) { c , err := newComputeUtil ( d ) if err != nil { return " " , err } ip , err := c . ip ( ) if err != nil { return " " , err } if ip == " " { return " " , drivers . ErrHostIsNotRunning } return ip , nil }

// GetIP returns the IP address of the GCE instance.

GetIP returns the IP address of the GCE instance .


func (d *Driver) GetState() (state.State, error) {
	c, err := newComputeUtil(d)
	if err != nil {
		return state.None, err
	}

	// All we care about is whether the disk exists, so we just check disk for a nil value.
	// There will be no error if disk is not nil.
	instance, _ := c.instance()
	if instance == nil {
		disk, _ := c.disk()
		if disk == nil {
			return state.None, nil
		}
		return state.Stopped, nil
	}

	switch instance.Status {
	case "PROVISIONING", "STAGING":
		return state.Starting, nil
	case "RUNNING":
		return state.Running, nil
	case "STOPPING", "STOPPED", "TERMINATED":
		return state.Stopped, nil
	}
	return state.None, nil
}

// GetState returns a docker.hosts.state.State value representing the current state of the host.

GetState returns a docker . hosts . state . State value representing the current state of the host .


func (d *Driver) Start() error {
	c, err := newComputeUtil(d)
	if err != nil {
		return err
	}

	instance, err := c.instance()
	if err != nil {
		if !isNotFound(err) {
			return err
		}
	}

	if instance == nil {
		if err = c.createInstance(d); err != nil {
			return err
		}
	} else {
		if err := c.startInstance(); err != nil {
			return err
		}
	}

	d.IPAddress, err = d.GetIP()
	return err
}

func ( d * Driver ) Start ( ) error { c , err := newComputeUtil ( d ) if err != nil { return err } instance , err := c . instance ( ) if err != nil { if ! isNotFound ( err ) { return err } } if instance == nil { if err = c . createInstance ( d ) ; err != nil { return err } } else { if err := c . startInstance ( ) ; err != nil { return err } } d . IPAddress , err = d . GetIP ( ) return err }

// Start starts an existing GCE instance or create an instance with an existing disk.

Start starts an existing GCE instance or create an instance with an existing disk .


func (d *Driver) Stop() error {
	c, err := newComputeUtil(d)
	if err != nil {
		return err
	}

	if err := c.stopInstance(); err != nil {
		return err
	}

	d.IPAddress = ""
	return nil
}

func ( d * Driver ) Stop ( ) error { c , err := newComputeUtil ( d ) if err != nil { return err } if err := c . stopInstance ( ) ; err != nil { return err } d . IPAddress = " " return nil }


func (d *Driver) Remove() error {
	c, err := newComputeUtil(d)
	if err != nil {
		return err
	}

	if err := c.deleteInstance(); err != nil {
		if isNotFound(err) {
			log.Warn("Remote instance does not exist, proceeding with removing local reference")
		} else {
			return err
		}
	}

	if err := c.deleteDisk(); err != nil {
		if isNotFound(err) {
			log.Warn("Remote disk does not exist, proceeding")
		} else {
			return err
		}
	}

	return nil
}

func ( d * Driver ) Remove ( ) error { c , err := newComputeUtil ( d ) if err != nil { return err } if err := c . deleteInstance ( ) ; err != nil { if isNotFound ( err ) { log . Warn ( " " ) } else { return err } } if err := c . deleteDisk ( ) ; err != nil { if isNotFound ( err ) { log . Warn ( " " ) } else { return err } } return nil }

// Remove deletes the GCE instance and the disk.

Remove deletes the GCE instance and the disk .


func NewDriver(hostName, storePath string) drivers.Driver {
	// NOTE(ahmetalpbalkan): any driver initialization I do here gets lost
	// afterwards, especially for non-Create RPC calls. Therefore I am mostly
	// making rest of the driver stateless by just relying on the following
	// piece of info.
	d := &Driver{
		BaseDriver: &drivers.BaseDriver{
			SSHUser:     defaultSSHUser,
			MachineName: hostName,
			StorePath:   storePath,
		},
	}
	return d
}

// NewDriver returns a new driver instance.

NewDriver returns a new driver instance .


func (d *Driver) SetConfigFromFlags(fl drivers.DriverOptions) error {
	// Initialize driver context for machine
	d.ctx = &azureutil.DeploymentContext{}

	// Required string flags
	flags := []struct {
		target *string
		flag   string
	}{
		{&d.BaseDriver.SSHUser, flAzureSSHUser},
		{&d.SubscriptionID, flAzureSubscriptionID},
		{&d.ResourceGroup, flAzureResourceGroup},
		{&d.Location, flAzureLocation},
		{&d.Size, flAzureSize},
		{&d.Image, flAzureImage},
		{&d.VirtualNetwork, flAzureVNet},
		{&d.SubnetName, flAzureSubnet},
		{&d.SubnetPrefix, flAzureSubnetPrefix},
		{&d.AvailabilitySet, flAzureAvailabilitySet},
		{&d.StorageType, flAzureStorageType},
	}
	for _, f := range flags {
		*f.target = fl.String(f.flag)
		if *f.target == "" {
			return requiredOptionError(f.flag)
		}
	}

	// Optional flags or Flags of other types
	d.Environment = fl.String(flAzureEnvironment)
	d.OpenPorts = fl.StringSlice(flAzurePorts)
	d.PrivateIPAddr = fl.String(flAzurePrivateIPAddr)
	d.UsePrivateIP = fl.Bool(flAzureUsePrivateIP)
	d.NoPublicIP = fl.Bool(flAzureNoPublicIP)
	d.StaticPublicIP = fl.Bool(flAzureStaticPublicIP)
	d.DockerPort = fl.Int(flAzureDockerPort)
	d.DNSLabel = fl.String(flAzureDNSLabel)
	d.CustomDataFile = fl.String(flAzureCustomData)

	d.ClientID = fl.String(flAzureClientID)
	d.ClientSecret = fl.String(flAzureClientSecret)

	// Set flags on the BaseDriver
	d.BaseDriver.SSHPort = sshPort
	d.SetSwarmConfigFromFlags(fl)

	log.Debug("Set configuration from flags.")
	return nil
}

// SetConfigFromFlags initializes driver values from the command line values
// and checks if the arguments have values.

SetConfigFromFlags initializes driver values from the command line values and checks if the arguments have values .


func (d *Driver) PreCreateCheck() (err error) {
	if d.CustomDataFile != "" {
		if _, err := os.Stat(d.CustomDataFile); os.IsNotExist(err) {
			return fmt.Errorf("custom-data file %s could not be found", d.CustomDataFile)
		}
	}

	c, err := d.newAzureClient()
	if err != nil {
		return err
	}

	// Register used resource providers with current Azure subscription.
	if err := c.RegisterResourceProviders(
		"Microsoft.Compute",
		"Microsoft.Network",
		"Microsoft.Storage"); err != nil {
		return err
	}

	// Validate if firewall rules can be read correctly
	d.ctx.FirewallRules, err = d.getSecurityRules(d.OpenPorts)
	if err != nil {
		return err
	}

	// Check if virtual machine exists. An existing virtual machine cannot be updated.
	log.Debug("Checking if Virtual Machine already exists.")
	if exists, err := c.VirtualMachineExists(d.ResourceGroup, d.naming().VM()); err != nil {
		return err
	} else if exists {
		return fmt.Errorf("Virtual Machine with name %s already exists in resource group %q", d.naming().VM(), d.ResourceGroup)
	}

	// NOTE(ahmetalpbalkan) we could have done more checks here but Azure often
	// returns meaningful error messages and it would be repeating the backend
	// logic on the client side. Some examples:
	//   - Deployment of a machine to an existing Virtual Network fails if
	//     virtual network is in a different region.
	//   - Changing IP Address space of a subnet would fail if there are machines
	//     running in the Virtual Network.
	log.Info("Completed machine pre-create checks.")
	return nil
}

// PreCreateCheck validates if driver values are valid to create the machine.

PreCreateCheck validates if driver values are valid to create the machine .