yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ucloud/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 ucloud 16 17 import ( 18 "context" 19 "encoding/base64" 20 "fmt" 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/utils" 28 29 billing_api "yunion.io/x/cloudmux/pkg/apis/billing" 30 api "yunion.io/x/cloudmux/pkg/apis/compute" 31 "yunion.io/x/cloudmux/pkg/cloudprovider" 32 "yunion.io/x/cloudmux/pkg/multicloud" 33 "yunion.io/x/onecloud/pkg/util/billing" 34 "yunion.io/x/onecloud/pkg/util/imagetools" 35 ) 36 37 type SInstance struct { 38 multicloud.SInstanceBase 39 UcloudTags 40 41 host *SHost 42 43 osInfo *imagetools.ImageInfo 44 45 UHostID string `json:"UHostId"` 46 Zone string `json:"Zone"` 47 LifeCycle string `json:"LifeCycle"` 48 OSName string `json:"OsName"` 49 ImageID string `json:"ImageId"` 50 BasicImageID string `json:"BasicImageId"` 51 BasicImageName string `json:"BasicImageName"` 52 Tag string `json:"Tag"` 53 Name string `json:"Name"` 54 Remark string `json:"Remark"` 55 State string `json:"State"` 56 NetworkState string `json:"NetworkState"` 57 HostType string `json:"HostType"` 58 StorageType string `json:"StorageType"` 59 TotalDiskSpace int `json:"TotalDiskSpace"` 60 DiskSet []DiskSet `json:"DiskSet"` 61 NetCapability string `json:"NetCapability"` 62 IPSet []IPSet `json:"IPSet"` 63 SubnetType string `json:"SubnetType"` 64 ChargeType string `json:"ChargeType"` 65 ExpireTime int64 `json:"ExpireTime"` 66 AutoRenew string `json:"AutoRenew"` 67 IsExpire string `json:"IsExpire"` 68 UHostType string `json:"UHostType"` 69 OSType string `json:"OsType"` 70 CreateTime int64 `json:"CreateTime"` 71 CPU int `json:"CPU"` 72 GPU int `json:"GPU"` 73 MemoryMB int `json:"Memory"` 74 TimemachineFeature string `json:"TimemachineFeature"` 75 HotplugFeature bool `json:"HotplugFeature"` 76 NetCapFeature bool `json:"NetCapFeature"` 77 BootDiskState string `json:"BootDiskState"` 78 } 79 80 func (self *SInstance) GetSecurityGroupIds() ([]string, error) { 81 secgroups, err := self.GetSecurityGroups() 82 if err != nil { 83 log.Errorln(err) 84 } 85 86 secgroupIds := make([]string, 0) 87 for _, secgroup := range secgroups { 88 secgroupIds = append(secgroupIds, secgroup.GetId()) 89 } 90 91 return secgroupIds, nil 92 } 93 94 func (self *SInstance) GetProjectId() string { 95 return self.host.zone.region.client.projectId 96 } 97 98 func (self *SInstance) GetError() error { 99 return nil 100 } 101 102 type DiskSet struct { 103 DiskID string `json:"DiskId"` 104 DiskType string `json:"DiskType"` 105 Drive string `json:"Drive"` 106 IsBoot bool `json:"IsBoot"` 107 Size int `json:"Size"` 108 Encrypted string `json:"Encrypted"` 109 Type string `json:"Type"` 110 } 111 112 type IPSet struct { 113 Type string `json:"Type"` 114 IP string `json:"IP"` 115 IPId string `json:"IPId"` // IP资源ID (内网IP无对应的资源ID) 116 MAC string `json:"Mac"` 117 VPCID string `json:"VPCId"` 118 SubnetID string `json:"SubnetId"` 119 } 120 121 type SVncInfo struct { 122 VNCIP string `json:"VncIP"` 123 VNCPassword string `json:"VncPassword"` 124 UHostID string `json:"UHostId"` 125 Action string `json:"Action"` 126 VNCPort int64 `json:"VncPort"` 127 } 128 129 func (self *SInstance) GetId() string { 130 return self.UHostID 131 } 132 133 func (self *SInstance) GetName() string { 134 if len(self.Name) == 0 { 135 return self.GetId() 136 } 137 return self.Name 138 } 139 140 func (self *SInstance) GetHostname() string { 141 return self.GetName() 142 } 143 144 func (self *SInstance) GetGlobalId() string { 145 return self.GetId() 146 } 147 148 // 实例状态,枚举值: 149 // >初始化: Initializing; 150 // >启动中: Starting; 151 // > 运行中: Running; 152 // > 关机中: Stopping; 153 // >关机: Stopped 154 // >安装失败: Install Fail; 155 // >重启中: Rebooting 156 func (self *SInstance) GetStatus() string { 157 switch self.State { 158 case "Running": 159 return api.VM_RUNNING 160 case "Stopped": 161 return api.VM_READY 162 case "Rebooting": 163 return api.VM_STOPPING 164 case "Initializing": 165 return api.VM_INIT 166 case "Starting": 167 return api.VM_STARTING 168 case "Stopping": 169 return api.VM_STOPPING 170 case "Install Fail": 171 return api.VM_CREATE_FAILED 172 default: 173 return api.VM_UNKNOWN 174 } 175 } 176 177 func (self *SInstance) Refresh() error { 178 new, err := self.host.zone.region.GetInstanceByID(self.GetId()) 179 if err != nil { 180 return err 181 } 182 183 new.host = self.host 184 return jsonutils.Update(self, new) 185 } 186 187 func (self *SInstance) IsEmulated() bool { 188 return false 189 } 190 191 func (self *SInstance) GetSysTags() map[string]string { 192 data := map[string]string{} 193 // todo: add price key here 194 data["zone_ext_id"] = self.host.zone.GetGlobalId() 195 if len(self.BasicImageID) > 0 { 196 if image, err := self.host.zone.region.GetImage(self.BasicImageID); err != nil { 197 log.Errorf("Failed to find image %s for instance %s", self.BasicImageID, self.GetName()) 198 } else { 199 meta := image.GetSysTags() 200 for k, v := range meta { 201 data[k] = v 202 } 203 } 204 } 205 206 return data 207 } 208 209 // 计费模式,枚举值为: Year,按年付费; Month,按月付费; Dynamic,按需付费(需开启权限); 210 func (self *SInstance) GetBillingType() string { 211 switch self.ChargeType { 212 case "Year", "Month": 213 return billing_api.BILLING_TYPE_PREPAID 214 default: 215 return billing_api.BILLING_TYPE_POSTPAID 216 } 217 } 218 219 func (self *SInstance) GetCreatedAt() time.Time { 220 return time.Unix(self.CreateTime, 0) 221 } 222 223 func (self *SInstance) GetExpiredAt() time.Time { 224 if self.AutoRenew != "Yes" { 225 return time.Unix(self.ExpireTime, 0) 226 } 227 228 return time.Time{} 229 } 230 231 func (self *SInstance) GetIHost() cloudprovider.ICloudHost { 232 return self.host 233 } 234 235 func (self *SInstance) GetLocalDisk(diskId, storageType string, sizeGB int, isBoot bool) SDisk { 236 diskType := "" 237 if isBoot { 238 diskType = "SystemDisk" 239 } 240 241 disk := SDisk{ 242 SDisk: multicloud.SDisk{}, 243 Status: "Available", 244 UHostID: self.GetId(), 245 Name: diskId, 246 Zone: self.host.zone.GetId(), 247 DiskType: diskType, 248 UDiskID: diskId, 249 UHostName: self.GetName(), 250 CreateTime: self.CreateTime, 251 SizeGB: sizeGB, 252 } 253 254 disk.storage = &SStorage{zone: self.host.zone, storageType: storageType} 255 return disk 256 } 257 258 func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { 259 localDisks := make([]SDisk, 0) 260 diskIds := make([]string, 0) 261 for _, disk := range self.DiskSet { 262 if utils.IsInStringArray(disk.DiskType, []string{api.STORAGE_UCLOUD_LOCAL_NORMAL, api.STORAGE_UCLOUD_LOCAL_SSD}) { 263 localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot)) 264 } else { 265 diskIds = append(diskIds, disk.DiskID) 266 } 267 } 268 269 disks := []SDisk{} 270 var err error 271 if len(diskIds) > 0 { 272 disks, err = self.host.zone.region.GetDisks("", "", diskIds) 273 if err != nil { 274 return nil, err 275 } 276 } 277 278 disks = append(disks, localDisks...) 279 idisks := make([]cloudprovider.ICloudDisk, len(disks)) 280 for i := 0; i < len(disks); i += 1 { 281 if disks[i].storage == nil { 282 var category string 283 if strings.Contains(disks[i].DiskType, "SSD") { 284 category = api.STORAGE_UCLOUD_CLOUD_SSD 285 } else { 286 category = api.STORAGE_UCLOUD_CLOUD_NORMAL 287 } 288 storage, err := self.host.zone.getStorageByCategory(category) 289 if err != nil { 290 return nil, err 291 } 292 disks[i].storage = storage 293 } 294 idisks[i] = &disks[i] 295 // 将系统盘放到第0个位置 296 if disks[i].GetDiskType() == api.DISK_TYPE_SYS { 297 idisks[0], idisks[i] = idisks[i], idisks[0] 298 } 299 } 300 301 return idisks, nil 302 } 303 304 func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { 305 nics := make([]cloudprovider.ICloudNic, 0) 306 307 for _, ip := range self.IPSet { 308 if len(ip.SubnetID) == 0 { 309 continue 310 } 311 312 nic := SInstanceNic{ 313 instance: self, 314 ipAddr: ip.IP, 315 macAddr: ip.MAC, 316 } 317 nics = append(nics, &nic) 318 } 319 320 return nics, nil 321 } 322 323 // 国际: Internation,BGP: BGP,内网: Private 324 func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { 325 for _, ip := range self.IPSet { 326 if len(ip.IPId) > 0 { 327 eip, err := self.host.zone.region.GetEipById(ip.IPId) 328 if err != nil { 329 return nil, err 330 } 331 332 return &eip, nil 333 } 334 } 335 336 return nil, nil 337 } 338 339 func (self *SInstance) GetVcpuCount() int { 340 return self.CPU 341 } 342 343 func (self *SInstance) GetVmemSizeMB() int { 344 return self.MemoryMB 345 } 346 347 func (self *SInstance) GetBootOrder() string { 348 return "dcn" 349 } 350 351 func (self *SInstance) GetVga() string { 352 return "std" 353 } 354 355 func (self *SInstance) GetVdi() string { 356 return "vnc" 357 } 358 359 func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { 360 if ins.osInfo == nil { 361 osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") 362 ins.osInfo = &osInfo 363 } 364 return ins.osInfo 365 } 366 367 func (ins *SInstance) GetOsType() cloudprovider.TOsType { 368 return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) 369 } 370 371 func (ins *SInstance) GetFullOsName() string { 372 return ins.OSName 373 } 374 375 func (ins *SInstance) GetBios() cloudprovider.TBiosType { 376 return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) 377 } 378 379 func (ins *SInstance) GetOsArch() string { 380 return ins.getNormalizedOsInfo().OsArch 381 } 382 383 func (ins *SInstance) GetOsDist() string { 384 return ins.getNormalizedOsInfo().OsDistro 385 } 386 387 func (ins *SInstance) GetOsVersion() string { 388 return ins.getNormalizedOsInfo().OsVersion 389 } 390 391 func (ins *SInstance) GetOsLang() string { 392 return ins.getNormalizedOsInfo().OsLang 393 } 394 395 func (self *SInstance) GetMachine() string { 396 return "pc" 397 } 398 399 func (self *SInstance) GetInstanceType() string { 400 // C1.c8.m24 401 if strings.HasPrefix(self.HostType, "G") { 402 return fmt.Sprintf("%s.c%d.m%d.g%d", self.HostType, self.CPU, self.MemoryMB/1014, self.GPU) 403 } else { 404 return fmt.Sprintf("%s.c%d.m%d", self.HostType, self.CPU, self.MemoryMB/1014) 405 } 406 } 407 408 func (self *SInstance) AssignSecurityGroup(secgroupId string) error { 409 return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupId) 410 } 411 412 // https://docs.ucloud.cn/api/unet-api/grant_firewall 413 func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { 414 if len(secgroupIds) == 0 { 415 return fmt.Errorf("SetSecurityGroups secgroup id should not be empty") 416 } else if len(secgroupIds) > 1 { 417 return fmt.Errorf("SetSecurityGroups only allowed to assign one secgroup id. %d given", len(secgroupIds)) 418 } 419 420 return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupIds[0]) 421 } 422 423 func (self *SInstance) GetHypervisor() string { 424 return api.HYPERVISOR_UCLOUD 425 } 426 427 func (self *SInstance) StartVM(ctx context.Context) error { 428 err := self.host.zone.region.StartVM(self.GetId()) 429 if err != nil { 430 return err 431 } 432 err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 10*time.Second, 600*time.Second) 433 if err != nil { 434 return errors.Wrap(err, "StartVM") 435 } 436 437 return nil 438 } 439 440 func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { 441 err := self.host.zone.region.StopVM(self.GetId()) 442 if err != nil { 443 return err 444 } 445 err = cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 10*time.Second, 10*time.Second, 600*time.Second) 446 if err != nil { 447 return errors.Wrap(err, "StopVM") 448 } 449 450 return nil 451 } 452 453 func (self *SInstance) DeleteVM(ctx context.Context) error { 454 return self.host.zone.region.DeleteVM(self.GetId()) 455 } 456 457 func (self *SInstance) UpdateVM(ctx context.Context, name string) error { 458 return self.host.zone.region.UpdateVM(self.GetId(), name) 459 } 460 461 func (self *SInstance) UpdateUserData(userData string) error { 462 return cloudprovider.ErrNotSupported 463 } 464 465 // https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance 466 // 1.请确认在重新安装之前,该实例已被关闭; 467 // 2.请确认该实例未挂载UDisk; 468 // todo:// 3.将原系统重装为不同类型的系统时(Linux->Windows),不可选择保留数据盘; 469 // 4.重装不同版本的系统时(CentOS6->CentOS7),若选择保留数据盘,请注意数据盘的文件系统格式; 470 // 5.若主机CPU低于2核,不可重装为Windows系统。 471 func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { 472 if len(desc.PublicKey) > 0 { 473 return "", fmt.Errorf("DeployVM not support assign ssh keypair") 474 } 475 476 if self.GetStatus() != api.VM_READY { 477 return "", fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) 478 } 479 480 if len(self.DiskSet) > 1 { 481 for _, disk := range self.DiskSet { 482 if disk.Type == "Data" { 483 err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) 484 if err != nil { 485 return "", fmt.Errorf("RebuildRoot detach disk %s", err) 486 } 487 488 defer self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) 489 } 490 491 } 492 } 493 494 err := self.host.zone.region.RebuildRoot(self.GetId(), desc.ImageId, desc.Password) 495 if err != nil { 496 return "", err 497 } 498 499 err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 15*time.Second, 300*time.Second) 500 if err != nil { 501 return "", errors.Wrap(err, "RebuildRoot") 502 } 503 504 disks, err := self.GetIDisks() 505 if len(disks) > 0 { 506 return disks[0].GetId(), nil 507 } else { 508 return "", fmt.Errorf("RebuildRoot %s", err) 509 } 510 } 511 512 func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { 513 if len(publicKey) > 0 { 514 return fmt.Errorf("DeployVM not support assign ssh keypair") 515 } 516 517 if deleteKeypair { 518 return fmt.Errorf("DeployVM not support delete ssh keypair") 519 } 520 521 if self.GetStatus() != api.VM_READY { 522 return fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) 523 } 524 525 if len(password) > 0 { 526 err := self.host.zone.region.ResetVMPasswd(self.GetId(), password) 527 if err != nil { 528 return err 529 } 530 } 531 532 err := cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) 533 if err != nil { 534 return errors.Wrap(err, "DeployVM") 535 } 536 537 return nil 538 } 539 540 func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { 541 if len(config.InstanceType) > 0 { 542 return self.ChangeConfig2(ctx, config.InstanceType) 543 } 544 return self.host.zone.region.ResizeVM(self.GetId(), config.Cpu, config.MemoryMB) 545 } 546 547 func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { 548 i, err := ParseInstanceType(instanceType) 549 if err != nil { 550 return err 551 } 552 553 return self.host.zone.region.ResizeVM(self.GetId(), i.CPU, i.MemoryMB) 554 } 555 556 func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { 557 return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) 558 } 559 560 func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { 561 return self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), diskId) 562 } 563 564 func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { 565 err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), diskId) 566 if err != nil { 567 return err 568 } 569 570 disk, err := self.host.zone.region.GetDisk(diskId) 571 if err != nil { 572 return err 573 } 574 575 disk.storage = &SStorage{zone: self.host.zone, storageType: disk.GetStorageType()} 576 err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 10*time.Second, 60*time.Second) 577 if err != nil { 578 return errors.Wrap(err, "DetachDisk") 579 } 580 581 return nil 582 } 583 584 func (self *SInstance) Renew(bc billing.SBillingCycle) error { 585 // return self.host.zone.region 586 return self.host.zone.region.RenewInstance(self.GetId(), bc) 587 } 588 589 func (self *SInstance) GetSecurityGroups() ([]SSecurityGroup, error) { 590 return self.host.zone.region.GetSecurityGroups("", self.GetId(), "") 591 } 592 593 // https://docs.ucloud.cn/api/uhost-api/get_uhost_instance_vnc_info 594 func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { 595 params := NewUcloudParams() 596 params.Set("UHostId", instanceId) 597 vnc := SVncInfo{} 598 err := self.DoAction("GetUHostInstanceVncInfo", params, &vnc) 599 if err != nil { 600 return nil, err 601 } 602 603 ret := &cloudprovider.ServerVncOutput{ 604 Host: vnc.VNCIP, 605 Port: vnc.VNCPort, 606 Password: vnc.VNCPassword, 607 Hypervisor: api.HYPERVISOR_UCLOUD, 608 } 609 return ret, nil 610 } 611 612 // https://docs.ucloud.cn/api/unet-api/grant_firewall 613 func (self *SRegion) assignSecurityGroups(instanceId string, secgroupId string) error { 614 params := NewUcloudParams() 615 params.Set("FWId", secgroupId) 616 params.Set("ResourceType", "uhost") 617 params.Set("ResourceId", instanceId) 618 619 return self.DoAction("GrantFirewall", params, nil) 620 } 621 622 // https://docs.ucloud.cn/api/uhost-api/start_uhost_instance 623 func (self *SRegion) StartVM(instanceId string) error { 624 params := NewUcloudParams() 625 params.Set("UHostId", instanceId) 626 627 return self.DoAction("StartUHostInstance", params, nil) 628 } 629 630 // https://docs.ucloud.cn/api/uhost-api/stop_uhost_instance 631 func (self *SRegion) StopVM(instanceId string) error { 632 params := NewUcloudParams() 633 params.Set("UHostId", instanceId) 634 635 return self.DoAction("StopUHostInstance", params, nil) 636 } 637 638 // https://docs.ucloud.cn/api/uhost-api/terminate_uhost_instance 639 func (self *SRegion) DeleteVM(instanceId string) error { 640 params := NewUcloudParams() 641 params.Set("UHostId", instanceId) 642 params.Set("Destroy", 1) // 跳过回收站,直接删除 643 644 return self.DoAction("TerminateUHostInstance", params, nil) 645 } 646 647 // https://docs.ucloud.cn/api/uhost-api/modify_uhost_instance_name 648 func (self *SRegion) UpdateVM(instanceId, name string) error { 649 params := NewUcloudParams() 650 params.Set("UHostId", instanceId) 651 params.Set("Name", name) 652 653 return self.DoAction("ModifyUHostInstanceName", params, nil) 654 } 655 656 // ChargeType : Dynamic(按需)/Month(按月)/Year(按年) 657 func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { 658 params := NewUcloudParams() 659 params.Set("ResourceId", instanceId) 660 params.Set("ResourceType", "Host") 661 662 if bc.GetMonths() >= 10 && bc.GetMonths() < 12 { 663 params.Set("ChargeType", "Year") 664 params.Set("Quantity", 1) 665 } else if bc.GetYears() >= 1 { 666 params.Set("ChargeType", "Year") 667 params.Set("Quantity", bc.GetYears()) 668 } else { 669 params.Set("ChargeType", "Month") 670 params.Set("Quantity", bc.GetMonths()) 671 } 672 673 return self.DoAction("CreateRenew", params, nil) 674 } 675 676 // https://docs.ucloud.cn/api/uhost-api/reset_uhost_instance_password 677 // 该操作需要UHost实例处于关闭状态。 678 func (self *SRegion) ResetVMPasswd(instanceId, password string) error { 679 params := NewUcloudParams() 680 params.Set("UHostId", instanceId) 681 params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) 682 683 return self.DoAction("ResetUHostInstancePassword", params, nil) 684 } 685 686 // https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance 687 // (密码格式使用BASE64编码;LoginMode不可变更) 688 func (self *SRegion) RebuildRoot(instanceId, imageId, password string) error { 689 params := NewUcloudParams() 690 params.Set("UHostId", instanceId) 691 params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) 692 params.Set("ImageId", imageId) 693 694 return self.DoAction("ReinstallUHostInstance", params, nil) 695 } 696 697 // https://docs.ucloud.cn/api/uhost-api/resize_uhost_instance 698 func (self *SRegion) ResizeVM(instanceId string, cpu, memoryMB int) error { 699 params := NewUcloudParams() 700 params.Set("UHostId", instanceId) 701 params.Set("CPU", cpu) 702 params.Set("Memory", memoryMB) 703 704 return self.DoAction("ResizeUHostInstance", params, nil) 705 }