azure.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. package guestdrivers
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/billing"
  22. "yunion.io/x/pkg/util/rbacscope"
  23. "yunion.io/x/pkg/utils"
  24. api "yunion.io/x/onecloud/pkg/apis/compute"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  26. "yunion.io/x/onecloud/pkg/compute/models"
  27. "yunion.io/x/onecloud/pkg/compute/options"
  28. "yunion.io/x/onecloud/pkg/httperrors"
  29. "yunion.io/x/onecloud/pkg/mcclient"
  30. "yunion.io/x/onecloud/pkg/mcclient/auth"
  31. modules "yunion.io/x/onecloud/pkg/mcclient/modules/image"
  32. )
  33. type SAzureGuestDriver struct {
  34. SManagedVirtualizedGuestDriver
  35. }
  36. func init() {
  37. driver := SAzureGuestDriver{}
  38. models.RegisterGuestDriver(&driver)
  39. }
  40. func (self *SAzureGuestDriver) GetHypervisor() string {
  41. return api.HYPERVISOR_AZURE
  42. }
  43. func (self *SAzureGuestDriver) GetProvider() string {
  44. return api.CLOUD_PROVIDER_AZURE
  45. }
  46. func (self *SAzureGuestDriver) GetComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
  47. keys := models.SComputeResourceKeys{}
  48. keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
  49. keys.CloudEnv = api.CLOUD_ENV_PUBLIC_CLOUD
  50. keys.Provider = api.CLOUD_PROVIDER_AZURE
  51. keys.Brand = api.CLOUD_PROVIDER_AZURE
  52. keys.Hypervisor = api.HYPERVISOR_AZURE
  53. return keys
  54. }
  55. func (self *SAzureGuestDriver) GetDefaultSysDiskBackend() string {
  56. return api.STORAGE_STANDARD_LRS
  57. }
  58. func (self *SAzureGuestDriver) GetMinimalSysDiskSizeGb() int {
  59. return 30
  60. }
  61. func (self *SAzureGuestDriver) GetStorageTypes() []string {
  62. return []string{
  63. api.STORAGE_STANDARD_LRS,
  64. api.STORAGE_STANDARDSSD_LRS,
  65. api.STORAGE_PREMIUM_LRS,
  66. }
  67. }
  68. func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, guest *models.SGuest, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
  69. return chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil
  70. }
  71. func (self *SAzureGuestDriver) GetMaxSecurityGroupCount() int {
  72. return 1
  73. }
  74. func (self *SAzureGuestDriver) GetDetachDiskStatus() ([]string, error) {
  75. return []string{api.VM_READY, api.VM_RUNNING}, nil
  76. }
  77. func (self *SAzureGuestDriver) GetAttachDiskStatus() ([]string, error) {
  78. return []string{api.VM_READY, api.VM_RUNNING}, nil
  79. }
  80. func (self *SAzureGuestDriver) GetRebuildRootStatus() ([]string, error) {
  81. return []string{api.VM_READY, api.VM_RUNNING}, nil
  82. }
  83. func (self *SAzureGuestDriver) IsRebuildRootSupportChangeUEFI() bool {
  84. return false
  85. }
  86. func (self *SAzureGuestDriver) GetChangeInstanceTypeStatus() ([]string, error) {
  87. return []string{api.VM_READY, api.VM_RUNNING}, nil
  88. }
  89. func (self *SAzureGuestDriver) GetDeployStatus() ([]string, error) {
  90. return []string{api.VM_RUNNING}, nil
  91. }
  92. func (self *SAzureGuestDriver) IsNeedRestartForResetLoginInfo() bool {
  93. return false
  94. }
  95. func (self *SAzureGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
  96. //https://docs.microsoft.com/en-us/rest/api/compute/disks/update
  97. //Resizes are only allowed if the disk is not attached to a running VM, and can only increase the disk's size
  98. if !utils.IsInStringArray(guest.Status, []string{api.VM_READY, api.VM_START_RESIZE_DISK, api.VM_RESIZE_DISK}) {
  99. return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
  100. }
  101. return nil
  102. }
  103. func (self *SAzureGuestDriver) ValidateImage(ctx context.Context, image *cloudprovider.SImage) error {
  104. if len(image.ExternalId) == 0 {
  105. s := auth.GetAdminSession(ctx, options.Options.Region)
  106. result, err := modules.Images.GetSpecific(s, image.Id, "subformats", nil)
  107. if err != nil {
  108. return errors.Wrap(err, "get subformats")
  109. }
  110. subFormats := []struct {
  111. Format string
  112. }{}
  113. err = result.Unmarshal(&subFormats)
  114. if err != nil {
  115. return errors.Wrap(err, "Unmarshal subformats")
  116. }
  117. for i := range subFormats {
  118. if subFormats[i].Format == "vhd" {
  119. return nil
  120. }
  121. }
  122. return httperrors.NewResourceNotFoundError("failed to find subformat vhd for image %s, please append 'vhd' for glance options(target_image_formats)", image.Name)
  123. }
  124. return nil
  125. }
  126. func (self *SAzureGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  127. input, err := self.SManagedVirtualizedGuestDriver.ValidateCreateData(ctx, userCred, input)
  128. if err != nil {
  129. return nil, err
  130. }
  131. if len(input.Networks) > 2 {
  132. return nil, httperrors.NewInputParameterError("cannot support more than 1 nic")
  133. }
  134. if len(input.Disks) > 0 && len(input.Disks[0].ImageId) > 0 {
  135. _image, err := models.CachedimageManager.FetchById(input.Disks[0].ImageId)
  136. if err != nil {
  137. return nil, errors.Wrap(err, "FetchById")
  138. }
  139. cachedimage := _image.(*models.SCachedimage)
  140. image, err := cachedimage.GetImage()
  141. if err != nil {
  142. return nil, errors.Wrap(err, "GetImage")
  143. }
  144. err = self.ValidateImage(ctx, image)
  145. if err != nil {
  146. return nil, err
  147. }
  148. if len(image.ExternalId) > 0 && len(input.InstanceType) > 0 {
  149. if cachedimage.UEFI.IsFalse() {
  150. if strings.HasPrefix(input.InstanceType, "Standard_M") && strings.HasSuffix(input.InstanceType, "v2") {
  151. return nil, httperrors.NewNotSupportedError("Azure Mv2-series instance sku only support UEFI image")
  152. }
  153. } else {
  154. // https://docs.microsoft.com/en-us/azure/virtual-machines/windows/generation-2
  155. if !(strings.HasPrefix(input.InstanceType, "Standard_B") || // B-series
  156. (strings.HasPrefix(input.InstanceType, "Standard_DC") && strings.HasSuffix(input.InstanceType, "s_v2") || input.InstanceType == "Standard_DC8_v2") || // DCsv2-series
  157. (strings.HasPrefix(input.InstanceType, "Standard_DS") && strings.HasSuffix(input.InstanceType, "v2")) || // DSv2-series
  158. (strings.HasPrefix(input.InstanceType, "Standard_DS") && strings.HasSuffix(input.InstanceType, "s_v3")) || // Dsv3-series
  159. (strings.HasPrefix(input.InstanceType, "Standard_D") && strings.HasSuffix(input.InstanceType, "as_v4")) || // Dasv4-series
  160. (strings.HasPrefix(input.InstanceType, "Standard_E") && strings.HasSuffix(input.InstanceType, "s_v3")) || // Esv3-series
  161. (strings.HasPrefix(input.InstanceType, "Standard_E") && strings.HasSuffix(input.InstanceType, "as_v4")) || // Easv4-series
  162. (strings.HasPrefix(input.InstanceType, "Standard_F") && strings.HasSuffix(input.InstanceType, "s_v2")) || // Fsv2-series
  163. (strings.HasPrefix(input.InstanceType, "Standard_GS")) || // GS-series
  164. (strings.HasPrefix(input.InstanceType, "Standard_HB")) || // HB-series
  165. (strings.HasPrefix(input.InstanceType, "Standard_HC")) || // HC-series
  166. (strings.HasPrefix(input.InstanceType, "Standard_L") && strings.HasSuffix(input.InstanceType, "s")) || // Ls-series
  167. (strings.HasPrefix(input.InstanceType, "Standard_L") && strings.HasSuffix(input.InstanceType, "s_v2")) || // Ls-series
  168. (strings.HasPrefix(input.InstanceType, "Standard_M")) || // M-series
  169. (strings.HasPrefix(input.InstanceType, "Standard_M") && strings.HasSuffix(input.InstanceType, "s_v2")) || // Mv2-series
  170. (strings.HasPrefix(input.InstanceType, "Standard_NC") && strings.HasSuffix(input.InstanceType, "s_v2")) || // NCv2-series
  171. (strings.HasPrefix(input.InstanceType, "Standard_NC") && strings.HasSuffix(input.InstanceType, "s_v3")) || // NCv3-series
  172. (strings.HasPrefix(input.InstanceType, "Standard_ND")) || // ND-series
  173. (strings.HasPrefix(input.InstanceType, "Standard_NV") && strings.HasSuffix(input.InstanceType, "s_v3"))) { // NVv3-series
  174. return nil, httperrors.NewUnsupportOperationError("Azure UEFI image %s not support this instance sku", image.Name)
  175. }
  176. }
  177. }
  178. }
  179. return input, nil
  180. }
  181. func (self *SAzureGuestDriver) GetGuestInitialStateAfterCreate() string {
  182. return api.VM_RUNNING
  183. }
  184. func (self *SAzureGuestDriver) GetGuestInitialStateAfterRebuild() string {
  185. return api.VM_READY
  186. }
  187. func (self *SAzureGuestDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
  188. return cloudprovider.SInstanceCapability{
  189. Hypervisor: self.GetHypervisor(),
  190. Provider: self.GetProvider(),
  191. DefaultAccount: cloudprovider.SDefaultAccount{
  192. Linux: cloudprovider.SOsDefaultAccount{
  193. DefaultAccount: api.VM_AZURE_DEFAULT_LOGIN_USER,
  194. Changeable: false,
  195. },
  196. Windows: cloudprovider.SOsDefaultAccount{
  197. // Administrator 为Azure保留用户,不能使用
  198. DefaultAccount: api.VM_AZURE_DEFAULT_LOGIN_USER,
  199. Changeable: false,
  200. },
  201. },
  202. Storages: cloudprovider.Storage{
  203. DataDisk: []cloudprovider.StorageInfo{
  204. cloudprovider.StorageInfo{StorageType: api.STORAGE_STANDARDSSD_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  205. cloudprovider.StorageInfo{StorageType: api.STORAGE_STANDARD_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  206. cloudprovider.StorageInfo{StorageType: api.STORAGE_PREMIUM_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  207. },
  208. SysDisk: []cloudprovider.StorageInfo{
  209. cloudprovider.StorageInfo{StorageType: api.STORAGE_STANDARDSSD_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  210. cloudprovider.StorageInfo{StorageType: api.STORAGE_STANDARD_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  211. cloudprovider.StorageInfo{StorageType: api.STORAGE_PREMIUM_LRS, MaxSizeGb: 32767, MinSizeGb: 1, StepSizeGb: 1, Resizable: false},
  212. },
  213. },
  214. }
  215. }
  216. func (self *SAzureGuestDriver) GetDefaultAccount(osType, osDist, imageType string) string {
  217. return api.VM_AZURE_DEFAULT_LOGIN_USER
  218. }
  219. func (self *SAzureGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
  220. return false
  221. }