mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
rebuild root bugfix
This commit is contained in:
@@ -184,11 +184,11 @@ func (self *SHuaweiGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
|
||||
|
||||
log.Debugf("VMrebuildRoot %s new diskID %s, wait status ready ...", iVM.GetGlobalId(), diskId)
|
||||
|
||||
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*1800)
|
||||
err = cloudprovider.WaitStatus(iVM, models.VM_RUNNING, time.Second*5, time.Second*1800)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("VMrebuildRoot %s, and status is ready", iVM.GetGlobalId())
|
||||
log.Debugf("VMrebuildRoot %s, and status is %s", iVM.GetGlobalId(), iVM.GetStatus())
|
||||
|
||||
maxWaitSecs := 300
|
||||
waited := 0
|
||||
|
||||
@@ -4,7 +4,10 @@ package huawei
|
||||
const DATETIME_FORMAT = "2006-01-02T15:04:05.999999999"
|
||||
|
||||
// Task status
|
||||
const TASK_SUCCESS = "SUCCESS"
|
||||
const (
|
||||
TASK_SUCCESS = "SUCCESS"
|
||||
TASK_FAIL = "FAIL"
|
||||
)
|
||||
|
||||
// Charging Type
|
||||
const (
|
||||
|
||||
@@ -95,6 +95,7 @@ type SDisk struct {
|
||||
ConsistencygroupID string `json:"consistencygroup_id"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
|
||||
DiskType string // 额外添加的字段用于标记是否为系统盘
|
||||
/*下面这些字段也许不需要*/
|
||||
ExpiredTime time.Time
|
||||
}
|
||||
@@ -233,8 +234,14 @@ func (self *SDisk) GetTemplateId() string {
|
||||
return self.VolumeImageMetadata.ImageID
|
||||
}
|
||||
|
||||
// Bootable 表示硬盘是否为启动盘。
|
||||
// 启动盘 != 系统盘(必须是启动盘且挂载在root device上)
|
||||
func (self *SDisk) GetDiskType() string {
|
||||
if self.Bootable == "true" {
|
||||
if self.Bootable != "true" || len(self.Attachments) == 0 {
|
||||
return models.DISK_TYPE_DATA
|
||||
}
|
||||
|
||||
if self.DiskType == models.DISK_TYPE_SYS {
|
||||
return models.DISK_TYPE_SYS
|
||||
} else {
|
||||
return models.DISK_TYPE_DATA
|
||||
|
||||
+68
-17
@@ -96,7 +96,6 @@ type SInstance struct {
|
||||
Tags []string `json:"tags"`
|
||||
Description string `json:"description"`
|
||||
Locked bool `json:"locked"`
|
||||
Image Image `json:"image"`
|
||||
ConfigDrive string `json:"config_drive"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
UserID string `json:"user_id"`
|
||||
@@ -156,6 +155,25 @@ func compareSet(currentSet []string, newSet []string) (add []string, remove []st
|
||||
return add, remove, keep
|
||||
}
|
||||
|
||||
func markDiskType(server *SInstance, disk *SDisk) {
|
||||
if disk.Bootable != "true" {
|
||||
return
|
||||
}
|
||||
|
||||
if len(disk.Attachments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, attachment := range disk.Attachments {
|
||||
if attachment.ServerID == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName {
|
||||
disk.DiskType = models.DISK_TYPE_SYS
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (self *SInstance) GetId() string {
|
||||
return self.ID
|
||||
}
|
||||
@@ -216,9 +234,9 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
|
||||
priceKey := fmt.Sprintf("%s::%s::%s", self.host.zone.region.GetId(), self.GetInstanceType(), lowerOs)
|
||||
data.Add(jsonutils.NewString(priceKey), "price_key")
|
||||
data.Add(jsonutils.NewString(self.host.zone.GetGlobalId()), "zone_ext_id")
|
||||
if len(self.Image.ID) > 0 {
|
||||
if image, err := self.host.zone.region.GetImage(self.Image.ID); err != nil {
|
||||
log.Errorf("Failed to find image %s for instance %s zone %s", self.Image.ID, self.GetId(), self.OSEXTAZAvailabilityZone)
|
||||
if len(self.Metadata.MeteringImageID) > 0 {
|
||||
if image, err := self.host.zone.region.GetImage(self.Metadata.MeteringImageID); err != nil {
|
||||
log.Errorf("Failed to find image %s for instance %s zone %s", self.Metadata.MeteringImageID, self.GetId(), self.OSEXTAZAvailabilityZone)
|
||||
} else if meta := image.GetMetadata(); meta != nil {
|
||||
data.Update(meta)
|
||||
}
|
||||
@@ -281,6 +299,7 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
}
|
||||
disks[i].storage = storage
|
||||
idisks[i] = &disks[i]
|
||||
markDiskType(self, &disks[i])
|
||||
// todo: 通过这个字段判断可能更准确 "OS-EXT-SRV-ATTR:root_device_name": "/dev/vda"
|
||||
// 将系统盘放到第0个位置
|
||||
if disks[i].GetDiskType() == models.DISK_TYPE_SYS {
|
||||
@@ -481,20 +500,40 @@ func (self *SInstance) UpdateUserData(userData string) error {
|
||||
// todo: 支持注入user_data
|
||||
func (self *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
|
||||
var err error
|
||||
if self.Image.ID == imageId {
|
||||
err = self.host.zone.region.RebuildRoot(ctx, self.GetId(), passwd, publicKey)
|
||||
var jobId string
|
||||
if self.Metadata.MeteringImageID == imageId {
|
||||
jobId, err = self.host.zone.region.RebuildRoot(ctx, self.GetId(), passwd, publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
err = self.host.zone.region.ChangeRoot(ctx, self.GetId(), imageId, passwd, publicKey)
|
||||
jobId, err = self.host.zone.region.ChangeRoot(ctx, self.GetId(), imageId, passwd, publicKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// todo: wait job finished here
|
||||
return "", nil
|
||||
err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second)
|
||||
if err != nil {
|
||||
log.Errorf("RebuildRoot task error %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = self.Refresh()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
idisks, err := self.GetIDisks()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(idisks) == 0 {
|
||||
return "", fmt.Errorf("server %s has no volume attached.", self.GetId())
|
||||
}
|
||||
|
||||
return idisks[0].GetId(), nil
|
||||
}
|
||||
|
||||
func (self *SInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error {
|
||||
@@ -883,7 +922,9 @@ func (self *SRegion) UpdateVM(instanceId, name string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SRegion) RebuildRoot(ctx context.Context, instanceId, passwd, publicKeyName string) error {
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html
|
||||
// 返回job id
|
||||
func (self *SRegion) RebuildRoot(ctx context.Context, instanceId, passwd, publicKeyName string) (string, error) {
|
||||
params := jsonutils.NewDict()
|
||||
reinstallObj := jsonutils.NewDict()
|
||||
// meta := jsonutils.NewDict()
|
||||
@@ -893,15 +934,21 @@ func (self *SRegion) RebuildRoot(ctx context.Context, instanceId, passwd, public
|
||||
} else if len(publicKeyName) > 0 {
|
||||
reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname")
|
||||
} else {
|
||||
return fmt.Errorf("both password and publicKey are empty.")
|
||||
return "", fmt.Errorf("both password and publicKey are empty.")
|
||||
}
|
||||
|
||||
params.Add(reinstallObj, "os-reinstall")
|
||||
_, err := self.ecsClient.Servers.PerformAction2("reinstallos", instanceId, params, "")
|
||||
return err
|
||||
ret, err := self.ecsClient.Servers.PerformAction2("reinstallos", instanceId, params, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ret.GetString("job_id")
|
||||
}
|
||||
|
||||
func (self *SRegion) ChangeRoot(ctx context.Context, instanceId, imageId, passwd, publicKeyName string) error {
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html
|
||||
// 返回job id
|
||||
func (self *SRegion) ChangeRoot(ctx context.Context, instanceId, imageId, passwd, publicKeyName string) (string, error) {
|
||||
params := jsonutils.NewDict()
|
||||
changeOsObj := jsonutils.NewDict()
|
||||
// meta := jsonutils.NewDict()
|
||||
@@ -911,14 +958,18 @@ func (self *SRegion) ChangeRoot(ctx context.Context, instanceId, imageId, passwd
|
||||
} else if len(publicKeyName) > 0 {
|
||||
changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname")
|
||||
} else {
|
||||
return fmt.Errorf("both password and publicKey are empty.")
|
||||
return "", fmt.Errorf("both password and publicKey are empty.")
|
||||
}
|
||||
|
||||
changeOsObj.Add(jsonutils.NewString(imageId), "imageid")
|
||||
params.Add(changeOsObj, "os-change")
|
||||
|
||||
_, err := self.ecsClient.Servers.PerformAction2("changeos", instanceId, params, "")
|
||||
return err
|
||||
ret, err := self.ecsClient.Servers.PerformAction2("changeos", instanceId, params, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ret.GetString("job_id")
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html
|
||||
|
||||
+11
-1
@@ -1,7 +1,10 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
func (self *SRegion) waitTaskStatus(serviceType string, taskId string, targetStatus string, interval time.Duration, timeout time.Duration) error {
|
||||
@@ -13,6 +16,8 @@ func (self *SRegion) waitTaskStatus(serviceType string, taskId string, targetSta
|
||||
}
|
||||
if status == targetStatus {
|
||||
break
|
||||
} else if status == TASK_FAIL {
|
||||
return fmt.Errorf("task %s failed", taskId)
|
||||
} else {
|
||||
time.Sleep(interval)
|
||||
}
|
||||
@@ -27,7 +32,12 @@ func (self *SRegion) GetTaskStatus(serviceType string, taskId string) (string, e
|
||||
return "", err
|
||||
}
|
||||
|
||||
return task.GetString("status")
|
||||
status, err := task.GetString("status")
|
||||
if status == TASK_FAIL {
|
||||
log.Debugf("task %s failed: %s", taskId, task.String())
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022225398.html
|
||||
|
||||
Reference in New Issue
Block a user