yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/azure/host.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package azure
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"yunion.io/x/jsonutils"
    23  	"yunion.io/x/log"
    24  	"yunion.io/x/pkg/errors"
    25  	"yunion.io/x/pkg/util/osprofile"
    26  	"yunion.io/x/pkg/utils"
    27  
    28  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    29  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    30  	"yunion.io/x/cloudmux/pkg/multicloud"
    31  	"yunion.io/x/onecloud/pkg/util/seclib2"
    32  )
    33  
    34  type SHost struct {
    35  	multicloud.SHostBase
    36  	zone *SZone
    37  }
    38  
    39  func (self *SHost) GetId() string {
    40  	return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId())
    41  }
    42  
    43  func (self *SHost) GetName() string {
    44  	return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
    45  }
    46  
    47  func (self *SHost) GetGlobalId() string {
    48  	return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
    49  }
    50  
    51  func (self *SHost) IsEmulated() bool {
    52  	return true
    53  }
    54  
    55  func (self *SHost) GetStatus() string {
    56  	return api.HOST_STATUS_RUNNING
    57  }
    58  
    59  func (self *SHost) Refresh() error {
    60  	return nil
    61  }
    62  
    63  func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
    64  	nic, err := self.zone.region.CreateNetworkInterface(desc.ProjectId, fmt.Sprintf("%s-ipconfig", desc.NameEn), desc.IpAddr, desc.ExternalNetworkId, desc.ExternalSecgroupId)
    65  	if err != nil {
    66  		return nil, errors.Wrapf(err, "CreateNetworkInterface")
    67  	}
    68  
    69  	instance, err := self.zone.region._createVM(desc, nic.ID)
    70  	if err != nil {
    71  		self.zone.region.DeleteNetworkInterface(nic.ID)
    72  		return nil, err
    73  	}
    74  	instance.host = self
    75  	return instance, nil
    76  }
    77  
    78  func (self *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, nicId string) (*SInstance, error) {
    79  	image, err := self.GetImageById(desc.ExternalImageId)
    80  	if err != nil {
    81  		return nil, errors.Wrapf(err, "GetImageById(%s)", desc.ExternalImageId)
    82  	}
    83  
    84  	if len(desc.Password) == 0 {
    85  		//Azure创建必须要设置密码
    86  		desc.Password = seclib2.RandomPassword2(12)
    87  	}
    88  
    89  	if image.Properties.ProvisioningState != ImageStatusAvailable {
    90  		return nil, fmt.Errorf("image %s not ready status: %s", desc.ExternalImageId, image.Properties.ProvisioningState)
    91  	}
    92  	if !utils.IsInStringArray(desc.OsType, []string{osprofile.OS_TYPE_LINUX, osprofile.OS_TYPE_WINDOWS}) {
    93  		desc.OsType = string(image.GetOsType())
    94  	}
    95  	computeName := desc.Hostname
    96  	for _, k := range "`~!@#$%^&*()=+_[]{}\\|;:.'\",<>/?" {
    97  		computeName = strings.Replace(computeName, string(k), "", -1)
    98  	}
    99  	if len(computeName) > 15 {
   100  		computeName = computeName[:15]
   101  	}
   102  	osProfile := map[string]string{
   103  		"ComputerName":  computeName,
   104  		"AdminUsername": api.VM_AZURE_DEFAULT_LOGIN_USER,
   105  		"AdminPassword": desc.Password,
   106  	}
   107  	if len(desc.UserData) > 0 {
   108  		osProfile["CustomData"] = desc.UserData
   109  	}
   110  	params := jsonutils.Marshal(map[string]interface{}{
   111  		"Name":     desc.NameEn,
   112  		"Location": self.Name,
   113  		"Properties": map[string]interface{}{
   114  			"HardwareProfile": map[string]string{
   115  				"VMSize": "",
   116  			},
   117  			"OsProfile": osProfile,
   118  			"NetworkProfile": map[string]interface{}{
   119  				"NetworkInterfaces": []map[string]string{
   120  					map[string]string{
   121  						"Id": nicId,
   122  					},
   123  				},
   124  			},
   125  			"StorageProfile": map[string]interface{}{
   126  				"ImageReference": image.getImageReference(),
   127  				"OsDisk": map[string]interface{}{
   128  					"Name":    fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()),
   129  					"Caching": "ReadWrite",
   130  					"ManagedDisk": map[string]string{
   131  						"StorageAccountType": desc.SysDisk.StorageType,
   132  					},
   133  					"CreateOption": "FromImage",
   134  					"DiskSizeGB":   desc.SysDisk.SizeGB,
   135  					"OsType":       desc.OsType,
   136  				},
   137  			},
   138  		},
   139  		"Type": "Microsoft.Compute/virtualMachines",
   140  	}).(*jsonutils.JSONDict)
   141  	if len(desc.PublicKey) > 0 && desc.OsType == osprofile.OS_TYPE_LINUX {
   142  		linuxConfiguration := map[string]interface{}{
   143  			"DisablePasswordAuthentication": false,
   144  			"SSH": map[string]interface{}{
   145  				"PublicKeys": []map[string]string{
   146  					map[string]string{
   147  						"KeyData": desc.PublicKey,
   148  						"Path":    fmt.Sprintf("/home/%s/.ssh/authorized_keys", api.VM_AZURE_DEFAULT_LOGIN_USER),
   149  					},
   150  				},
   151  			},
   152  		}
   153  		params.Add(jsonutils.Marshal(linuxConfiguration), "Properties", "OsProfile", "LinuxConfiguration")
   154  	}
   155  	if len(desc.Tags) > 0 {
   156  		params.Add(jsonutils.Marshal(desc.Tags), "tags")
   157  	}
   158  
   159  	dataDisks := jsonutils.NewArray()
   160  	for i := 0; i < len(desc.DataDisks); i++ {
   161  		dataDisk := jsonutils.Marshal(map[string]interface{}{
   162  			"Name":         fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()),
   163  			"DiskSizeGB":   desc.DataDisks[i].SizeGB,
   164  			"CreateOption": "Empty",
   165  			"ManagedDisk": map[string]string{
   166  				"StorageAccountType": desc.DataDisks[i].StorageType,
   167  			},
   168  			"Lun": i,
   169  		})
   170  		dataDisks.Add(dataDisk)
   171  	}
   172  	if dataDisks.Length() > 0 {
   173  		params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks")
   174  	}
   175  
   176  	instance := &SInstance{}
   177  	if len(desc.InstanceType) > 0 {
   178  		params.Add(jsonutils.NewString(desc.InstanceType), "Properties", "HardwareProfile", "VMSize")
   179  		log.Debugf("Try HardwareProfile : %s", desc.InstanceType)
   180  		err = self.create(desc.ProjectId, params, instance)
   181  		if err != nil {
   182  			return nil, errors.Wrapf(err, "create")
   183  		}
   184  		return instance, nil
   185  	}
   186  
   187  	for _, profile := range self.getHardwareProfile(desc.Cpu, desc.MemoryMB) {
   188  		params.Add(jsonutils.NewString(profile), "Properties", "HardwareProfile", "VMSize")
   189  		log.Debugf("Try HardwareProfile : %s", profile)
   190  		err = self.create(desc.ProjectId, params, &instance)
   191  		if err != nil {
   192  			for _, key := range []string{`"code":"InvalidParameter"`, `"code":"NicInUse"`} {
   193  				if strings.Contains(err.Error(), key) {
   194  					return nil, err
   195  				}
   196  			}
   197  			log.Errorf("Failed for %s: %s", profile, err)
   198  			continue
   199  		}
   200  		return instance, nil
   201  	}
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB)
   206  }
   207  
   208  func (self *SHost) GetAccessIp() string {
   209  	return ""
   210  }
   211  
   212  func (self *SHost) GetAccessMac() string {
   213  	return ""
   214  }
   215  
   216  func (self *SHost) GetCpuCount() int {
   217  	return 0
   218  }
   219  
   220  func (self *SHost) GetCpuDesc() string {
   221  	return ""
   222  }
   223  
   224  func (self *SHost) GetCpuMhz() int {
   225  	return 0
   226  }
   227  
   228  func (self *SHost) GetMemSizeMB() int {
   229  	return 0
   230  }
   231  func (self *SHost) GetEnabled() bool {
   232  	return true
   233  }
   234  
   235  func (self *SHost) GetHostStatus() string {
   236  	return api.HOST_ONLINE
   237  }
   238  func (self *SHost) GetNodeCount() int8 {
   239  	return 0
   240  }
   241  
   242  func (self *SHost) GetHostType() string {
   243  	return api.HOST_TYPE_AZURE
   244  }
   245  
   246  func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
   247  	return self.zone.GetIStorageById(id)
   248  }
   249  
   250  func (self *SHost) GetSysInfo() jsonutils.JSONObject {
   251  	info := jsonutils.NewDict()
   252  	info.Add(jsonutils.NewString(CLOUD_PROVIDER_AZURE), "manufacture")
   253  	return info
   254  }
   255  
   256  func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
   257  	return self.zone.getIStorages(), nil
   258  }
   259  
   260  func (self *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) {
   261  	instance, err := self.zone.region.GetInstance(instanceId)
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	instance.host = self
   266  	return instance, nil
   267  }
   268  
   269  func (self *SHost) GetStorageSizeMB() int {
   270  	return 0
   271  }
   272  
   273  func (self *SHost) GetStorageType() string {
   274  	return api.DISK_TYPE_HYBRID
   275  }
   276  
   277  func (self *SHost) GetSN() string {
   278  	return ""
   279  }
   280  
   281  func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
   282  	vms, err := self.zone.region.GetInstances()
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	ivms := make([]cloudprovider.ICloudVM, len(vms))
   287  	for i := 0; i < len(vms); i++ {
   288  		vms[i].host = self
   289  		ivms[i] = &vms[i]
   290  		log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName())
   291  	}
   292  	return ivms, nil
   293  }
   294  
   295  func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
   296  	return self.zone.GetIWires()
   297  }
   298  
   299  func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
   300  	return nil, cloudprovider.ErrNotSupported
   301  }
   302  
   303  func (host *SHost) GetIsMaintenance() bool {
   304  	return false
   305  }
   306  
   307  func (host *SHost) GetVersion() string {
   308  	return AZURE_API_VERSION
   309  }