managedvirtual.go 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713
  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. "math"
  19. "strings"
  20. "sync"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/gotypes"
  27. "yunion.io/x/pkg/util/billing"
  28. "yunion.io/x/pkg/util/pinyinutils"
  29. "yunion.io/x/pkg/utils"
  30. "yunion.io/x/sqlchemy"
  31. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  32. api "yunion.io/x/onecloud/pkg/apis/compute"
  33. image_api "yunion.io/x/onecloud/pkg/apis/image"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  38. "yunion.io/x/onecloud/pkg/compute/models"
  39. "yunion.io/x/onecloud/pkg/compute/options"
  40. "yunion.io/x/onecloud/pkg/httperrors"
  41. "yunion.io/x/onecloud/pkg/mcclient"
  42. "yunion.io/x/onecloud/pkg/mcclient/auth"
  43. img "yunion.io/x/onecloud/pkg/mcclient/modules/image"
  44. "yunion.io/x/onecloud/pkg/util/logclient"
  45. )
  46. type SManagedVirtualizedGuestDriver struct {
  47. SVirtualizedGuestDriver
  48. }
  49. func (d SManagedVirtualizedGuestDriver) DoScheduleCPUFilter() bool { return false }
  50. func (d SManagedVirtualizedGuestDriver) DoScheduleSKUFilter() bool { return true }
  51. func (d SManagedVirtualizedGuestDriver) DoScheduleMemoryFilter() bool { return false }
  52. func (d SManagedVirtualizedGuestDriver) DoScheduleStorageFilter() bool { return false }
  53. func (d SManagedVirtualizedGuestDriver) DoScheduleCloudproviderTagFilter() bool { return true }
  54. func (drv *SManagedVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, params *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
  55. driver, err := guest.GetDriver()
  56. if err != nil {
  57. return nil, err
  58. }
  59. config := cloudprovider.SManagedVMCreateConfig{
  60. IsNeedInjectPasswordByCloudInit: driver.IsNeedInjectPasswordByCloudInit(),
  61. UserDataType: driver.GetUserDataType(),
  62. WindowsUserDataType: driver.GetWindowsUserDataType(),
  63. IsWindowsUserDataTypeNeedEncode: driver.IsWindowsUserDataTypeNeedEncode(),
  64. }
  65. config.Name = guest.Name
  66. config.NameEn = pinyinutils.Text2Pinyin(guest.Name)
  67. config.Hostname = guest.Hostname
  68. config.Cpu = int(guest.VcpuCount)
  69. config.MemoryMB = guest.VmemSize
  70. config.UserData = guest.GetUserData(ctx, userCred)
  71. config.Description = guest.Description
  72. config.EnableMonitorAgent = options.Options.EnableMonitorAgent
  73. if params != nil {
  74. params.Unmarshal(&config.SPublicIpInfo)
  75. }
  76. config.InstanceType = guest.InstanceType
  77. if len(guest.KeypairId) > 0 {
  78. keypair := guest.GetKeypair()
  79. if keypair != nil {
  80. config.PublicKey = keypair.PublicKey
  81. config.KeypairName = keypair.Name
  82. }
  83. }
  84. nics, _ := guest.GetNetworks("")
  85. if len(nics) > 0 {
  86. net, err := nics[0].GetNetwork()
  87. if err != nil {
  88. return nil, errors.Wrapf(err, "GetNetwork")
  89. }
  90. config.ExternalNetworkId = net.ExternalId
  91. vpc, err := net.GetVpc()
  92. if err == nil {
  93. config.ExternalVpcId = vpc.ExternalId
  94. }
  95. config.IpAddr = nics[0].IpAddr
  96. }
  97. provider := host.GetCloudprovider()
  98. config.ProjectId, err = provider.SyncProject(ctx, userCred, guest.ProjectId)
  99. if err != nil {
  100. if errors.Cause(err) != cloudprovider.ErrNotSupported && errors.Cause(err) != cloudprovider.ErrNotImplemented {
  101. logclient.AddSimpleActionLog(guest, logclient.ACT_SYNC_CLOUD_PROJECT, err, userCred, false)
  102. }
  103. }
  104. disks, err := guest.GetDisks()
  105. if err != nil {
  106. return nil, errors.Wrapf(err, "GetDisks")
  107. }
  108. config.DataDisks = []cloudprovider.SDiskInfo{}
  109. for i := 0; i < len(disks); i += 1 {
  110. disk := disks[i]
  111. storage, _ := disk.GetStorage()
  112. if i == 0 {
  113. config.SysDisk.Name = disk.Name
  114. config.SysDisk.StorageExternalId = storage.ExternalId
  115. config.SysDisk.StorageType = storage.StorageType
  116. config.SysDisk.SizeGB = int(math.Ceil(float64(disk.DiskSize) / 1024))
  117. config.SysDisk.Iops = disk.Iops
  118. config.SysDisk.Throughput = disk.Throughput
  119. if gds, err := disk.GetGuestDisk(); err == nil {
  120. config.SysDisk.Driver = gds.Driver
  121. config.SysDisk.CacheMode = gds.CacheMode
  122. }
  123. cache := storage.GetStoragecache()
  124. imageId := disk.GetTemplateId()
  125. //避免因同步过来的instance没有对应的imagecache信息,重置密码时引发空指针访问
  126. if len(imageId) == 0 {
  127. if cdrom := guest.GetCdrom(); cdrom != nil {
  128. imageId = cdrom.ImageId
  129. }
  130. }
  131. if scimg := models.StoragecachedimageManager.GetStoragecachedimage(cache.Id, imageId); scimg != nil {
  132. config.ExternalImageId = scimg.ExternalId
  133. img := scimg.GetCachedimage()
  134. config.OsDistribution, _ = img.Info.GetString("properties", "os_distribution")
  135. config.OsVersion, _ = img.Info.GetString("properties", "os_version")
  136. config.OsType, _ = img.Info.GetString("properties", "os_type")
  137. config.ImageType = img.ImageType
  138. }
  139. } else {
  140. dataDisk := cloudprovider.SDiskInfo{
  141. SizeGB: disk.DiskSize / 1024,
  142. StorageType: storage.StorageType,
  143. StorageExternalId: storage.ExternalId,
  144. Iops: disk.Iops,
  145. Throughput: disk.Throughput,
  146. Name: disk.Name,
  147. }
  148. if gds, err := disk.GetGuestDisk(); err == nil {
  149. dataDisk.Driver = gds.Driver
  150. dataDisk.CacheMode = gds.CacheMode
  151. }
  152. config.DataDisks = append(config.DataDisks, dataDisk)
  153. }
  154. }
  155. if len(config.ExternalImageId) == 0 {
  156. image, err := func() (*models.SCachedimage, error) {
  157. cdrom := guest.GetCdrom()
  158. if cdrom == nil {
  159. return nil, fmt.Errorf("empty cdrom")
  160. }
  161. return cdrom.GetImage()
  162. }()
  163. if err != nil {
  164. log.Errorf("get cachdimage error: %v", err)
  165. } else {
  166. config.ExternalImageId = image.ExternalId
  167. config.OsDistribution, _ = image.Info.GetString("properties", "os_distribution")
  168. config.OsVersion, _ = image.Info.GetString("properties", "os_version")
  169. config.OsType, _ = image.Info.GetString("properties", "os_type")
  170. config.ImageType = image.ImageType
  171. }
  172. }
  173. // 避免因同步包年包月实例billing_cycle失败,导致重置虚拟机密码异常
  174. if guest.BillingType == billing_api.BILLING_TYPE_PREPAID && len(guest.BillingCycle) > 0 {
  175. bc, err := billing.ParseBillingCycle(guest.BillingCycle)
  176. if err != nil {
  177. return nil, errors.Wrapf(err, "ParseBillingCycle(%s)", guest.BillingCycle)
  178. }
  179. if bc.IsValid() {
  180. bc.AutoRenew = guest.AutoRenew
  181. config.BillingCycle = &bc
  182. }
  183. }
  184. return jsonutils.Marshal(&config), nil
  185. }
  186. func (drv *SManagedVirtualizedGuestDriver) RequestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, task taskman.ITask) error {
  187. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  188. iVm, err := guest.GetIVM(ctx)
  189. if err != nil {
  190. return nil, errors.Wrapf(err, "guest.GetIVM")
  191. }
  192. input := &api.DiskSaveInput{}
  193. err = task.GetParams().Unmarshal(input)
  194. if err != nil {
  195. return nil, errors.Wrapf(err, "Unmarshal")
  196. }
  197. opts := &cloudprovider.SaveImageOptions{
  198. Name: input.Name,
  199. }
  200. image, err := iVm.SaveImage(opts)
  201. if err != nil {
  202. return nil, errors.Wrapf(err, "iVm.SaveImage")
  203. }
  204. err = cloudprovider.WaitStatus(image, cloudprovider.IMAGE_STATUS_ACTIVE, time.Second*10, time.Minute*10)
  205. if err != nil {
  206. return nil, errors.Wrapf(err, "wait image %s(%s) active current is: %s", image.GetName(), image.GetGlobalId(), image.GetStatus())
  207. }
  208. if options.Options.SaveCloudImageToGlance {
  209. exports, err := image.Export(&cloudprovider.SImageExportOptions{})
  210. if err != nil {
  211. if errors.Cause(err) != cloudprovider.ErrNotImplemented && errors.Cause(err) != cloudprovider.ErrNotSupported {
  212. logclient.AddSimpleActionLog(guest, logclient.ACT_SAVE_IMAGE, errors.Wrapf(err, "Export"), userCred, false)
  213. }
  214. }
  215. osProfile := guest.GetOSProfile()
  216. s := auth.GetSession(ctx, userCred, options.Options.Region)
  217. var wg sync.WaitGroup
  218. for _, export := range exports {
  219. wg.Add(1)
  220. go func(export cloudprovider.SImageExportInfo) {
  221. defer wg.Done()
  222. params := map[string]string{
  223. "name": export.Name,
  224. "os_type": osProfile.OSType,
  225. "copy_from": export.DownloadUrl,
  226. "compress_format": export.CompressFormat,
  227. }
  228. localImage, err := img.Images.Create(s, jsonutils.Marshal(params))
  229. if err != nil {
  230. log.Errorf("create image error: %v", err)
  231. return
  232. }
  233. imageId, err := localImage.GetString("id")
  234. if err != nil {
  235. return
  236. }
  237. info := &image_api.ImageDetails{}
  238. for {
  239. localImage, err = img.Images.Get(s, imageId, jsonutils.Marshal(map[string]string{"scope": "system"}))
  240. if err != nil {
  241. break
  242. }
  243. localImage.Unmarshal(info)
  244. log.Debugf("save image %s(%s) status: %s", info.Name, info.Id, info.Status)
  245. if utils.IsInStringArray(info.Status, []string{
  246. image_api.IMAGE_STATUS_ACTIVE,
  247. image_api.IMAGE_STATUS_KILLED,
  248. image_api.IMAGE_STATUS_SAVE_FAIL,
  249. }) {
  250. break
  251. }
  252. time.Sleep(time.Second * 20)
  253. }
  254. }(export)
  255. }
  256. wg.Wait()
  257. }
  258. host, err := guest.GetHost()
  259. if err != nil {
  260. return nil, errors.Wrapf(err, "GetHost")
  261. }
  262. region, err := host.GetRegion()
  263. if err != nil {
  264. return nil, errors.Wrapf(err, "GetRegion")
  265. }
  266. iRegion, err := host.GetIRegion(ctx)
  267. if err != nil {
  268. return nil, errors.Wrapf(err, "host.GetIRegion")
  269. }
  270. caches, err := region.GetStoragecaches()
  271. if err != nil {
  272. return nil, errors.Wrapf(err, "region.GetStoragecaches")
  273. }
  274. for i := range caches {
  275. if caches[i].ManagerId == host.ManagerId {
  276. iStoragecache, err := iRegion.GetIStoragecacheById(caches[i].ExternalId)
  277. if err != nil {
  278. return nil, errors.Wrapf(err, "iRegion.GetIStoragecacheById(%s)", caches[i].ExternalId)
  279. }
  280. result := caches[i].SyncCloudImages(ctx, userCred, iStoragecache, region, true)
  281. log.Infof("sync cloud image for storagecache %s result: %s", caches[i].Name, result.Result())
  282. }
  283. }
  284. return nil, nil
  285. })
  286. return nil
  287. }
  288. func (drv *SManagedVirtualizedGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  289. diskCat := guest.CategorizeDisks()
  290. var imageId string
  291. if diskCat.Root != nil {
  292. imageId = diskCat.Root.GetTemplateId()
  293. }
  294. if len(imageId) == 0 {
  295. task.ScheduleRun(nil)
  296. return nil
  297. }
  298. storage, _ := diskCat.Root.GetStorage()
  299. if storage == nil {
  300. return fmt.Errorf("no valid storage")
  301. }
  302. storageCache := storage.GetStoragecache()
  303. if storageCache == nil {
  304. return fmt.Errorf("no valid storage cache")
  305. }
  306. input := api.CacheImageInput{
  307. ImageId: imageId,
  308. Format: diskCat.Root.DiskFormat,
  309. ParentTaskId: task.GetTaskId(),
  310. ServerId: guest.Id,
  311. }
  312. return storageCache.StartImageCacheTask(ctx, task.GetUserCred(), input)
  313. }
  314. func (drv *SManagedVirtualizedGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  315. if input.Cdrom != "" {
  316. return nil, httperrors.NewInputParameterError("%s not support cdrom params", input.Hypervisor)
  317. }
  318. var vpc *models.SVpc = nil
  319. for _, network := range input.Networks {
  320. netObj, err := validators.ValidateModel(ctx, userCred, models.NetworkManager, &network.Network)
  321. if err == nil {
  322. net := netObj.(*models.SNetwork)
  323. vpc, err = net.GetVpc()
  324. if err != nil {
  325. return nil, errors.Wrapf(err, "GetVpc")
  326. }
  327. }
  328. }
  329. for i := range input.Secgroups {
  330. if input.Secgroups[i] == api.SECGROUP_DEFAULT_ID {
  331. continue
  332. }
  333. if gotypes.IsNil(vpc) {
  334. return nil, httperrors.NewMissingParameterError("nets")
  335. }
  336. secObj, err := validators.ValidateModel(ctx, userCred, models.SecurityGroupManager, &input.Secgroups[i])
  337. if err != nil {
  338. return nil, err
  339. }
  340. secgroup := secObj.(*models.SSecurityGroup)
  341. err = vpc.CheckSecurityGroupConsistent(secgroup)
  342. if err != nil {
  343. return nil, err
  344. }
  345. }
  346. return input, nil
  347. }
  348. func (drv *SManagedVirtualizedGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
  349. return nil
  350. }
  351. func (drv *SManagedVirtualizedGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, disk *models.SDisk, task taskman.ITask) error {
  352. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  353. iVM, err := guest.GetIVM(ctx)
  354. if err != nil {
  355. //若guest被删除,忽略错误,否则会无限删除guest失败(有挂载的云盘)
  356. if errors.Cause(err) == cloudprovider.ErrNotFound {
  357. return nil, nil
  358. }
  359. return nil, errors.Wrapf(err, "guest.GetIVM")
  360. }
  361. if len(disk.ExternalId) == 0 {
  362. return nil, nil
  363. }
  364. _, err = disk.GetIDisk(ctx)
  365. if errors.Cause(err) == cloudprovider.ErrNotFound {
  366. //忽略云上磁盘已经被删除错误
  367. return nil, nil
  368. }
  369. err = iVM.DetachDisk(ctx, disk.ExternalId)
  370. if err != nil {
  371. return nil, errors.Wrapf(err, "iVM.DetachDisk")
  372. }
  373. err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) {
  374. err := iVM.Refresh()
  375. if err != nil {
  376. return false, errors.Wrapf(err, "iVM.Refresh")
  377. }
  378. iDisks, err := iVM.GetIDisks()
  379. if err != nil {
  380. return false, errors.Wrapf(err, "RequestDetachDisk.iVM.GetIDisks")
  381. }
  382. exist := false
  383. for i := 0; i < len(iDisks); i++ {
  384. if iDisks[i].GetGlobalId() == disk.ExternalId {
  385. exist = true
  386. }
  387. }
  388. if !exist {
  389. return true, nil
  390. }
  391. return false, nil
  392. })
  393. if err != nil {
  394. return nil, errors.Wrapf(err, "RequestDetachDisk.Wait")
  395. }
  396. return nil, nil
  397. })
  398. return nil
  399. }
  400. func (drv *SManagedVirtualizedGuestDriver) RequestAttachDisk(ctx context.Context, guest *models.SGuest, disk *models.SDisk, task taskman.ITask) error {
  401. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  402. iVM, err := guest.GetIVM(ctx)
  403. if err != nil {
  404. return nil, errors.Wrapf(err, "guest.GetIVM")
  405. }
  406. if len(disk.ExternalId) == 0 {
  407. return nil, fmt.Errorf("disk %s(%s) is not a managed resource", disk.Name, disk.Id)
  408. }
  409. err = iVM.AttachDisk(ctx, disk.ExternalId)
  410. if err != nil {
  411. return nil, errors.Wrapf(err, "iVM.AttachDisk")
  412. }
  413. err = cloudprovider.Wait(time.Second*10, time.Minute*6, func() (bool, error) {
  414. err := iVM.Refresh()
  415. if err != nil {
  416. return false, errors.Wrapf(err, "iVM.Refresh")
  417. }
  418. iDisks, err := iVM.GetIDisks()
  419. if err != nil {
  420. return false, errors.Wrapf(err, "RequestAttachDisk.iVM.GetIDisks")
  421. }
  422. for i := 0; i < len(iDisks); i++ {
  423. if iDisks[i].GetGlobalId() == disk.ExternalId {
  424. err := cloudprovider.WaitStatus(iDisks[i], api.DISK_READY, 5*time.Second, 60*time.Second)
  425. if err != nil {
  426. return false, errors.Wrapf(err, "RequestAttachDisk.iVM.WaitStatus")
  427. }
  428. if device := iDisks[i].GetDeviceName(); len(device) > 0 {
  429. db.Update(disk, func() error {
  430. disk.Device = device
  431. return nil
  432. })
  433. }
  434. return true, nil
  435. }
  436. }
  437. return false, nil
  438. })
  439. if err != nil {
  440. return nil, errors.Wrapf(err, "RequestAttachDisk.Wait")
  441. }
  442. return nil, nil
  443. })
  444. return nil
  445. }
  446. func (drv *SManagedVirtualizedGuestDriver) RequestStartOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) error {
  447. ivm, err := guest.GetIVM(ctx)
  448. if err != nil {
  449. return errors.Wrapf(err, "GetIVM")
  450. }
  451. result := jsonutils.NewDict()
  452. if ivm.GetStatus() != api.VM_RUNNING {
  453. if guest.BillingType == billing_api.BILLING_TYPE_POSTPAID && guest.ShutdownMode != api.VM_SHUTDOWN_MODE_STOP_CHARGING && jsonutils.QueryBoolean(task.GetParams(), "auto_prepaid", false) {
  454. err = ivm.ChangeBillingType(string(billing_api.BILLING_TYPE_PREPAID))
  455. if err != nil && errors.Cause(err) != cloudprovider.ErrNotImplemented {
  456. logclient.AddSimpleActionLog(guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, string(billing_api.BILLING_TYPE_PREPAID)), userCred, false)
  457. }
  458. }
  459. err := ivm.StartVM(ctx)
  460. if err != nil {
  461. return errors.Wrapf(err, "StartVM")
  462. }
  463. err = cloudprovider.WaitStatus(ivm, api.VM_RUNNING, time.Second*5, time.Minute*10)
  464. if err != nil {
  465. return errors.Wrapf(err, "Wait vm running")
  466. }
  467. if guest.BillingType == billing_api.BILLING_TYPE_POSTPAID && guest.ShutdownMode == api.VM_SHUTDOWN_MODE_STOP_CHARGING && jsonutils.QueryBoolean(task.GetParams(), "auto_prepaid", false) {
  468. err := ivm.ChangeBillingType(string(billing_api.BILLING_TYPE_PREPAID))
  469. if err != nil && errors.Cause(err) != cloudprovider.ErrNotImplemented {
  470. logclient.AddSimpleActionLog(guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, string(billing_api.BILLING_TYPE_PREPAID)), userCred, false)
  471. }
  472. }
  473. // 虚拟机开机,公网ip自动生成
  474. guest.SyncAllWithCloudVM(ctx, userCred, host, ivm, true)
  475. return task.ScheduleRun(result)
  476. }
  477. return guest.SetStatus(ctx, userCred, api.VM_RUNNING, "StartOnHost")
  478. }
  479. func (drv *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  480. config, err := guest.GetDeployConfigOnHost(ctx, task.GetUserCred(), host, task.GetParams())
  481. if err != nil {
  482. return errors.Wrapf(err, "GetDeployConfigOnHost")
  483. }
  484. log.Debugf("RequestDeployGuestOnHost: %s", config)
  485. desc := cloudprovider.SManagedVMCreateConfig{}
  486. desc.Description = guest.Description
  487. // 账号必须在desc.GetConfig()之前设置,避免默认用户不能正常注入
  488. osInfo := struct {
  489. OsType string
  490. OsDistribution string
  491. ImageType string
  492. }{}
  493. config.Unmarshal(&osInfo, "desc")
  494. driver, err := guest.GetDriver()
  495. if err != nil {
  496. return err
  497. }
  498. desc.Account = driver.GetDefaultAccount(osInfo.OsType, osInfo.OsDistribution, osInfo.ImageType)
  499. err = desc.GetConfig(config)
  500. if err != nil {
  501. return errors.Wrapf(err, "desc.GetConfig")
  502. }
  503. desc.Tags, _ = guest.GetAllUserMetadata()
  504. desc.UserData, err = desc.GetUserData()
  505. if err != nil {
  506. return errors.Wrapf(err, "GetUserData")
  507. }
  508. action, err := config.GetString("action")
  509. if err != nil {
  510. return err
  511. }
  512. ihost, err := host.GetIHost(ctx)
  513. if err != nil {
  514. return err
  515. }
  516. region, err := host.GetRegion()
  517. if err != nil {
  518. return errors.Wrapf(err, "GetRegion")
  519. }
  520. switch action {
  521. case "create":
  522. if len(desc.InstanceType) == 0 && region != nil && utils.IsInStringArray(region.Provider, api.PUBLIC_CLOUD_PROVIDERS) {
  523. sku, err := models.ServerSkuManager.GetMatchedSku(region.GetId(), int64(desc.Cpu), int64(desc.MemoryMB))
  524. if err != nil {
  525. return errors.Wrap(err, "ManagedVirtualizedGuestDriver.RequestDeployGuestOnHost.GetMatchedSku")
  526. }
  527. if sku == nil {
  528. return errors.Wrap(errors.ErrNotFound, "ManagedVirtualizedGuestDriver.RequestDeployGuestOnHost.GetMatchedSku")
  529. }
  530. desc.InstanceType = sku.Name
  531. }
  532. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  533. return driver.RemoteDeployGuestForCreate(ctx, task.GetUserCred(), guest, host, desc)
  534. })
  535. case "deploy":
  536. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  537. return driver.RemoteDeployGuestForDeploy(ctx, guest, ihost, task, desc)
  538. })
  539. case "rebuild":
  540. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  541. return driver.RemoteDeployGuestForRebuildRoot(ctx, guest, ihost, task, desc)
  542. })
  543. default:
  544. log.Errorf("RequestDeployGuestOnHost: Action %s not supported", action)
  545. return fmt.Errorf("Action %s not supported", action)
  546. }
  547. return nil
  548. }
  549. func (drv *SManagedVirtualizedGuestDriver) GetGuestInitialStateAfterCreate() string {
  550. return api.VM_READY
  551. }
  552. func (drv *SManagedVirtualizedGuestDriver) GetGuestInitialStateAfterRebuild() string {
  553. return api.VM_READY
  554. }
  555. func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestForCreate(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, desc cloudprovider.SManagedVMCreateConfig) (jsonutils.JSONObject, error) {
  556. ihost, err := host.GetIHost(ctx)
  557. if err != nil {
  558. return nil, errors.Wrapf(err, "RemoteDeployGuestForCreate.GetIHost")
  559. }
  560. secgroups, err := guest.GetSecgroups()
  561. if err != nil {
  562. return nil, errors.Wrap(err, "GetSecgroups")
  563. }
  564. desc.ExternalSecgroupIds = []string{}
  565. for _, secgroup := range secgroups {
  566. if len(secgroup.ExternalId) > 0 {
  567. desc.ExternalSecgroupIds = append(desc.ExternalSecgroupIds, secgroup.ExternalId)
  568. }
  569. }
  570. devs, err := guest.GetIsolatedDevices()
  571. if err != nil {
  572. return nil, errors.Wrapf(err, "GetIsolatedDevices")
  573. }
  574. desc.IsolateDevices = []cloudprovider.SIsolateDevice{}
  575. for _, dev := range devs {
  576. desc.IsolateDevices = append(desc.IsolateDevices, cloudprovider.SIsolateDevice{
  577. Id: dev.ExternalId,
  578. Name: dev.Name,
  579. })
  580. }
  581. desc.KsyunPostpaidChargeType = options.Options.KsyunPostpaidChargeType
  582. var iVM cloudprovider.ICloudVM = nil
  583. iVM, err = func() (cloudprovider.ICloudVM, error) {
  584. lockman.LockObject(ctx, guest)
  585. defer lockman.ReleaseObject(ctx, guest)
  586. tryCnt := 0
  587. iVM, err = func() (cloudprovider.ICloudVM, error) {
  588. iVM, err = ihost.CreateVM(&desc)
  589. if err == nil || !options.Options.EnableAutoSwitchServerSku {
  590. return iVM, err
  591. }
  592. if errors.Cause(err) != cloudprovider.ErrInvalidSku {
  593. return iVM, err
  594. }
  595. skus, e := models.ServerSkuManager.GetSkus(host.GetProviderName(), guest.VcpuCount, guest.VmemSize)
  596. if e != nil {
  597. return iVM, errors.Wrapf(e, "GetSkus")
  598. }
  599. oldSku := desc.InstanceType
  600. for i := range skus {
  601. if skus[i].Name != oldSku && len(skus[i].Name) > 0 {
  602. desc.InstanceType = skus[i].Name
  603. log.Infof("try switch server sku from %s to %s for create %s", oldSku, desc.InstanceType, guest.Name)
  604. iVM, err = ihost.CreateVM(&desc)
  605. if err == nil {
  606. db.Update(guest, func() error {
  607. guest.InstanceType = desc.InstanceType
  608. return nil
  609. })
  610. return iVM, nil
  611. }
  612. log.Errorf("use sku %s error: %v", desc.InstanceType, err)
  613. tryCnt++
  614. }
  615. }
  616. return iVM, err
  617. }()
  618. if err != nil {
  619. return nil, errors.Wrapf(err, "After try %d skus", tryCnt)
  620. }
  621. db.SetExternalId(guest, userCred, iVM.GetGlobalId())
  622. return iVM, nil
  623. }()
  624. if err != nil {
  625. return nil, err
  626. }
  627. driver, err := guest.GetDriver()
  628. if err != nil {
  629. return nil, err
  630. }
  631. // iVM 实际所在的ihost 可能和 调度选择的host不是同一个,此处根据iVM实际所在host,重新同步
  632. ihost, err = driver.RemoteDeployGuestSyncHost(ctx, userCred, guest, host, iVM)
  633. if err != nil {
  634. return nil, errors.Wrap(err, "RemoteDeployGuestSyncHost")
  635. }
  636. vmId := iVM.GetGlobalId()
  637. initialState := driver.GetGuestInitialStateAfterCreate()
  638. log.Debugf("VMcreated %s, wait status %s ...", vmId, initialState)
  639. err = cloudprovider.WaitStatusWithInstanceErrorCheck(iVM, initialState, time.Second*5, time.Second*1800, func() error {
  640. return iVM.GetError()
  641. })
  642. if err != nil {
  643. return nil, err
  644. }
  645. log.Debugf("VMcreated %s, and status is running", vmId)
  646. iVM, err = ihost.GetIVMById(vmId)
  647. if err != nil {
  648. return nil, errors.Wrapf(err, "GetIVMById(%s)", vmId)
  649. }
  650. if driver.GetMaxSecurityGroupCount() > 0 {
  651. err = iVM.SetSecurityGroups(desc.ExternalSecgroupIds)
  652. if err != nil {
  653. return nil, errors.Wrapf(err, "SetSecurityGroups")
  654. }
  655. }
  656. ret, expect, eipSync := 0, len(desc.DataDisks)+1, false
  657. err = cloudprovider.RetryUntil(func() (bool, error) {
  658. // 虚拟机启动后才分配静态公网IP,否则取不到public ip
  659. if desc.PublicIpBw > 0 && initialState == api.VM_RUNNING {
  660. eip, _ := iVM.GetIEIP()
  661. if eip == nil {
  662. iVM.Refresh()
  663. return false, nil
  664. }
  665. // 同步静态公网ip
  666. if !eipSync {
  667. provider := host.GetCloudprovider()
  668. guest.SyncVMEip(ctx, userCred, provider, eip, provider.GetOwnerId())
  669. eipSync = true
  670. }
  671. }
  672. idisks, err := iVM.GetIDisks()
  673. if err != nil {
  674. return false, errors.Wrap(err, "iVM.GetIDisks")
  675. }
  676. ret = len(idisks)
  677. log.Debugf("wait vm disk ready, expect %d disks, return %d disks", expect, ret)
  678. if ret >= expect { // 有可能自定义镜像里面也有磁盘,会导致返回的磁盘多于创建时的磁盘
  679. return true, nil
  680. }
  681. err = iVM.Refresh()
  682. if err != nil {
  683. log.Warningf("refresh vm %s error: %v", guest.Name, err)
  684. }
  685. return false, nil
  686. }, 10)
  687. if err != nil {
  688. return nil, errors.Wrapf(err, "GuestDriver.RemoteDeployGuestForCreate.RetryUntil expect %d disks return %d disks", expect, ret)
  689. }
  690. // 回填IP
  691. if len(desc.IpAddr) == 0 {
  692. nics, _ := iVM.GetINics()
  693. gns, _ := guest.GetNetworks("")
  694. if len(nics) > 0 && len(gns) > 0 {
  695. db.Update(&gns[0], func() error {
  696. gns[0].IpAddr = nics[0].GetIP()
  697. gns[0].MacAddr = nics[0].GetMAC()
  698. gns[0].Driver = nics[0].GetDriver()
  699. return nil
  700. })
  701. }
  702. }
  703. driver.RemoteActionAfterGuestCreated(ctx, userCred, guest, host, iVM, &desc)
  704. data := fetchIVMinfo(desc, iVM, guest.Id, desc.Account, desc.Password, desc.PublicKey, "create")
  705. return data, nil
  706. }
  707. func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestSyncHost(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, iVM cloudprovider.ICloudVM) (cloudprovider.ICloudHost, error) {
  708. if hostId := iVM.GetIHostId(); len(hostId) > 0 {
  709. nh, err := db.FetchByExternalIdAndManagerId(models.HostManager, hostId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  710. return q.Equals("manager_id", host.ManagerId)
  711. })
  712. if err != nil {
  713. log.Warningf("failed to found new hostId(%s) for ivm %s(%s) error: %v", hostId, guest.Name, guest.Id, err)
  714. } else if nh.GetId() != guest.HostId {
  715. guest.OnScheduleToHost(ctx, userCred, nh.GetId())
  716. host = nh.(*models.SHost)
  717. }
  718. }
  719. return host.GetIHost(ctx)
  720. }
  721. func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestForDeploy(ctx context.Context, guest *models.SGuest, ihost cloudprovider.ICloudHost, task taskman.ITask, desc cloudprovider.SManagedVMCreateConfig) (jsonutils.JSONObject, error) {
  722. iVM, err := ihost.GetIVMById(guest.GetExternalId())
  723. if err != nil || iVM == nil {
  724. log.Errorf("cannot find vm %s", err)
  725. return nil, fmt.Errorf("cannot find vm")
  726. }
  727. params := task.GetParams()
  728. log.Debugf("Deploy VM params %s", params.String())
  729. opts := &cloudprovider.SInstanceDeployOptions{
  730. Username: desc.Account,
  731. PublicKey: desc.PublicKey,
  732. KeypairName: desc.KeypairName,
  733. Password: desc.Password,
  734. UserData: desc.UserData,
  735. }
  736. opts.DeleteKeypair = jsonutils.QueryBoolean(params, "__delete_keypair__", false)
  737. if len(desc.UserData) > 0 {
  738. err := iVM.UpdateUserData(desc.UserData)
  739. if err != nil {
  740. log.Errorf("update userdata fail %s", err)
  741. }
  742. }
  743. err = func() error {
  744. lockman.LockObject(ctx, guest)
  745. defer lockman.ReleaseObject(ctx, guest)
  746. // 避免DeployVM函数里面执行顺序不一致导致与预期结果不符
  747. if opts.DeleteKeypair {
  748. opts.Password, opts.PublicKey = "", ""
  749. }
  750. if len(desc.PublicKey) > 0 {
  751. opts.Password = ""
  752. }
  753. e := iVM.DeployVM(ctx, opts)
  754. if e != nil {
  755. return e
  756. }
  757. if len(desc.Password) == 0 {
  758. //可以从秘钥解密旧密码
  759. desc.Password = guest.GetOldPassword(ctx, task.GetUserCred())
  760. }
  761. return nil
  762. }()
  763. if err != nil {
  764. return nil, err
  765. }
  766. data := fetchIVMinfo(desc, iVM, guest.Id, desc.Account, desc.Password, desc.PublicKey, "deploy")
  767. return data, nil
  768. }
  769. func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestForRebuildRoot(ctx context.Context, guest *models.SGuest, ihost cloudprovider.ICloudHost, task taskman.ITask, desc cloudprovider.SManagedVMCreateConfig) (jsonutils.JSONObject, error) {
  770. iVM, err := ihost.GetIVMById(guest.GetExternalId())
  771. if err != nil {
  772. return nil, errors.Wrapf(err, "ihost.GetIVMById(%s)", guest.GetExternalId())
  773. }
  774. if len(desc.UserData) > 0 {
  775. err := iVM.UpdateUserData(desc.UserData)
  776. if err != nil {
  777. log.Errorf("update userdata fail %s", err)
  778. }
  779. cloudprovider.WaitMultiStatus(iVM, []string{api.VM_READY, api.VM_RUNNING}, time.Second*5, time.Minute*3)
  780. }
  781. diskId, err := func() (string, error) {
  782. lockman.LockObject(ctx, guest)
  783. defer lockman.ReleaseObject(ctx, guest)
  784. conf := cloudprovider.SManagedVMRebuildRootConfig{
  785. Account: desc.Account,
  786. ImageId: desc.ExternalImageId,
  787. Password: desc.Password,
  788. PublicKey: desc.PublicKey,
  789. KeypairName: desc.KeypairName,
  790. SysSizeGB: desc.SysDisk.SizeGB,
  791. OsType: desc.OsType,
  792. UserData: desc.UserData,
  793. }
  794. return iVM.RebuildRoot(ctx, &conf)
  795. }()
  796. if err != nil {
  797. return nil, err
  798. }
  799. driver, err := guest.GetDriver()
  800. if err != nil {
  801. return nil, err
  802. }
  803. initialState := driver.GetGuestInitialStateAfterRebuild()
  804. log.Debugf("VMrebuildRoot %s new diskID %s, wait status %s ...", iVM.GetGlobalId(), diskId, initialState)
  805. err = cloudprovider.WaitStatus(iVM, initialState, time.Second*5, time.Second*1800)
  806. if err != nil {
  807. return nil, err
  808. }
  809. log.Debugf("VMrebuildRoot %s, and status is ready", iVM.GetGlobalId())
  810. maxWaitSecs := 300
  811. waited := 0
  812. for {
  813. // hack, wait disk number consistent
  814. idisks, err := iVM.GetIDisks()
  815. if err != nil {
  816. log.Errorf("fail to find VM idisks %s", err)
  817. return nil, err
  818. }
  819. if len(idisks) < len(desc.DataDisks)+1 {
  820. if waited > maxWaitSecs {
  821. return nil, errors.Wrapf(cloudprovider.ErrTimeout, "inconsistent disk number %d < %d, wait timeout, must be something wrong on remote", len(idisks), len(desc.DataDisks)+1)
  822. }
  823. log.Debugf("inconsistent disk number???? %d != %d", len(idisks), len(desc.DataDisks)+1)
  824. time.Sleep(time.Second * 5)
  825. waited += 5
  826. } else {
  827. if idisks[0].GetGlobalId() == diskId {
  828. break
  829. }
  830. if waited > maxWaitSecs {
  831. return nil, fmt.Errorf("inconsistent sys disk id after rebuild root")
  832. }
  833. log.Debugf("current system disk id inconsistent %s != %s, try after 5 seconds", idisks[0].GetGlobalId(), diskId)
  834. time.Sleep(time.Second * 5)
  835. waited += 5
  836. }
  837. }
  838. data := fetchIVMinfo(desc, iVM, guest.Id, desc.Account, desc.Password, desc.PublicKey, "rebuild")
  839. return data, nil
  840. }
  841. func (drv *SManagedVirtualizedGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  842. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  843. ihost, err := host.GetIHost(ctx)
  844. if err != nil {
  845. //私有云宿主机有可能下线,会导致虚拟机无限删除失败
  846. if errors.Cause(err) == cloudprovider.ErrNotFound {
  847. return nil, nil
  848. }
  849. return nil, errors.Wrapf(err, "host.GetIHost")
  850. }
  851. // 创建失败时external id为空。此时直接返回即可。不需要再调用公有云api
  852. if len(guest.ExternalId) == 0 {
  853. return nil, nil
  854. }
  855. ivm, err := ihost.GetIVMById(guest.ExternalId)
  856. if err != nil {
  857. if errors.Cause(err) == cloudprovider.ErrNotFound {
  858. return nil, nil
  859. }
  860. return nil, errors.Wrapf(err, "ihost.GetIVMById(%s)", guest.ExternalId)
  861. }
  862. err = ivm.DeleteVM(ctx)
  863. if err != nil {
  864. return nil, errors.Wrapf(err, "ivm.DeleteVM")
  865. }
  866. cloudprovider.WaitDeleted(ivm, time.Second*10, time.Minute*3)
  867. driver, err := guest.GetDriver()
  868. if err != nil {
  869. return nil, err
  870. }
  871. if driver.IsNeedCleanDisksAfterUndeploy() {
  872. disks, err := guest.GetDisks()
  873. if err != nil {
  874. return nil, errors.Wrapf(err, "GetDisks")
  875. }
  876. for i := range disks {
  877. disk := disks[i]
  878. storage, _ := disk.GetStorage()
  879. if !utils.IsInStringArray(storage.StorageType, api.STORAGE_LOCAL_TYPES) && disk.DiskType != api.DISK_TYPE_SYS {
  880. idisk, err := disk.GetIDisk(ctx)
  881. if err != nil {
  882. if errors.Cause(err) == cloudprovider.ErrNotFound {
  883. continue
  884. }
  885. return nil, errors.Wrapf(err, "disk.GetIDisk")
  886. }
  887. if idisk.GetStatus() == api.DISK_DEALLOC {
  888. continue
  889. }
  890. err = idisk.Delete(ctx)
  891. if err != nil {
  892. return nil, errors.Wrapf(err, "idisk.Delete")
  893. }
  894. }
  895. }
  896. }
  897. return nil, nil
  898. })
  899. return nil
  900. }
  901. func (drv *SManagedVirtualizedGuestDriver) RequestStopOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask, syncStatus bool) error {
  902. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  903. ivm, err := guest.GetIVM(ctx)
  904. if err != nil {
  905. return nil, errors.Wrapf(err, "guest.GetIVM")
  906. }
  907. if ivm.GetStatus() != api.VM_READY {
  908. opts := &cloudprovider.ServerStopOptions{}
  909. task.GetParams().Unmarshal(opts)
  910. // 包年包月实例关机不收费,先转按量付费再关机
  911. if opts.StopCharging && guest.BillingType == billing_api.BILLING_TYPE_PREPAID {
  912. err = ivm.ChangeBillingType(string(billing_api.BILLING_TYPE_POSTPAID))
  913. if err != nil && errors.Cause(err) != cloudprovider.ErrNotImplemented {
  914. logclient.AddSimpleActionLog(guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, string(billing_api.BILLING_TYPE_POSTPAID)), task.GetUserCred(), false)
  915. }
  916. }
  917. err = ivm.StopVM(ctx, opts)
  918. if err != nil {
  919. return nil, errors.Wrapf(err, "ivm.StopVM")
  920. }
  921. err = cloudprovider.WaitStatus(ivm, api.VM_READY, time.Second*3, time.Minute*5)
  922. if err != nil {
  923. return nil, errors.Wrapf(err, "wait server stop after 5 miniutes")
  924. }
  925. }
  926. // 公有云关机,公网ip会释放
  927. guest.SyncAllWithCloudVM(ctx, task.GetUserCred(), host, ivm, syncStatus)
  928. return nil, nil
  929. })
  930. return nil
  931. }
  932. func (drv *SManagedVirtualizedGuestDriver) RequestChangeBillingType(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  933. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  934. ivm, err := guest.GetIVM(ctx)
  935. if err != nil {
  936. return nil, errors.Wrapf(err, "guest.GetIVM")
  937. }
  938. var billType billing_api.TBillingType
  939. switch guest.BillingType {
  940. case billing_api.BILLING_TYPE_POSTPAID:
  941. billType = billing_api.BILLING_TYPE_PREPAID
  942. case billing_api.BILLING_TYPE_PREPAID:
  943. billType = billing_api.BILLING_TYPE_POSTPAID
  944. }
  945. err = ivm.ChangeBillingType(string(billType))
  946. if err != nil {
  947. return nil, errors.Wrapf(err, "ChangeBillingType")
  948. }
  949. err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) {
  950. err = ivm.Refresh()
  951. if err != nil {
  952. return false, err
  953. }
  954. if ivm.GetBillingType() != string(billType) {
  955. return false, nil
  956. }
  957. return true, nil
  958. })
  959. if err != nil {
  960. return nil, errors.Wrapf(err, "Wait vm billing type changed")
  961. }
  962. _, err = db.Update(guest, func() error {
  963. guest.BillingType = billing_api.TBillingType(ivm.GetBillingType())
  964. guest.Status = ivm.GetStatus()
  965. guest.ExpiredAt = time.Time{}
  966. guest.AutoRenew = false
  967. if guest.BillingType == billing_api.BILLING_TYPE_PREPAID {
  968. guest.AutoRenew = ivm.IsAutoRenew()
  969. guest.ExpiredAt = ivm.GetExpiredAt()
  970. }
  971. return nil
  972. })
  973. return nil, err
  974. })
  975. return nil
  976. }
  977. func (drv *SManagedVirtualizedGuestDriver) RequestSyncstatusOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) error {
  978. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  979. ihost, err := host.GetIHost(ctx)
  980. if err != nil {
  981. return nil, errors.Wrap(err, "host.GetIHost")
  982. }
  983. ivm, err := ihost.GetIVMById(guest.ExternalId)
  984. if err != nil {
  985. log.Errorf("fail to find ivm by id %s", err)
  986. return nil, errors.Wrap(err, "ihost.GetIVMById")
  987. }
  988. err = guest.SyncAllWithCloudVM(ctx, userCred, host, ivm, true)
  989. if err != nil {
  990. return nil, errors.Wrap(err, "guest.SyncAllWithCloudVM")
  991. }
  992. status := GetCloudVMStatus(ivm)
  993. body := jsonutils.NewDict()
  994. body.Add(jsonutils.NewString(status), "status")
  995. return body, nil
  996. })
  997. return nil
  998. }
  999. func (drv *SManagedVirtualizedGuestDriver) GetGuestVncInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  1000. ihost, err := host.GetIHost(ctx)
  1001. if err != nil {
  1002. return nil, err
  1003. }
  1004. iVM, err := ihost.GetIVMById(guest.ExternalId)
  1005. if err != nil {
  1006. log.Errorf("cannot find vm %s %s", iVM, err)
  1007. return nil, err
  1008. }
  1009. return iVM.GetVNCInfo(input)
  1010. }
  1011. func (drv *SManagedVirtualizedGuestDriver) RequestRebuildRootDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  1012. subtask, err := taskman.TaskManager.NewTask(ctx, "ManagedGuestRebuildRootTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
  1013. if err != nil {
  1014. return err
  1015. }
  1016. subtask.ScheduleRun(nil)
  1017. return nil
  1018. }
  1019. func (drv *SManagedVirtualizedGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  1020. subtask, err := taskman.TaskManager.NewTask(ctx, "ManagedGuestCreateDiskTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
  1021. if err != nil {
  1022. return err
  1023. }
  1024. subtask.ScheduleRun(nil)
  1025. return nil
  1026. }
  1027. func (drv *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, cpuSockets, vmemSize int64) error {
  1028. host, err := guest.GetHost()
  1029. if err != nil {
  1030. return errors.Wrapf(err, "GetHost")
  1031. }
  1032. ihost, err := host.GetIHost(ctx)
  1033. if err != nil {
  1034. return err
  1035. }
  1036. iVM, err := ihost.GetIVMById(guest.GetExternalId())
  1037. if err != nil {
  1038. return err
  1039. }
  1040. if len(instanceType) == 0 {
  1041. region, err := host.GetRegion()
  1042. if err != nil {
  1043. return err
  1044. }
  1045. sku, err := models.ServerSkuManager.GetMatchedSku(region.GetId(), vcpuCount, vmemSize)
  1046. if err != nil {
  1047. return errors.Wrapf(err, "GetMatchedSku %s %dC%dM", region.GetId(), vcpuCount, vmemSize)
  1048. }
  1049. instanceType = sku.Name
  1050. }
  1051. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  1052. config := &cloudprovider.SManagedVMChangeConfig{
  1053. Cpu: int(vcpuCount),
  1054. CpuSocket: int(cpuSockets),
  1055. MemoryMB: int(vmemSize),
  1056. InstanceType: instanceType,
  1057. }
  1058. err := iVM.ChangeConfig(ctx, config)
  1059. if err != nil {
  1060. return nil, errors.Wrap(err, "ChangeConfig")
  1061. }
  1062. err = cloudprovider.WaitCreated(time.Second*5, time.Minute*5, func() bool {
  1063. err := iVM.Refresh()
  1064. if err != nil {
  1065. return false
  1066. }
  1067. status := iVM.GetStatus()
  1068. if status == api.VM_READY || status == api.VM_RUNNING {
  1069. iInstanceType := iVM.GetInstanceType()
  1070. if len(instanceType) > 0 && len(iInstanceType) > 0 && instanceType == iInstanceType {
  1071. return true
  1072. } else {
  1073. // aws 目前取不到内存。返回值永远为0
  1074. if iVM.GetVcpuCount() == int(vcpuCount) && (iVM.GetVmemSizeMB() == int(vmemSize) || iVM.GetVmemSizeMB() == 0) {
  1075. return true
  1076. }
  1077. }
  1078. }
  1079. return false
  1080. })
  1081. if err != nil {
  1082. return nil, errors.Wrap(err, "wait config change")
  1083. }
  1084. instanceType = iVM.GetInstanceType()
  1085. if len(instanceType) > 0 {
  1086. _, err = db.Update(guest, func() error {
  1087. guest.InstanceType = instanceType
  1088. return nil
  1089. })
  1090. if err != nil {
  1091. return nil, errors.Wrap(err, "Update")
  1092. }
  1093. }
  1094. return nil, nil
  1095. })
  1096. return nil
  1097. }
  1098. func (drv *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
  1099. uuid, _ := data.GetString("uuid")
  1100. if len(uuid) > 0 {
  1101. db.SetExternalId(guest, task.GetUserCred(), uuid)
  1102. }
  1103. recycle := false
  1104. if guest.IsPrepaidRecycle() {
  1105. recycle = true
  1106. }
  1107. if data.Contains("disks") {
  1108. diskInfo := make([]SDiskInfo, 0)
  1109. err := data.Unmarshal(&diskInfo, "disks")
  1110. if err != nil {
  1111. return err
  1112. }
  1113. disks, _ := guest.GetGuestDisks()
  1114. if len(disks) != len(diskInfo) {
  1115. // 公有云镜像可能包含数据盘, 若忽略设置磁盘的external id, 会导致部分磁盘状态异常
  1116. log.Warningf("inconsistent disk number: guest have %d disks, data contains %d disks", len(disks), len(diskInfo))
  1117. }
  1118. for i := 0; i < len(diskInfo) && i < len(disks); i += 1 {
  1119. disk := disks[i].GetDisk()
  1120. _, err = db.Update(disk, func() error {
  1121. disk.DiskSize = diskInfo[i].Size
  1122. disk.ExternalId = diskInfo[i].Uuid
  1123. disk.DiskType = diskInfo[i].DiskType
  1124. disk.Status = api.DISK_READY
  1125. disk.Device = diskInfo[i].Device
  1126. disk.FsFormat = diskInfo[i].FsFromat
  1127. if diskInfo[i].AutoDelete {
  1128. disk.AutoDelete = true
  1129. }
  1130. // disk.TemplateId = diskInfo[i].TemplateId
  1131. disk.AccessPath = diskInfo[i].Path
  1132. if !recycle {
  1133. if len(diskInfo[i].BillingType) > 0 {
  1134. disk.BillingType = diskInfo[i].BillingType
  1135. disk.ExpiredAt = diskInfo[i].ExpiredAt
  1136. }
  1137. }
  1138. if len(diskInfo[i].StorageExternalId) > 0 {
  1139. storage, err := db.FetchByExternalIdAndManagerId(models.StorageManager, diskInfo[i].StorageExternalId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1140. host, _ := guest.GetHost()
  1141. if host != nil {
  1142. return q.Equals("manager_id", host.ManagerId)
  1143. }
  1144. return q
  1145. })
  1146. if err != nil {
  1147. log.Warningf("failed to found storage by externalId %s error: %v", diskInfo[i].StorageExternalId, err)
  1148. } else if disk.StorageId != storage.GetId() {
  1149. disk.StorageId = storage.GetId()
  1150. }
  1151. }
  1152. if len(diskInfo[i].Metadata) > 0 {
  1153. for key, value := range diskInfo[i].Metadata {
  1154. if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
  1155. log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err)
  1156. }
  1157. }
  1158. }
  1159. return nil
  1160. })
  1161. if err != nil {
  1162. msg := fmt.Sprintf("save disk info failed %s", err)
  1163. log.Errorf("%s", msg)
  1164. break
  1165. }
  1166. db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(ctx), task.GetUserCred())
  1167. guestdisk := guest.GetGuestDisk(disk.Id)
  1168. _, err = db.Update(guestdisk, func() error {
  1169. guestdisk.Driver = diskInfo[i].Driver
  1170. guestdisk.CacheMode = diskInfo[i].CacheMode
  1171. return nil
  1172. })
  1173. if err != nil {
  1174. msg := fmt.Sprintf("save disk info failed %s", err)
  1175. log.Errorf("%s", msg)
  1176. break
  1177. }
  1178. }
  1179. }
  1180. if metaData, _ := data.Get("metadata"); metaData != nil {
  1181. meta := make(map[string]string, 0)
  1182. if err := metaData.Unmarshal(meta); err != nil {
  1183. log.Errorf("Get guest %s metadata error: %v", guest.Name, err)
  1184. } else {
  1185. for key, value := range meta {
  1186. if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
  1187. log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err)
  1188. }
  1189. }
  1190. }
  1191. }
  1192. exp, err := data.GetTime("expired_at")
  1193. if err == nil && !guest.IsPrepaidRecycle() {
  1194. models.SaveRenewInfo(ctx, task.GetUserCred(), guest, nil, &exp, "")
  1195. }
  1196. driver, _ := guest.GetDriver()
  1197. if driver != nil && driver.IsSupportSetAutoRenew() {
  1198. autoRenew, _ := data.Bool("auto_renew")
  1199. guest.SetAutoRenew(autoRenew)
  1200. }
  1201. guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
  1202. iVM, err := guest.GetIVM(ctx)
  1203. if err != nil {
  1204. return errors.Wrap(err, "guest.GetIVM")
  1205. }
  1206. guest.SyncOsInfo(ctx, task.GetUserCred(), iVM)
  1207. return nil
  1208. }
  1209. func (drv *SManagedVirtualizedGuestDriver) RequestSyncSecgroupsOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  1210. secgroups, err := guest.GetSecgroups()
  1211. if err != nil {
  1212. return errors.Wrapf(err, "GetSecgroups")
  1213. }
  1214. iVM, err := guest.GetIVM(ctx)
  1215. if err != nil {
  1216. return err
  1217. }
  1218. externalIds := []string{}
  1219. for _, secgroup := range secgroups {
  1220. if len(secgroup.ExternalId) > 0 {
  1221. externalIds = append(externalIds, secgroup.ExternalId)
  1222. }
  1223. }
  1224. return iVM.SetSecurityGroups(externalIds)
  1225. }
  1226. func (drv *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  1227. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  1228. if jsonutils.QueryBoolean(task.GetParams(), "fw_only", false) {
  1229. driver, err := guest.GetDriver()
  1230. if err != nil {
  1231. return nil, err
  1232. }
  1233. err = driver.RequestSyncSecgroupsOnHost(ctx, guest, host, task)
  1234. if err != nil {
  1235. return nil, err
  1236. }
  1237. }
  1238. return nil, nil
  1239. })
  1240. return nil
  1241. }
  1242. func (drv *SManagedVirtualizedGuestDriver) RequestRenewInstance(ctx context.Context, guest *models.SGuest, bc billing.SBillingCycle) (time.Time, error) {
  1243. iVM, err := guest.GetIVM(ctx)
  1244. if err != nil {
  1245. return time.Time{}, err
  1246. }
  1247. oldExpired := iVM.GetExpiredAt()
  1248. err = iVM.Renew(bc)
  1249. if err != nil {
  1250. return time.Time{}, err
  1251. }
  1252. //避免有些云续费后过期时间刷新比较慢问题
  1253. cloudprovider.WaitCreated(15*time.Second, 5*time.Minute, func() bool {
  1254. err := iVM.Refresh()
  1255. if err != nil {
  1256. log.Errorf("failed refresh instance %s error: %v", guest.Name, err)
  1257. }
  1258. newExipred := iVM.GetExpiredAt()
  1259. if newExipred.After(oldExpired) {
  1260. return true
  1261. }
  1262. return false
  1263. })
  1264. return iVM.GetExpiredAt(), nil
  1265. }
  1266. func (drv *SManagedVirtualizedGuestDriver) IsSupportEip() bool {
  1267. return true
  1268. }
  1269. func chooseHostStorage(
  1270. drv models.IGuestDriver,
  1271. host *models.SHost,
  1272. backend string,
  1273. storageIds []string,
  1274. ) *models.SStorage {
  1275. if len(storageIds) != 0 {
  1276. return models.StorageManager.FetchStorageById(storageIds[0])
  1277. }
  1278. storages := host.GetAttachedEnabledHostStorages(nil)
  1279. for i := 0; i < len(storages); i += 1 {
  1280. if storages[i].StorageType == backend {
  1281. return &storages[i]
  1282. }
  1283. }
  1284. for _, stype := range drv.GetStorageTypes() {
  1285. for i := 0; i < len(storages); i += 1 {
  1286. if storages[i].StorageType == stype {
  1287. return &storages[i]
  1288. }
  1289. }
  1290. }
  1291. return nil
  1292. }
  1293. func (drv *SManagedVirtualizedGuestDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
  1294. return false, nil
  1295. }
  1296. func (drv *SManagedVirtualizedGuestDriver) IsSupportFloppy(guest *models.SGuest) (bool, error) {
  1297. return false, nil
  1298. }
  1299. func GetCloudVMStatus(vm cloudprovider.ICloudVM) string {
  1300. status := vm.GetStatus()
  1301. switch status {
  1302. case api.VM_RUNNING:
  1303. status = cloudprovider.CloudVMStatusRunning
  1304. case api.VM_READY:
  1305. status = cloudprovider.CloudVMStatusStopped
  1306. case api.VM_STARTING:
  1307. status = cloudprovider.CloudVMStatusStopped
  1308. case api.VM_STOPPING:
  1309. status = cloudprovider.CloudVMStatusStopping
  1310. case api.VM_CHANGE_FLAVOR:
  1311. status = cloudprovider.CloudVMStatusChangeFlavor
  1312. case api.VM_DEPLOYING:
  1313. status = cloudprovider.CloudVMStatusDeploying
  1314. case api.VM_SUSPEND:
  1315. status = cloudprovider.CloudVMStatusSuspend
  1316. case api.VM_MIGRATING, api.VM_START_MIGRATE:
  1317. default:
  1318. status = cloudprovider.CloudVMStatusOther
  1319. }
  1320. return status
  1321. }
  1322. func (self *SManagedVirtualizedGuestDriver) RequestMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, input api.GuestMigrateInput, task taskman.ITask) error {
  1323. return self.requestMigrate(ctx, guest, userCred, api.GuestLiveMigrateInput{PreferHostId: input.PreferHostId}, task, false)
  1324. }
  1325. func (self *SManagedVirtualizedGuestDriver) RequestLiveMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, input api.GuestLiveMigrateInput, task taskman.ITask) error {
  1326. return self.requestMigrate(ctx, guest, userCred, input, task, true)
  1327. }
  1328. func (self *SManagedVirtualizedGuestDriver) requestMigrate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, input api.GuestLiveMigrateInput, task taskman.ITask, isLive bool) error {
  1329. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  1330. iVM, err := guest.GetIVM(ctx)
  1331. if err != nil {
  1332. return nil, errors.Wrap(err, "guest.GetIVM")
  1333. }
  1334. iHost, err := models.HostManager.FetchById(input.PreferHostId)
  1335. if err != nil {
  1336. return nil, errors.Wrapf(err, "FetchById(%s)", input.PreferHostId)
  1337. }
  1338. host := iHost.(*models.SHost)
  1339. hostExternalId := host.ExternalId
  1340. if isLive {
  1341. err = iVM.LiveMigrateVM(hostExternalId)
  1342. } else {
  1343. err = iVM.MigrateVM(hostExternalId)
  1344. }
  1345. if err != nil {
  1346. return nil, errors.Wrapf(err, "Migrate (%s)", hostExternalId)
  1347. }
  1348. err = cloudprovider.Wait(time.Second*10, time.Hour*1, func() (bool, error) {
  1349. err = iVM.Refresh()
  1350. if err != nil {
  1351. return false, err
  1352. }
  1353. vmStatus := iVM.GetStatus()
  1354. log.Debugf("vm %s migrate status: %s", guest.Name, vmStatus)
  1355. if vmStatus == api.VM_UNKNOWN || strings.Contains(vmStatus, "fail") {
  1356. return false, errors.Wrapf(cloudprovider.ErrInvalidStatus, "%s", vmStatus)
  1357. }
  1358. if !utils.IsInStringArray(vmStatus, []string{api.VM_RUNNING, api.VM_READY}) {
  1359. return false, nil
  1360. }
  1361. hostId := iVM.GetIHostId()
  1362. log.Debugf("guest %s migrate from %s -> %s", guest.Name, guest.HostId, host.Id)
  1363. if len(hostId) > 0 && hostId == hostExternalId {
  1364. return true, nil
  1365. }
  1366. return false, nil
  1367. })
  1368. if err != nil {
  1369. return nil, errors.Wrapf(err, "wait host change")
  1370. }
  1371. iHost, err = db.FetchByExternalIdAndManagerId(models.HostManager, hostExternalId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1372. if host, _ := guest.GetHost(); host != nil {
  1373. return q.Equals("manager_id", host.ManagerId)
  1374. }
  1375. return q
  1376. })
  1377. if err != nil {
  1378. return nil, errors.Wrapf(err, "fetch host %s", hostExternalId)
  1379. }
  1380. host = iHost.(*models.SHost)
  1381. _, err = db.Update(guest, func() error {
  1382. guest.HostId = host.GetId()
  1383. return nil
  1384. })
  1385. if err != nil {
  1386. return nil, errors.Wrap(err, "update hostId")
  1387. }
  1388. provider := host.GetCloudprovider()
  1389. driver, err := provider.GetProvider(ctx)
  1390. if err != nil {
  1391. return nil, err
  1392. }
  1393. models.SyncVMPeripherals(ctx, userCred, guest, iVM, host, provider, driver)
  1394. return nil, nil
  1395. })
  1396. return nil
  1397. }
  1398. func (drv *SManagedVirtualizedGuestDriver) RequestConvertPublicipToEip(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, task taskman.ITask) error {
  1399. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  1400. iVM, err := guest.GetIVM(ctx)
  1401. if err != nil {
  1402. return nil, errors.Wrap(err, "guest.GetIVM")
  1403. }
  1404. err = iVM.ConvertPublicIpToEip()
  1405. if err != nil {
  1406. return nil, errors.Wrap(err, "iVM.ConvertPublicIpToEip")
  1407. }
  1408. publicIp, err := guest.GetPublicIp()
  1409. if err != nil {
  1410. return nil, errors.Wrap(err, "guest.GetPublicIp")
  1411. }
  1412. if publicIp == nil {
  1413. return nil, fmt.Errorf("faild to found public ip after convert")
  1414. }
  1415. err = cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) {
  1416. err = iVM.Refresh()
  1417. if err != nil {
  1418. log.Errorf("refresh ivm error: %v", err)
  1419. return false, nil
  1420. }
  1421. eip, err := iVM.GetIEIP()
  1422. if err != nil {
  1423. log.Errorf("iVM.GetIEIP error: %v", err)
  1424. return false, nil
  1425. }
  1426. if eip.GetGlobalId() == iVM.GetGlobalId() || eip.GetGlobalId() == eip.GetIpAddr() {
  1427. log.Errorf("wait public ip convert to eip (%s)...", eip.GetGlobalId())
  1428. return false, nil
  1429. }
  1430. _, err = db.Update(publicIp, func() error {
  1431. publicIp.ExternalId = eip.GetGlobalId()
  1432. publicIp.IpAddr = eip.GetIpAddr()
  1433. publicIp.Bandwidth = eip.GetBandwidth()
  1434. publicIp.Mode = api.EIP_MODE_STANDALONE_EIP
  1435. return nil
  1436. })
  1437. return true, err
  1438. })
  1439. if err != nil {
  1440. return nil, errors.Wrap(err, "cloudprovider.Wait")
  1441. }
  1442. return nil, nil
  1443. })
  1444. return nil
  1445. }
  1446. func (drv *SManagedVirtualizedGuestDriver) RequestSetAutoRenewInstance(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, input api.GuestAutoRenewInput, task taskman.ITask) error {
  1447. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  1448. iVM, err := guest.GetIVM(ctx)
  1449. if err != nil {
  1450. return nil, errors.Wrap(err, "guest.GetIVM")
  1451. }
  1452. bc, err := billing.ParseBillingCycle(input.Duration)
  1453. if err != nil {
  1454. return nil, errors.Wrapf(err, "billing.ParseBillingCycle")
  1455. }
  1456. bc.AutoRenew = input.AutoRenew
  1457. err = iVM.SetAutoRenew(bc)
  1458. if err != nil {
  1459. return nil, errors.Wrap(err, "iVM.SetAutoRenew")
  1460. }
  1461. return nil, guest.SetAutoRenew(input.AutoRenew)
  1462. })
  1463. return nil
  1464. }
  1465. func (drv *SManagedVirtualizedGuestDriver) RequestRemoteUpdate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, replaceTags bool) error {
  1466. // nil ops
  1467. iVM, err := guest.GetIVM(ctx)
  1468. if err != nil {
  1469. return errors.Wrap(err, "guest.GetIVM")
  1470. }
  1471. err = func() error {
  1472. oldTags, err := iVM.GetTags()
  1473. if err != nil {
  1474. if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented {
  1475. return nil
  1476. }
  1477. return errors.Wrap(err, "iVM.GetTags()")
  1478. }
  1479. tags, err := guest.GetAllUserMetadata()
  1480. if err != nil {
  1481. return errors.Wrapf(err, "GetAllUserMetadata")
  1482. }
  1483. tagsUpdateInfo := cloudprovider.TagsUpdateInfo{OldTags: oldTags, NewTags: tags}
  1484. host, _ := guest.GetHost()
  1485. err = cloudprovider.SetTags(ctx, iVM, host.ManagerId, tags, replaceTags)
  1486. if err != nil {
  1487. if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented {
  1488. return nil
  1489. }
  1490. logclient.AddSimpleActionLog(guest, logclient.ACT_UPDATE_TAGS, err, userCred, false)
  1491. return errors.Wrap(err, "iVM.SetTags")
  1492. }
  1493. logclient.AddSimpleActionLog(guest, logclient.ACT_UPDATE_TAGS, tagsUpdateInfo, userCred, true)
  1494. // sync back cloud metadata
  1495. iVM.Refresh()
  1496. guest.SyncOsInfo(ctx, userCred, iVM)
  1497. err = models.SyncVirtualResourceMetadata(ctx, userCred, guest, iVM, false)
  1498. if err != nil {
  1499. return errors.Wrap(err, "syncVirtualResourceMetadata")
  1500. }
  1501. return nil
  1502. }()
  1503. if err != nil {
  1504. return err
  1505. }
  1506. err = iVM.UpdateVM(ctx, cloudprovider.SInstanceUpdateOptions{NAME: guest.Name, HostName: guest.Hostname, Description: guest.Description})
  1507. if err != nil {
  1508. if errors.Cause(err) != cloudprovider.ErrNotSupported {
  1509. return errors.Wrap(err, "iVM.UpdateVM")
  1510. }
  1511. }
  1512. return nil
  1513. }
  1514. func (drv *SManagedVirtualizedGuestDriver) SyncOsInfo(ctx context.Context, userCred mcclient.TokenCredential, g *models.SGuest, extVM cloudprovider.IOSInfo) error {
  1515. // save os info
  1516. osinfo := map[string]interface{}{}
  1517. for k, v := range map[string]string{
  1518. "os_full_name": extVM.GetFullOsName(),
  1519. "os_name": string(extVM.GetOsType()),
  1520. "os_arch": extVM.GetOsArch(),
  1521. "os_type": string(extVM.GetOsType()),
  1522. "os_distribution": extVM.GetOsDist(),
  1523. "os_version": extVM.GetOsVersion(),
  1524. "os_language": extVM.GetOsLang(),
  1525. } {
  1526. if len(v) == 0 {
  1527. continue
  1528. }
  1529. osinfo[k] = v
  1530. }
  1531. if len(osinfo) > 0 {
  1532. err := g.SetAllMetadata(ctx, osinfo, userCred)
  1533. if err != nil {
  1534. return errors.Wrap(err, "SetAllMetadata")
  1535. }
  1536. }
  1537. return nil
  1538. }
  1539. func (self *SManagedVirtualizedGuestDriver) ValidateSetOSInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, input *api.ServerSetOSInfoInput) error {
  1540. return httperrors.NewNotAcceptableError("%s server doesn't allow to set OS info", guest.Hypervisor)
  1541. }