// +build go1.7 // Package vmutils provides convenience methods for creating Virtual // Machine Role configurations. package vmutils // Copyright 2017 Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import ( "fmt" vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine" ) const ( errParamNotSpecified = "Parameter %s is not specified." ) // NewVMConfiguration creates configuration for a new virtual machine Role. func NewVMConfiguration(name string, roleSize string) vm.Role { return vm.Role{ RoleName: name, RoleType: "PersistentVMRole", RoleSize: roleSize, ProvisionGuestAgent: true, } } // ConfigureForLinux adds configuration when deploying a generalized Linux // image. If "password" is left empty, SSH password security will be disabled by // default. Certificates with SSH public keys should already be uploaded to the // cloud service where the VM will be deployed and referenced here only by their // thumbprint. func ConfigureForLinux(role *vm.Role, hostname, user, password string, sshPubkeyCertificateThumbprint ...string) error { if role == nil { return fmt.Errorf(errParamNotSpecified, "role") } role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeLinuxProvisioning, func(config *vm.ConfigurationSet) { config.HostName = hostname config.UserName = user config.UserPassword = password if password != "" { config.DisableSSHPasswordAuthentication = "false" } if len(sshPubkeyCertificateThumbprint) != 0 { config.SSH = &vm.SSH{} for _, k := range sshPubkeyCertificateThumbprint { config.SSH.PublicKeys = append(config.SSH.PublicKeys, vm.PublicKey{ Fingerprint: k, Path: "/home/" + user + "/.ssh/authorized_keys", }, ) } } }, ) return nil } // ConfigureForWindows adds configuration when deploying a generalized // Windows image. timeZone can be left empty. For a complete list of supported // time zone entries, you can either refer to the values listed in the registry // entry "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time // Zones" or you can use the tzutil command-line tool to list the valid time. func ConfigureForWindows(role *vm.Role, hostname, user, password string, enableAutomaticUpdates bool, timeZone string) error { if role == nil { return fmt.Errorf(errParamNotSpecified, "role") } role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning, func(config *vm.ConfigurationSet) { config.ComputerName = hostname config.AdminUsername = user config.AdminPassword = password config.EnableAutomaticUpdates = enableAutomaticUpdates config.TimeZone = timeZone }, ) return nil } // ConfigureWithCustomDataForLinux configures custom data for Linux-based images. // The customData contains either cloud-init or shell script to be executed upon start. // // The function expects the customData to be base64-encoded. func ConfigureWithCustomDataForLinux(role *vm.Role, customData string) error { return configureWithCustomData(role, customData, vm.ConfigurationSetTypeLinuxProvisioning) } // ConfigureWithCustomDataForWindows configures custom data for Windows-based images. // The customData contains either cloud-init or shell script to be executed upon start. // // The function expects the customData to be base64-encoded. func ConfigureWithCustomDataForWindows(role *vm.Role, customData string) error { return configureWithCustomData(role, customData, vm.ConfigurationSetTypeWindowsProvisioning) } func configureWithCustomData(role *vm.Role, customData string, typ vm.ConfigurationSetType) error { if role == nil { return fmt.Errorf(errParamNotSpecified, "role") } role.ConfigurationSets = updateOrAddConfig(role.ConfigurationSets, typ, func(config *vm.ConfigurationSet) { config.CustomData = customData }) return nil } // ConfigureWindowsToJoinDomain adds configuration to join a new Windows vm to a // domain. "username" must be in UPN form (user@domain.com), "machineOU" can be // left empty func ConfigureWindowsToJoinDomain(role *vm.Role, username, password, domainToJoin, machineOU string) error { if role == nil { return fmt.Errorf(errParamNotSpecified, "role") } winconfig := findConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning) if winconfig != nil { winconfig.DomainJoin = &vm.DomainJoin{ Credentials: vm.Credentials{Username: username, Password: password}, JoinDomain: domainToJoin, MachineObjectOU: machineOU, } } return nil } func ConfigureWinRMListener(role *vm.Role, protocol vm.WinRMProtocol, certificateThumbprint string) error { if role == nil { return fmt.Errorf(errParamNotSpecified, "role") } winconfig := findConfig(role.ConfigurationSets, vm.ConfigurationSetTypeWindowsProvisioning) if winconfig != nil { listener := vm.WinRMListener{ Protocol: protocol, CertificateThumbprint: certificateThumbprint, } if winconfig.WinRMListeners == nil { winconfig.WinRMListeners = &[]vm.WinRMListener{} } currentListeners := *winconfig.WinRMListeners // replace existing listener if it's already configured for i, existingListener := range currentListeners { if existingListener.Protocol == protocol { currentListeners[i] = listener return nil } } // otherwise append to list of listeners newListeners := append(currentListeners, listener) winconfig.WinRMListeners = &newListeners return nil } return fmt.Errorf("WindowsProvisioningConfigurationSet not found in 'role'") } func ConfigureWinRMOverHTTP(role *vm.Role) error { return ConfigureWinRMListener(role, vm.WinRMProtocolHTTP, "") } func ConfigureWinRMOverHTTPS(role *vm.Role, certificateThumbprint string) error { return ConfigureWinRMListener(role, vm.WinRMProtocolHTTPS, certificateThumbprint) }