yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/azure/classic_instance.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  	"context"
    19  	"fmt"
    20  	"net/url"
    21  	"strings"
    22  	"time"
    23  
    24  	"yunion.io/x/jsonutils"
    25  	"yunion.io/x/log"
    26  	"yunion.io/x/pkg/errors"
    27  	"yunion.io/x/pkg/util/osprofile"
    28  
    29  	"yunion.io/x/cloudmux/pkg/apis"
    30  	billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
    31  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    32  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    33  	"yunion.io/x/cloudmux/pkg/multicloud"
    34  	"yunion.io/x/onecloud/pkg/util/billing"
    35  )
    36  
    37  type FormattedMessage struct {
    38  	Language string
    39  	Message  string
    40  }
    41  
    42  type GuestAgentStatus struct {
    43  	ProtocolVersion   string           `json:"protocolVersion,omitempty"`
    44  	Timestamp         time.Time        `json:"timestamp,omitempty"`
    45  	GuestAgentVersion string           `json:"guestAgentVersion,omitempty"`
    46  	Status            string           `json:"status,omitempty"`
    47  	FormattedMessage  FormattedMessage `json:"formattedMessage,omitempty"`
    48  }
    49  
    50  type ClassicVirtualMachineInstanceView struct {
    51  	Status                   string   `json:"status,omitempty"`
    52  	PowerState               string   `json:"powerState,omitempty"`
    53  	PublicIpAddresses        []string `json:"publicIpAddresses,omitempty"`
    54  	FullyQualifiedDomainName string   `json:"fullyQualifiedDomainName,omitempty"`
    55  
    56  	UpdateDomain        int              `json:"updateDomain,omitempty"`
    57  	FaultDomain         int              `json:"faultDomain,omitempty"`
    58  	StatusMessage       string           `json:"statusMessage,omitempty"`
    59  	PrivateIpAddress    string           `json:"privateIpAddress,omitempty"`
    60  	InstanceIpAddresses []string         `json:"instanceIpAddresses,omitempty"`
    61  	ComputerName        string           `json:"computerName,omitempty"`
    62  	GuestAgentStatus    GuestAgentStatus `json:"guestAgentStatus,omitempty"`
    63  }
    64  
    65  type SubResource struct {
    66  	ID   string `json:"id,omitempty"`
    67  	Name string `json:"name,omitempty"`
    68  	Type string `json:"type,omitempty"`
    69  }
    70  
    71  type ClassicDisk struct {
    72  	Lun             int32
    73  	DiskName        string
    74  	Caching         string
    75  	OperatingSystem string
    76  	IoType          string
    77  	CreatedTime     string
    78  	SourceImageName string
    79  	VhdUri          string
    80  	DiskSize        int32 `json:"diskSize,omitempty"`
    81  	StorageAccount  SubResource
    82  }
    83  
    84  type ClassicStorageProfile struct {
    85  	OperatingSystemDisk ClassicDisk    `json:"operatingSystemDisk,omitempty"`
    86  	DataDisks           *[]ClassicDisk `json:"dataDisks,allowempty"`
    87  }
    88  
    89  type ClassicHardwareProfile struct {
    90  	PlatformGuestAgent bool
    91  	Size               string
    92  	DeploymentName     string
    93  	DeploymentId       string
    94  	DeploymentLabel    string
    95  	DeploymentLocked   bool
    96  }
    97  
    98  type InputEndpoint struct {
    99  	EndpointName             string
   100  	PrivatePort              int32
   101  	PublicPort               int32
   102  	Protocol                 string
   103  	EnableDirectServerReturn bool
   104  }
   105  
   106  type InstanceIp struct {
   107  	IdleTimeoutInMinutes int
   108  	ID                   string
   109  	Name                 string
   110  	Type                 string
   111  }
   112  
   113  type ClassicVirtualNetwork struct {
   114  	StaticIpAddress string   `json:"staticIpAddress,omitempty"`
   115  	SubnetNames     []string `json:"subnetNames,omitempty"`
   116  	ID              string
   117  	Name            string
   118  	Type            string
   119  }
   120  
   121  type ClassicNetworkProfile struct {
   122  	InputEndpoints       *[]InputEndpoint      `json:"inputEndpoints,omitempty"`
   123  	InstanceIps          *[]InstanceIp         `json:"instanceIps,omitempty"`
   124  	ReservedIps          *[]SubResource        `json:"reservedIps,omitempty"`
   125  	VirtualNetwork       ClassicVirtualNetwork `json:"virtualNetwork,omitempty"`
   126  	NetworkSecurityGroup *SubResource          `json:"networkSecurityGroup,omitempty"`
   127  }
   128  
   129  type ClassicVirtualMachineProperties struct {
   130  	DomainName      *SubResource                       `json:"domainName,omitempty"`
   131  	InstanceView    *ClassicVirtualMachineInstanceView `json:"instanceView,omitempty"`
   132  	NetworkProfile  ClassicNetworkProfile              `json:"networkProfile,omitempty"`
   133  	HardwareProfile ClassicHardwareProfile             `json:"hardwareProfile,omitempty"`
   134  	StorageProfile  ClassicStorageProfile              `json:"storageProfile,omitempty"`
   135  }
   136  
   137  type SClassicInstance struct {
   138  	multicloud.SInstanceBase
   139  	AzureTags
   140  
   141  	host *SClassicHost
   142  
   143  	idisks []cloudprovider.ICloudDisk
   144  
   145  	Properties ClassicVirtualMachineProperties `json:"properties,omitempty"`
   146  	ID         string
   147  	Name       string
   148  	Type       string
   149  	Location   string
   150  }
   151  
   152  func (self *SClassicInstance) GetSecurityGroupIds() ([]string, error) {
   153  	secgroupIds := []string{}
   154  	if self.Properties.NetworkProfile.NetworkSecurityGroup != nil {
   155  		secgroupIds = append(secgroupIds, self.Properties.NetworkProfile.NetworkSecurityGroup.ID)
   156  	}
   157  	return secgroupIds, nil
   158  }
   159  
   160  func (self *SClassicInstance) GetSysTags() map[string]string {
   161  	data := map[string]string{}
   162  	priceKey := fmt.Sprintf("%s::%s", self.Properties.HardwareProfile.Size, self.host.zone.region.Name)
   163  	data["price_key"] = priceKey
   164  	data["zone_ext_id"] = self.host.zone.GetGlobalId()
   165  	return data
   166  }
   167  
   168  func (self *SClassicInstance) GetHypervisor() string {
   169  	return api.HYPERVISOR_AZURE
   170  }
   171  
   172  func (self *SClassicInstance) GetInstanceType() string {
   173  	return self.Properties.HardwareProfile.Size
   174  }
   175  
   176  func (self *SRegion) GetClassicInstances() ([]SClassicInstance, error) {
   177  	instances := []SClassicInstance{}
   178  	err := self.list("Microsoft.ClassicCompute/virtualMachines", url.Values{}, &instances)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	return instances, nil
   183  }
   184  
   185  func (self *SRegion) GetClassicInstance(instanceId string) (*SClassicInstance, error) {
   186  	instance := SClassicInstance{}
   187  	params := url.Values{}
   188  	params.Add("$expand", "instanceView")
   189  	return &instance, self.get(instanceId, params, &instance)
   190  }
   191  
   192  func (self *SRegion) GetClassicInstanceDisks(instanceId string) ([]SClassicDisk, error) {
   193  	result := struct {
   194  		Value []SClassicDisk
   195  	}{}
   196  	resource := fmt.Sprintf("%s/disks", instanceId)
   197  	err := self.get(resource, url.Values{}, &result)
   198  	if err != nil {
   199  		return nil, errors.Wrapf(err, "list")
   200  	}
   201  	return result.Value, nil
   202  }
   203  
   204  func (self *SClassicInstance) getNics() ([]SClassicInstanceNic, error) {
   205  	instance, err := self.host.zone.region.GetClassicInstance(self.ID)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	networkProfile := instance.Properties.NetworkProfile
   210  	ip, id := "", ""
   211  	if len(networkProfile.VirtualNetwork.SubnetNames) > 0 {
   212  		id = fmt.Sprintf("%s/%s", networkProfile.VirtualNetwork.ID, networkProfile.VirtualNetwork.SubnetNames[0])
   213  	}
   214  	if len(instance.Properties.NetworkProfile.VirtualNetwork.StaticIpAddress) > 0 {
   215  		ip = instance.Properties.NetworkProfile.VirtualNetwork.StaticIpAddress
   216  	}
   217  	if (len(id) == 0 || len(ip) == 0) && instance.Properties.InstanceView != nil && len(instance.Properties.InstanceView.PrivateIpAddress) > 0 {
   218  		if len(id) == 0 {
   219  			id = fmt.Sprintf("%s/%s", self.ID, instance.Properties.InstanceView.PrivateIpAddress)
   220  		}
   221  		if len(ip) == 0 {
   222  			ip = instance.Properties.InstanceView.PrivateIpAddress
   223  		}
   224  	}
   225  	if len(id) > 0 && len(ip) > 0 {
   226  		instanceNic := []SClassicInstanceNic{
   227  			{instance: self, IP: ip, ID: id},
   228  		}
   229  		return instanceNic, nil
   230  	}
   231  	return nil, nil
   232  }
   233  
   234  func (self *SClassicInstance) Refresh() error {
   235  	instance, err := self.host.zone.region.GetClassicInstance(self.ID)
   236  	if err != nil {
   237  		return err
   238  	}
   239  	return jsonutils.Update(self, instance)
   240  }
   241  
   242  func (self *SClassicInstance) GetStatus() string {
   243  	if self.Properties.InstanceView == nil {
   244  		err := self.Refresh()
   245  		if err != nil {
   246  			log.Errorf("failed to get status for classic instance %s", self.Name)
   247  			return api.VM_UNKNOWN
   248  		}
   249  	}
   250  	switch self.Properties.InstanceView.Status {
   251  	case "StoppedDeallocated":
   252  		return api.VM_READY
   253  	case "ReadyRole":
   254  		return api.VM_RUNNING
   255  	case "Stopped":
   256  		return api.VM_READY
   257  	case "RoleStateUnknown":
   258  		return api.VM_UNKNOWN
   259  	default:
   260  		log.Errorf("Unknow classic instance %s status %s", self.Name, self.Properties.InstanceView.Status)
   261  		return api.VM_UNKNOWN
   262  	}
   263  }
   264  
   265  func (self *SClassicInstance) GetIHost() cloudprovider.ICloudHost {
   266  	return self.host
   267  }
   268  
   269  func (self *SClassicInstance) AttachDisk(ctx context.Context, diskId string) error {
   270  	status := self.GetStatus()
   271  	if err := self.host.zone.region.AttachDisk(self.ID, diskId); err != nil {
   272  		return err
   273  	}
   274  	return cloudprovider.WaitStatus(self, status, 10*time.Second, 300*time.Second)
   275  }
   276  
   277  func (self *SClassicInstance) DetachDisk(ctx context.Context, diskId string) error {
   278  	status := self.GetStatus()
   279  	if err := self.host.zone.region.DetachDisk(self.ID, diskId); err != nil {
   280  		return err
   281  	}
   282  	return cloudprovider.WaitStatus(self, status, 10*time.Second, 300*time.Second)
   283  }
   284  
   285  func (self *SClassicInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
   286  	return cloudprovider.ErrNotImplemented
   287  }
   288  
   289  func (self *SClassicInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
   290  	return cloudprovider.ErrNotImplemented
   291  	//return self.host.zone.region.DeployVM(self.ID, name, password, publicKey, deleteKeypair, description)
   292  }
   293  
   294  func (self *SClassicInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
   295  	return "", cloudprovider.ErrNotImplemented
   296  	//return self.host.zone.region.ReplaceSystemDisk(self.ID, imageId, passwd, publicKey, int32(sysSizeGB))
   297  }
   298  
   299  func (self *SClassicInstance) UpdateVM(ctx context.Context, name string) error {
   300  	return cloudprovider.ErrNotSupported
   301  }
   302  
   303  func (self *SClassicInstance) GetId() string {
   304  	return self.ID
   305  }
   306  
   307  func (self *SClassicInstance) GetName() string {
   308  	return self.Name
   309  }
   310  
   311  func (self *SClassicInstance) GetHostname() string {
   312  	return self.Name
   313  }
   314  
   315  func (self *SClassicInstance) GetGlobalId() string {
   316  	return strings.ToLower(self.ID)
   317  }
   318  
   319  func (self *SClassicInstance) DeleteVM(ctx context.Context) error {
   320  	if err := self.host.zone.region.DeleteVM(self.ID); err != nil {
   321  		return err
   322  	}
   323  	if self.Properties.NetworkProfile.NetworkSecurityGroup != nil {
   324  		self.host.zone.region.del(self.Properties.NetworkProfile.NetworkSecurityGroup.ID)
   325  	}
   326  	if self.Properties.DomainName != nil {
   327  		self.host.zone.region.del(self.Properties.DomainName.ID)
   328  	}
   329  	return nil
   330  }
   331  
   332  func (self *SClassicInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
   333  	disks, err := self.host.zone.region.GetClassicInstanceDisks(self.ID)
   334  	if err != nil {
   335  		return nil, errors.Wrapf(err, "GetClassicInstanceDisks")
   336  	}
   337  	ret := []cloudprovider.ICloudDisk{}
   338  	for i := range disks {
   339  		disks[i].region = self.host.zone.region
   340  		ret = append(ret, &disks[i])
   341  	}
   342  	return ret, nil
   343  }
   344  
   345  func (self *SClassicInstance) GetOsType() cloudprovider.TOsType {
   346  	return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Properties.StorageProfile.OperatingSystemDisk.OperatingSystem))
   347  }
   348  
   349  func (self *SClassicInstance) GetFullOsName() string {
   350  	return self.Properties.StorageProfile.OperatingSystemDisk.SourceImageName
   351  }
   352  
   353  func (self *SClassicInstance) GetBios() cloudprovider.TBiosType {
   354  	return cloudprovider.BIOS
   355  }
   356  
   357  func (sci *SClassicInstance) GetOsArch() string {
   358  	return apis.OS_ARCH_X86_64
   359  }
   360  
   361  func (sci *SClassicInstance) GetOsVersion() string {
   362  	return ""
   363  }
   364  
   365  func (sci *SClassicInstance) GetOsDist() string {
   366  	return ""
   367  }
   368  
   369  func (sci *SClassicInstance) GetOsLang() string {
   370  	return ""
   371  }
   372  
   373  func (self *SClassicInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
   374  	instancenics := make([]cloudprovider.ICloudNic, 0)
   375  	nics, err := self.getNics()
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  	for i := 0; i < len(nics); i++ {
   380  		nics[i].instance = self
   381  		instancenics = append(instancenics, &nics[i])
   382  	}
   383  	return instancenics, nil
   384  }
   385  
   386  func (self *SClassicInstance) GetMachine() string {
   387  	return "pc"
   388  }
   389  
   390  func (self *SClassicInstance) GetBootOrder() string {
   391  	return "dcn"
   392  }
   393  
   394  func (self *SClassicInstance) GetVga() string {
   395  	return "std"
   396  }
   397  
   398  func (self *SClassicInstance) GetVdi() string {
   399  	return "vnc"
   400  }
   401  
   402  func (self *SClassicInstance) GetVcpuCount() int {
   403  	if vmSize, ok := CLASSIC_VM_SIZES[self.Properties.HardwareProfile.Size]; ok {
   404  		return vmSize.NumberOfCores
   405  	}
   406  	log.Errorf("failed to find classic VMSize for %s", self.Properties.HardwareProfile.Size)
   407  	return 0
   408  }
   409  
   410  func (self *SClassicInstance) GetVmemSizeMB() int {
   411  	if vmSize, ok := CLASSIC_VM_SIZES[self.Properties.HardwareProfile.Size]; ok {
   412  		return vmSize.MemoryInMB
   413  	}
   414  	log.Errorf("failed to find classic VMSize for %s", self.Properties.HardwareProfile.Size)
   415  	return 0
   416  }
   417  
   418  func (self *SClassicInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
   419  	return nil, cloudprovider.ErrNotSupported
   420  }
   421  
   422  func (self *SClassicInstance) StartVM(ctx context.Context) error {
   423  	if err := self.host.zone.region.StartVM(self.ID); err != nil {
   424  		return err
   425  	}
   426  	return cloudprovider.WaitStatus(self, api.VM_RUNNING, 10*time.Second, 300*time.Second)
   427  }
   428  
   429  func (self *SClassicInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
   430  	err := self.host.zone.region.StopClassicVM(self.ID, opts.IsForce)
   431  	if err != nil {
   432  		return err
   433  	}
   434  	return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second)
   435  }
   436  
   437  func (self *SRegion) StopClassicVM(instanceId string, isForce bool) error {
   438  	_, err := self.perform(instanceId, "shutdown", nil)
   439  	return err
   440  }
   441  
   442  func (self *SClassicInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
   443  	if self.Properties.NetworkProfile.ReservedIps != nil && len(*self.Properties.NetworkProfile.ReservedIps) > 0 {
   444  		for _, reserveIp := range *self.Properties.NetworkProfile.ReservedIps {
   445  			eip, err := self.host.zone.region.GetClassicEip(reserveIp.ID)
   446  			if err == nil {
   447  				eip.instanceId = self.ID
   448  				if eip.Properties.AttachedTo != nil && eip.Properties.AttachedTo.ID != self.ID {
   449  					//一般是此实例deallocate, eip被绑到其他机器上了.
   450  					return nil, nil
   451  				}
   452  				return eip, nil
   453  			}
   454  			log.Errorf("failed find eip %s for classic instance %s", reserveIp.Name, self.Name)
   455  		}
   456  	}
   457  	if self.Properties.InstanceView != nil && len(self.Properties.InstanceView.PublicIpAddresses) > 0 {
   458  		eip := SClassicEipAddress{
   459  			region:     self.host.zone.region,
   460  			ID:         self.ID,
   461  			instanceId: self.ID,
   462  			Name:       self.Properties.InstanceView.PublicIpAddresses[0],
   463  			Properties: ClassicEipProperties{
   464  				IpAddress: self.Properties.InstanceView.PublicIpAddresses[0],
   465  			},
   466  		}
   467  		return &eip, nil
   468  	}
   469  	return nil, nil
   470  }
   471  
   472  type assignSecurityGroup struct {
   473  	ID         string           `json:"id,omitempty"`
   474  	Name       string           `json:"name,omitempty"`
   475  	Properties assignProperties `json:"properties,omitempty"`
   476  	Type       string           `json:"type,omitempty"`
   477  }
   478  
   479  type assignProperties struct {
   480  	NetworkSecurityGroup SubResource `json:"networkSecurityGroup,omitempty"`
   481  }
   482  
   483  func (self *SClassicInstance) SetSecurityGroups(secgroupIds []string) error {
   484  	return cloudprovider.ErrNotSupported
   485  }
   486  
   487  func (self *SClassicInstance) AssignSecurityGroup(secgroupId string) error {
   488  	if self.Properties.NetworkProfile.NetworkSecurityGroup != nil {
   489  		if self.Properties.NetworkProfile.NetworkSecurityGroup.ID == secgroupId {
   490  			return nil
   491  		}
   492  		self.host.zone.region.del(fmt.Sprintf("%s/associatedNetworkSecurityGroups/%s", self.ID, self.Properties.NetworkProfile.NetworkSecurityGroup.Name))
   493  	}
   494  
   495  	secgroup, err := self.host.zone.region.GetClassicSecurityGroupDetails(secgroupId)
   496  	if err != nil {
   497  		return err
   498  	}
   499  	data := assignSecurityGroup{
   500  		ID:   fmt.Sprintf("%s/associatedNetworkSecurityGroups/%s", self.ID, secgroup.Name),
   501  		Name: secgroup.Name,
   502  		Properties: assignProperties{
   503  			NetworkSecurityGroup: SubResource{
   504  				ID:   secgroup.ID,
   505  				Name: secgroup.Name,
   506  			},
   507  		},
   508  	}
   509  	return self.host.zone.region.update(jsonutils.Marshal(data), nil)
   510  }
   511  
   512  func (self *SClassicInstance) GetBillingType() string {
   513  	return billing_api.BILLING_TYPE_POSTPAID
   514  }
   515  
   516  func (self *SClassicInstance) GetCreatedAt() time.Time {
   517  	return time.Time{}
   518  }
   519  
   520  func (self *SClassicInstance) GetExpiredAt() time.Time {
   521  	return time.Time{}
   522  }
   523  
   524  func (self *SClassicInstance) UpdateUserData(userData string) error {
   525  	return cloudprovider.ErrNotSupported
   526  }
   527  
   528  func (self *SClassicInstance) Renew(bc billing.SBillingCycle) error {
   529  	return cloudprovider.ErrNotSupported
   530  }
   531  
   532  func (self *SClassicInstance) GetProjectId() string {
   533  	return getResourceGroup(self.ID)
   534  }
   535  
   536  func (self *SClassicInstance) GetError() error {
   537  	return nil
   538  }