mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
Merge pull request #577 from ioito/hotfix/qx-azure-rebuild-root
Azure重装系统支持初始化密码
This commit is contained in:
@@ -186,7 +186,8 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
|
||||
}
|
||||
|
||||
const (
|
||||
VM_AWS_DEFAULT_LOGIN_USER = "ec2user"
|
||||
VM_AWS_DEFAULT_LOGIN_USER = "ec2user"
|
||||
VM_AZURE_DEFAULT_LOGIN_USER = "toor"
|
||||
|
||||
VM_METADATA_APP_TAGS = "app_tags"
|
||||
VM_METADATA_CREATE_PARAMS = "create_params"
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/ansible"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
)
|
||||
|
||||
@@ -142,7 +141,7 @@ func (self *SAzureGuestDriver) GetGuestInitialStateAfterRebuild() string {
|
||||
}
|
||||
|
||||
func (self *SAzureGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManagedVMCreateConfig) string {
|
||||
return ansible.PUBLIC_CLOUD_ANSIBLE_USER
|
||||
return api.VM_AZURE_DEFAULT_LOGIN_USER
|
||||
}
|
||||
|
||||
func (self *SAzureGuestDriver) GetGuestSecgroupVpcid(guest *models.SGuest) (string, error) {
|
||||
|
||||
@@ -37,7 +37,7 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceCrateOptions struct {
|
||||
type InstanceCreateOptions struct {
|
||||
NAME string `help:"name of instance"`
|
||||
IMAGE string `help:"image ID"`
|
||||
CPU int `help:"CPU count"`
|
||||
@@ -48,7 +48,7 @@ func init() {
|
||||
PASSWD string `help:"password"`
|
||||
PublicKey string `help:"PublicKey"`
|
||||
}
|
||||
shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *aliyun.SRegion, args *InstanceCrateOptions) error {
|
||||
shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *aliyun.SRegion, args *InstanceCreateOptions) error {
|
||||
instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.VSWITCH, args.PASSWD, args.PublicKey)
|
||||
if e != nil {
|
||||
return e
|
||||
|
||||
@@ -39,7 +39,7 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceCrateOptions struct {
|
||||
type InstanceCreateOptions struct {
|
||||
NAME string `help:"name of instance"`
|
||||
IMAGE string `help:"image ID"`
|
||||
CPU int `help:"CPU count"`
|
||||
@@ -49,7 +49,7 @@ func init() {
|
||||
NETWORK string `help:"Network ID"`
|
||||
PUBLICKEY string `help:"PublicKey file path"`
|
||||
}
|
||||
shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *aws.SRegion, args *InstanceCrateOptions) error {
|
||||
shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *aws.SRegion, args *InstanceCreateOptions) error {
|
||||
content, err := ioutil.ReadFile(args.PUBLICKEY)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -128,7 +128,7 @@ func (self *SAzureClient) getDefaultClient() (*autorest.Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
client.Authorizer = authorizer
|
||||
if DEBUG {
|
||||
if self.debug {
|
||||
client.RequestInspector = LogRequest()
|
||||
client.ResponseInspector = LogResponse()
|
||||
}
|
||||
|
||||
@@ -23,10 +23,6 @@ import (
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG = false
|
||||
)
|
||||
|
||||
func LogRequest() autorest.PrepareDecorator {
|
||||
return func(p autorest.Preparer) autorest.Preparer {
|
||||
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
|
||||
+18
-1
@@ -124,7 +124,24 @@ func (self *SRegion) DeleteDisk(diskId string) error {
|
||||
|
||||
func (self *SRegion) deleteDisk(diskId string) error {
|
||||
if !strings.HasPrefix(diskId, "https://") {
|
||||
return self.client.Delete(diskId)
|
||||
startTime := time.Now()
|
||||
timeout := 5 * time.Minute
|
||||
for {
|
||||
err := self.client.Delete(diskId)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// Disk vdisk_stress-testvm-azure-1-1_1555940308395625000 is attached to VM /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Compute/virtualMachines/stress-testvm-azure-1.
|
||||
// 更换系统盘后,数据未刷新会出现如上错误,多尝试几次即可
|
||||
if strings.Contains(err.Error(), "is attached to VM") {
|
||||
time.Sleep(time.Second * 5)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
if time.Now().Sub(startTime) > timeout {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO
|
||||
return cloudprovider.ErrNotImplemented
|
||||
|
||||
+18
-1
@@ -123,7 +123,24 @@ func (self *SEipAddress) Delete() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeallocateEIP(eipId string) error {
|
||||
return region.client.Delete(eipId)
|
||||
startTime := time.Now()
|
||||
timeout := time.Minute * 3
|
||||
for {
|
||||
err := region.client.Delete(eipId)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// {"error":{"code":"PublicIPAddressCannotBeDeleted","details":[],"message":"Public IP address /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/publicIPAddresses/eip-for-test-wwl can not be deleted since it is still allocated to resource /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/networkInterfaces/test-wwl-ipconfig."}}
|
||||
// 刚解绑eip后可能数据未刷新,需要再次尝试
|
||||
if strings.Contains(err.Error(), "it is still allocated to resource") {
|
||||
time.Sleep(time.Second * 5)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
if time.Now().Sub(startTime) > timeout {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SEipAddress) Dissociate() error {
|
||||
|
||||
+47
-28
@@ -16,14 +16,17 @@ package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/util/osprofile"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/util/ansible"
|
||||
"yunion.io/x/onecloud/pkg/util/seclib2"
|
||||
)
|
||||
|
||||
@@ -103,7 +106,7 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
|
||||
desc.Password = seclib2.RandomPassword2(12)
|
||||
}
|
||||
|
||||
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, nic.ID, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.UserData)
|
||||
vmId, err := self._createVM(desc, nic.ID)
|
||||
if err != nil {
|
||||
self.zone.region.DeleteNetworkInterface(nic.ID)
|
||||
return nil, err
|
||||
@@ -116,34 +119,45 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, nicId string, ipAddr string, desc string, passwd string, dataDisks []cloudprovider.SDiskInfo, publicKey string, userData string) (string, error) {
|
||||
image, err := self.zone.region.GetImageById(imgId)
|
||||
func (self *SHost) _createVM(desc *cloudprovider.SManagedVMCreateConfig, nicId string) (string, error) {
|
||||
image, err := self.zone.region.GetImageById(desc.ExternalImageId)
|
||||
if err != nil {
|
||||
log.Errorf("Get Image %s fail %s", imgId, err)
|
||||
log.Errorf("Get Image %s fail %s", desc.ExternalImageId, err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if image.Properties.ProvisioningState != ImageStatusAvailable {
|
||||
log.Errorf("image %s status %s", imgId, image.Properties.ProvisioningState)
|
||||
log.Errorf("image %s status %s", desc.ExternalImageId, image.Properties.ProvisioningState)
|
||||
return "", fmt.Errorf("image not ready")
|
||||
}
|
||||
storage, err := self.zone.getStorageByType(sysDisk.StorageType)
|
||||
storage, err := self.zone.getStorageByType(desc.SysDisk.StorageType)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err)
|
||||
return "", fmt.Errorf("Storage %s not avaiable: %s", desc.SysDisk.StorageType, err)
|
||||
}
|
||||
if !utils.IsInStringArray(desc.OsType, []string{osprofile.OS_TYPE_LINUX, osprofile.OS_TYPE_WINDOWS}) {
|
||||
desc.OsType = image.GetOsType()
|
||||
}
|
||||
sysDiskSize := int32(desc.SysDisk.SizeGB)
|
||||
computeName := desc.Name
|
||||
for _, k := range []string{"`", "~", "!", "@", "#", "$", `%`, "^", "&", "*", "(", ")", "=", "+", "_", "[", "]", "{", "}", "\\", "|", ";", ":", ".", "'", `"`, ",", "<", ">", "/", "?"} {
|
||||
computeName = strings.Replace(computeName, k, "", -1)
|
||||
}
|
||||
if len(computeName) > 15 {
|
||||
computeName = computeName[:15]
|
||||
}
|
||||
sysDiskSize := int32(sysDisk.SizeGB)
|
||||
instance := SInstance{
|
||||
Name: name,
|
||||
Name: desc.Name,
|
||||
Location: self.zone.region.Name,
|
||||
Properties: VirtualMachineProperties{
|
||||
HardwareProfile: HardwareProfile{
|
||||
VMSize: "",
|
||||
},
|
||||
OsProfile: OsProfile{
|
||||
ComputerName: name,
|
||||
AdminUsername: ansible.PUBLIC_CLOUD_ANSIBLE_USER,
|
||||
AdminPassword: passwd,
|
||||
CustomData: userData,
|
||||
// Windows computer name cannot be more than 15 characters long, be entirely numeric, or contain the following characters: ` ~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \\ | ; : . ' \" , < > / ?."
|
||||
ComputerName: computeName,
|
||||
AdminUsername: api.VM_AZURE_DEFAULT_LOGIN_USER,
|
||||
AdminPassword: desc.Password,
|
||||
CustomData: desc.UserData,
|
||||
},
|
||||
NetworkProfile: NetworkProfile{
|
||||
NetworkInterfaces: []NetworkInterfaceReference{
|
||||
@@ -155,34 +169,34 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
|
||||
StorageProfile: StorageProfile{
|
||||
ImageReference: image.getImageReference(),
|
||||
OsDisk: OSDisk{
|
||||
Name: fmt.Sprintf("vdisk_%s_%d", name, time.Now().UnixNano()),
|
||||
Name: fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()),
|
||||
Caching: "ReadWrite",
|
||||
ManagedDisk: &ManagedDiskParameters{
|
||||
StorageAccountType: storage.Name,
|
||||
},
|
||||
CreateOption: "FromImage",
|
||||
DiskSizeGB: &sysDiskSize,
|
||||
OsType: image.GetOsType(),
|
||||
OsType: desc.OsType,
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: "Microsoft.Compute/virtualMachines",
|
||||
}
|
||||
if len(publicKey) > 0 {
|
||||
if len(desc.PublicKey) > 0 {
|
||||
instance.Properties.OsProfile.LinuxConfiguration = &LinuxConfiguration{
|
||||
DisablePasswordAuthentication: false,
|
||||
SSH: &SSHConfiguration{
|
||||
PublicKeys: []SSHPublicKey{
|
||||
{KeyData: publicKey},
|
||||
{KeyData: desc.PublicKey},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
_dataDisks := []DataDisk{}
|
||||
for i := 0; i < len(dataDisks); i++ {
|
||||
diskName := fmt.Sprintf("vdisk_%s_%d", name, time.Now().UnixNano())
|
||||
size := int32(dataDisks[i].SizeGB)
|
||||
for i := 0; i < len(desc.DataDisks); i++ {
|
||||
diskName := fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano())
|
||||
size := int32(desc.DataDisks[i].SizeGB)
|
||||
lun := int32(i)
|
||||
_dataDisks = append(_dataDisks, DataDisk{
|
||||
Name: diskName,
|
||||
@@ -195,28 +209,33 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
|
||||
instance.Properties.StorageProfile.DataDisks = _dataDisks
|
||||
}
|
||||
|
||||
if len(instanceType) > 0 {
|
||||
instance.Properties.HardwareProfile.VMSize = instanceType
|
||||
log.Debugf("Try HardwareProfile : %s", instanceType)
|
||||
if len(desc.InstanceType) > 0 {
|
||||
instance.Properties.HardwareProfile.VMSize = desc.InstanceType
|
||||
log.Debugf("Try HardwareProfile : %s", desc.InstanceType)
|
||||
err = self.zone.region.client.Create(jsonutils.Marshal(instance), &instance)
|
||||
if err != nil {
|
||||
log.Errorf("Failed for %s: %s", instanceType, err)
|
||||
return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error())
|
||||
log.Errorf("Failed for %s: %s", desc.InstanceType, err)
|
||||
return "", fmt.Errorf("Failed to create specification %s.%s", desc.InstanceType, err.Error())
|
||||
}
|
||||
return instance.ID, nil
|
||||
}
|
||||
|
||||
for _, profile := range self.zone.region.getHardwareProfile(cpu, memMB) {
|
||||
for _, profile := range self.zone.region.getHardwareProfile(desc.Cpu, desc.MemoryMB) {
|
||||
instance.Properties.HardwareProfile.VMSize = profile
|
||||
log.Debugf("Try HardwareProfile : %s", profile)
|
||||
err = self.zone.region.client.Create(jsonutils.Marshal(instance), &instance)
|
||||
if err != nil {
|
||||
for _, key := range []string{`"code":"InvalidParameter"`, `"code":"NicInUse"`} {
|
||||
if strings.Contains(err.Error(), key) {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
log.Errorf("Failed for %s: %s", profile, err)
|
||||
continue
|
||||
}
|
||||
return instance.ID, nil
|
||||
}
|
||||
return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB)
|
||||
return "", fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB)
|
||||
}
|
||||
|
||||
func (self *SHost) GetAccessIp() string {
|
||||
|
||||
+117
-68
@@ -134,13 +134,22 @@ type Statuses struct {
|
||||
//Time time.Time
|
||||
}
|
||||
|
||||
type VMAgent struct {
|
||||
VmAgentVersion string `json:"vmAgentVersion,omitempty"`
|
||||
Statuses Statuses `json:"statuses,omitempty"`
|
||||
type SVMAgent struct {
|
||||
VmAgentVersion string `json:"vmAgentVersion,omitempty"`
|
||||
Statuses []Statuses `json:"statuses,omitempty"`
|
||||
}
|
||||
|
||||
type SExtension struct {
|
||||
Name string
|
||||
Type string
|
||||
TypeHandlerVersion string `json:"typeHandlerVersion,omitempty"`
|
||||
Statuses []Statuses `json:"statuses,omitempty"`
|
||||
}
|
||||
|
||||
type VirtualMachineInstanceView struct {
|
||||
Statuses []Statuses `json:"statuses,omitempty"`
|
||||
Statuses []Statuses `json:"statuses,omitempty"`
|
||||
VMAgent SVMAgent `json:"vmAgent,omitempty"`
|
||||
Extensions []SExtension `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
type DomainName struct {
|
||||
@@ -257,6 +266,50 @@ func (self *SInstance) GetInstanceType() string {
|
||||
return self.Properties.HardwareProfile.VMSize
|
||||
}
|
||||
|
||||
func (self *SInstance) WaitEnableVMAccessReady() error {
|
||||
if self.Properties.InstanceView == nil {
|
||||
return fmt.Errorf("instance may not install VMAgent or VMAgent not running")
|
||||
}
|
||||
if len(self.Properties.InstanceView.VMAgent.VmAgentVersion) > 0 {
|
||||
startTime := time.Now()
|
||||
timeout := time.Minute * 5
|
||||
for {
|
||||
status := ""
|
||||
for _, vmAgent := range self.Properties.InstanceView.VMAgent.Statuses {
|
||||
status = vmAgent.DisplayStatus
|
||||
if status == "Ready" {
|
||||
break
|
||||
}
|
||||
log.Debugf("vmAgent %s status: %s waite for ready", self.Properties.InstanceView.VMAgent.VmAgentVersion, vmAgent.DisplayStatus)
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
if status == "Ready" {
|
||||
break
|
||||
}
|
||||
self.Refresh()
|
||||
if time.Now().Sub(startTime) > timeout {
|
||||
return fmt.Errorf("timeout for waitting vmAgent ready, current status: %s", status)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, extension := range self.Properties.InstanceView.Extensions {
|
||||
if extension.Name == "enablevmaccess" {
|
||||
displayStatus := ""
|
||||
for _, status := range extension.Statuses {
|
||||
displayStatus = status.DisplayStatus
|
||||
if displayStatus == "Provisioning succeeded" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return self.host.zone.region.deleteExtension(self.ID, "enablevmaccess")
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("instance may not install VMAgent or VMAgent not running")
|
||||
}
|
||||
|
||||
func (self *SInstance) getOsDisk() (*SDisk, error) {
|
||||
diskId := self.Properties.StorageProfile.OsDisk.ManagedDisk.ID
|
||||
if osDisk, err := self.getDiskWithStore(diskId); err != nil {
|
||||
@@ -603,6 +656,13 @@ func (region *SRegion) ChangeVMConfig(ctx context.Context, instanceId string, nc
|
||||
}
|
||||
|
||||
func (self *SInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error {
|
||||
if len(publicKey) > 0 || len(password) > 0 {
|
||||
// 先判断系统是否安装了vmAgent,然后等待扩展准备完成后再重置密码
|
||||
err := self.WaitEnableVMAccessReady()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return self.host.zone.region.DeployVM(ctx, self.ID, name, password, publicKey, deleteKeypair, description)
|
||||
}
|
||||
|
||||
@@ -704,33 +764,21 @@ func (region *SRegion) DeployVM(ctx context.Context, instanceId, name, password,
|
||||
if len(publicKey) > 0 {
|
||||
return region.resetPublicKey(instanceId, instance.Properties.OsProfile.AdminUsername, publicKey)
|
||||
}
|
||||
return region.resetPassword(instanceId, instance.Properties.OsProfile.AdminUsername, password)
|
||||
if len(password) > 0 {
|
||||
return region.resetPassword(instanceId, instance.Properties.OsProfile.AdminUsername, password)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
|
||||
return self.host.zone.region.ReplaceSystemDisk(self.ID, imageId, passwd, publicKey, int32(sysSizeGB))
|
||||
cpu := self.GetVcpuCount()
|
||||
memoryMb := self.GetVmemSizeMB()
|
||||
self.StopVM(ctx, true)
|
||||
return self.host.zone.region.ReplaceSystemDisk(self, cpu, memoryMb, imageId, passwd, publicKey, sysSizeGB)
|
||||
}
|
||||
|
||||
func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey string, sysSizeGB int32) (string, error) {
|
||||
log.Debugf("ReplaceSystemDisk %s image: %s", instanceId, imageId)
|
||||
instance, err := region.GetInstance(instanceId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
image, err := region.GetImageById(imageId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = region.StopVM(instanceId, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
orgOsType := instance.GetOSType()
|
||||
destOsType := image.GetOsType()
|
||||
if orgOsType != destOsType {
|
||||
return "", fmt.Errorf("Cannot replease osType %s => %s", orgOsType, destOsType)
|
||||
}
|
||||
diskName := fmt.Sprintf("vdisk_%s_%d", instance.Name, time.Now().UnixNano())
|
||||
func (region *SRegion) ReplaceSystemDisk(instance *SInstance, cpu int8, memoryMb int, imageId, passwd, publicKey string, sysSizeGB int) (string, error) {
|
||||
log.Debugf("ReplaceSystemDisk %s image: %s", instance.ID, imageId)
|
||||
storageType := instance.Properties.StorageProfile.OsDisk.ManagedDisk.StorageAccountType
|
||||
if len(storageType) == 0 {
|
||||
_disk, err := region.GetDisk(instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID)
|
||||
@@ -739,58 +787,55 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey
|
||||
}
|
||||
storageType = _disk.Sku.Name
|
||||
}
|
||||
oldDiskId := instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID
|
||||
disk, err := region.CreateDisk(storageType, diskName, sysSizeGB, "", imageId)
|
||||
if len(instance.Properties.NetworkProfile.NetworkInterfaces) == 0 {
|
||||
return "", fmt.Errorf("failed to find network for instance: %s", instance.Name)
|
||||
}
|
||||
nicId := instance.Properties.NetworkProfile.NetworkInterfaces[0].ID
|
||||
nic, err := region.GetNetworkInterfaceDetail(nicId)
|
||||
if err != nil {
|
||||
log.Errorf("Create system disk error: %v", err)
|
||||
log.Errorf("failed to find nic %s error: %v", nicId, err)
|
||||
return "", err
|
||||
}
|
||||
instance.Properties.StorageProfile.OsDisk.Name = disk.Name
|
||||
instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID = disk.ID
|
||||
instance.Properties.StorageProfile.OsDisk.ManagedDisk.StorageAccountType = storageType
|
||||
|
||||
instance.Properties.OsProfile.AdminPassword = passwd
|
||||
if len(publicKey) > 0 {
|
||||
instance.Properties.OsProfile.LinuxConfiguration = &LinuxConfiguration{
|
||||
SSH: &SSHConfiguration{
|
||||
PublicKeys: []SSHPublicKey{
|
||||
{
|
||||
KeyData: publicKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(nic.Properties.IPConfigurations) == 0 {
|
||||
return "", fmt.Errorf("failed to find networkId for nic %s", nicId)
|
||||
}
|
||||
for i := 0; i < len(instance.Properties.StorageProfile.DataDisks); i++ {
|
||||
//避免因size更新不及时导致更换系统盘失败
|
||||
instance.Properties.StorageProfile.DataDisks[i].DiskSizeGB = nil
|
||||
if instance.Properties.StorageProfile.OsDisk.DiskSizeGB != nil && *instance.Properties.StorageProfile.OsDisk.DiskSizeGB > int32(sysSizeGB) {
|
||||
sysSizeGB = int(*instance.Properties.StorageProfile.OsDisk.DiskSizeGB)
|
||||
}
|
||||
image, err := region.GetImageById(imageId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if minOsDiskSizeGB := image.GetMinOsDiskSizeGb(); minOsDiskSizeGB > sysSizeGB {
|
||||
sysSizeGB = minOsDiskSizeGB
|
||||
}
|
||||
|
||||
networkId := nic.Properties.IPConfigurations[0].Properties.Subnet.ID
|
||||
osType := instance.Properties.StorageProfile.OsDisk.OsType
|
||||
newInstance, err := region.CreateInstanceSimple(instance.Name+"-1", imageId, osType, cpu, memoryMb, sysSizeGB, storageType, []int{}, networkId, passwd, publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newInstance.StopVM(context.Background(), true)
|
||||
cloudprovider.WaitStatus(newInstance, api.VM_READY, time.Second*5, time.Minute*5)
|
||||
|
||||
newInstance.deleteVM(context.Background(), true)
|
||||
|
||||
//交换系统盘
|
||||
instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID, newInstance.Properties.StorageProfile.OsDisk.ManagedDisk.ID = newInstance.Properties.StorageProfile.OsDisk.ManagedDisk.ID, instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID
|
||||
instance.Properties.StorageProfile.OsDisk.Name = ""
|
||||
instance.Properties.ProvisioningState = ""
|
||||
instance.Properties.InstanceView = nil
|
||||
err = region.client.Update(jsonutils.Marshal(instance), nil)
|
||||
if err != nil {
|
||||
// 更新失败,需要删除之前交换过的系统盘
|
||||
region.DeleteDisk(instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID)
|
||||
return "", err
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
log.Debugf("try delete old disk: %s", oldDiskId)
|
||||
if err := region.deleteDisk(oldDiskId); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * time.Duration(i*10))
|
||||
}
|
||||
// Azure 数据刷新不及时,需要稍作等待
|
||||
for i := 0; i < 3; i++ {
|
||||
instance, err := region.GetInstance(instanceId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID == disk.ID {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * time.Duration(i*10))
|
||||
}
|
||||
return disk.ID, nil
|
||||
// 交换成功需要删掉旧的系统盘
|
||||
region.DeleteDisk(newInstance.Properties.StorageProfile.OsDisk.ManagedDisk.ID)
|
||||
return strings.ToLower(instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID), nil
|
||||
}
|
||||
|
||||
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
|
||||
@@ -813,7 +858,7 @@ func (self *SRegion) DeleteVM(instanceId string) error {
|
||||
return self.doDeleteVM(instanceId)
|
||||
}
|
||||
|
||||
func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
func (self *SInstance) deleteVM(ctx context.Context, keepSysDisk bool) error {
|
||||
sysDiskId := ""
|
||||
if self.Properties.StorageProfile.OsDisk.ManagedDisk != nil {
|
||||
sysDiskId = self.Properties.StorageProfile.OsDisk.ManagedDisk.ID
|
||||
@@ -822,7 +867,7 @@ func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(sysDiskId) > 0 {
|
||||
if len(sysDiskId) > 0 && !keepSysDisk {
|
||||
err := self.host.zone.region.deleteDisk(sysDiskId)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -843,6 +888,10 @@ func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SInstance) DeleteVM(ctx context.Context) error {
|
||||
return self.deleteVM(ctx, false)
|
||||
}
|
||||
|
||||
func (self *SInstance) getDiskWithStore(diskId string) (*SDisk, error) {
|
||||
if disk, err := self.host.zone.region.GetDisk(diskId); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -169,5 +169,9 @@ func (self *SRegion) CreateNetworkInterface(nicName string, ipAddr string, subne
|
||||
Type: "Microsoft.Network/networkInterfaces",
|
||||
}
|
||||
|
||||
if len(ipAddr) == 0 {
|
||||
instancenic.Properties.IPConfigurations[0].Properties.PrivateIPAllocationMethod = "Dynamic"
|
||||
}
|
||||
|
||||
return &instancenic, self.client.Create(jsonutils.Marshal(&instancenic), &instancenic)
|
||||
}
|
||||
|
||||
@@ -180,9 +180,10 @@ func publisherGetName(publisher, offer, sku, version string) string {
|
||||
}
|
||||
|
||||
func publisherGetOsType(publisher string) string {
|
||||
driver, ok := publisherDrivers[publisher]
|
||||
if ok {
|
||||
return driver.OsType
|
||||
for _publisher, driver := range publisherDrivers {
|
||||
if strings.ToLower(_publisher) == strings.ToLower(publisher) {
|
||||
return driver.OsType
|
||||
}
|
||||
}
|
||||
return "Linux"
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ func (self *SRegion) fetchInfrastructure() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, passwd string, publicKey string) (*SInstance, error) {
|
||||
func (self *SRegion) CreateInstanceSimple(name string, imgId, osType string, cpu int8, memMb int, sysDiskSizeGB int, storageType string, dataDiskSizesGB []int, networkId string, passwd string, publicKey string) (*SInstance, error) {
|
||||
izones, err := self.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -427,22 +427,29 @@ func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, me
|
||||
desc := &cloudprovider.SManagedVMCreateConfig{
|
||||
Name: name,
|
||||
ExternalImageId: imgId,
|
||||
SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType},
|
||||
Cpu: cpu,
|
||||
MemoryMB: memGB * 1024,
|
||||
SysDisk: cloudprovider.SDiskInfo{SizeGB: sysDiskSizeGB, StorageType: storageType},
|
||||
Cpu: int(cpu),
|
||||
MemoryMB: memMb,
|
||||
ExternalNetworkId: networkId,
|
||||
Password: seclib2.RandomPassword2(12),
|
||||
DataDisks: []cloudprovider.SDiskInfo{},
|
||||
PublicKey: publicKey,
|
||||
OsType: osType,
|
||||
}
|
||||
if len(passwd) > 0 {
|
||||
desc.Password = passwd
|
||||
}
|
||||
for _, sizeGB := range dataDiskSizesGB {
|
||||
desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType})
|
||||
}
|
||||
inst, err := z.getHost().CreateVM(desc)
|
||||
host := z.getHost()
|
||||
inst, err := host.CreateVM(desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return inst.(*SInstance), nil
|
||||
instance := inst.(*SInstance)
|
||||
instance.host = host
|
||||
return instance, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("cannot find network %s", networkId)
|
||||
|
||||
@@ -74,19 +74,21 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceCrateOptions struct {
|
||||
NAME string `help:"name of instance"`
|
||||
IMAGE string `help:"image ID"`
|
||||
CPU int `help:"CPU count"`
|
||||
MEMORYGB int `help:"MemoryGB"`
|
||||
Disk []int `help:"Data disk sizes int GB"`
|
||||
STORAGE string `help:"Storage type"`
|
||||
NETWORK string `help:"Network ID"`
|
||||
PASSWD string `help:"password"`
|
||||
PublicKey string `help:"PublicKey"`
|
||||
type InstanceCreateOptions struct {
|
||||
NAME string `help:"Name of instance"`
|
||||
IMAGE string `help:"image ID"`
|
||||
CPU int8 `help:"CPU count"`
|
||||
MEMORYGB int `help:"MemoryGB"`
|
||||
SYSDISKSIZEGB int `help:"System Disk Size"`
|
||||
Disk []int `help:"Data disk sizes int GB"`
|
||||
STORAGE string `help:"Storage type"`
|
||||
NETWORK string `help:"Network ID"`
|
||||
PASSWD string `help:"password"`
|
||||
PublicKey string `help:"PublicKey"`
|
||||
OsType string `help:"Operation system type" choices:"Linux|Windows"`
|
||||
}
|
||||
shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *azure.SRegion, args *InstanceCrateOptions) error {
|
||||
instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.NETWORK, args.PASSWD, args.PublicKey)
|
||||
shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *azure.SRegion, args *InstanceCreateOptions) error {
|
||||
instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.OsType, args.CPU, args.MEMORYGB, args.SYSDISKSIZEGB, args.STORAGE, args.Disk, args.NETWORK, args.PASSWD, args.PublicKey)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
@@ -120,18 +122,24 @@ func init() {
|
||||
|
||||
type InstanceRebuildOptions struct {
|
||||
ID string `help:"Instance ID"`
|
||||
Image string `help:"Image ID"`
|
||||
CPU int8 `help:"Instance CPU core"`
|
||||
MEMORYMB int `help:"Instance Memory MB"`
|
||||
IMAGE string `help:"Image ID"`
|
||||
Password string `help:"pasword"`
|
||||
PublicKey string `help:"Public Key"`
|
||||
Size int32 `help:"system disk size in GB"`
|
||||
Size int `help:"system disk size in GB"`
|
||||
}
|
||||
shellutils.R(&InstanceRebuildOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *azure.SRegion, args *InstanceRebuildOptions) error {
|
||||
if diskID, err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.PublicKey, args.Size); err != nil {
|
||||
instance, err := cli.GetInstance(args.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
fmt.Printf("New diskID is %s", diskID)
|
||||
return nil
|
||||
}
|
||||
diskId, err := cli.ReplaceSystemDisk(instance, args.CPU, args.MEMORYMB, args.IMAGE, args.Password, args.PublicKey, args.Size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("New diskId is %s", diskId)
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceDiskOptions struct {
|
||||
|
||||
@@ -37,7 +37,7 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceCrateOptions struct {
|
||||
type InstanceCreateOptions struct {
|
||||
NAME string `help:"name of instance"`
|
||||
IMAGE string `help:"image ID"`
|
||||
CPU int `help:"CPU count"`
|
||||
@@ -49,7 +49,7 @@ func init() {
|
||||
PublicKey string `help:"PublicKey"`
|
||||
}
|
||||
|
||||
shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *qcloud.SRegion, args *InstanceCrateOptions) error {
|
||||
shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *qcloud.SRegion, args *InstanceCreateOptions) error {
|
||||
instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.NETWORK, args.PASSWD, args.PublicKey)
|
||||
if e != nil {
|
||||
return e
|
||||
|
||||
Reference in New Issue
Block a user