diff --git a/cmd/climc/shell/cloudmeta.go b/cmd/climc/shell/cloudmeta.go index 6fa020a639..25beae7eab 100644 --- a/cmd/climc/shell/cloudmeta.go +++ b/cmd/climc/shell/cloudmeta.go @@ -7,8 +7,8 @@ import ( func init() { type CloudmetaOptions struct { PROVIDER_ID string `help:"provider_id"` - REGION_ID string `help:"region_id"` - ZONE_ID string `help:"zone_id"` + REGION_ID string `help:"region_id"` + ZONE_ID string `help:"zone_id"` } R(&CloudmetaOptions{}, "instance-type-list", "query backend service for its version", func(s *mcclient.ClientSession, args *CloudmetaOptions) error { return nil diff --git a/pkg/cloudcommon/db/taskman/interface.go b/pkg/cloudcommon/db/taskman/interface.go index 39b56b2525..e4735c42b1 100644 --- a/pkg/cloudcommon/db/taskman/interface.go +++ b/pkg/cloudcommon/db/taskman/interface.go @@ -2,6 +2,7 @@ package taskman import ( "context" + "net/http" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" @@ -14,6 +15,8 @@ type ITask interface { GetTaskId() string SetStage(stageName string, data *jsonutils.JSONDict) + GetTaskRequestHeader() http.Header + SetStageComplete(ctx context.Context, data *jsonutils.JSONDict) SetStageFailed(ctx context.Context, reason string) } diff --git a/pkg/cloudcommon/db/taskman/localtaskworker.go b/pkg/cloudcommon/db/taskman/localtaskworker.go index 57eaf00fb5..1adf2d9ac0 100644 --- a/pkg/cloudcommon/db/taskman/localtaskworker.go +++ b/pkg/cloudcommon/db/taskman/localtaskworker.go @@ -18,7 +18,7 @@ func init() { func Error2TaskData(err error) jsonutils.JSONObject { errJson := jsonutils.NewDict() errJson.Add(jsonutils.NewString("ERROR"), "__status__") - errJson.Add(jsonutils.NewString(err.Error()), "reason") + errJson.Add(jsonutils.NewString(err.Error()), "__reason__") return errJson } diff --git a/pkg/cloudcommon/db/taskman/tasks.go b/pkg/cloudcommon/db/taskman/tasks.go index 5460fff7cc..e588bb9825 100644 --- a/pkg/cloudcommon/db/taskman/tasks.go +++ b/pkg/cloudcommon/db/taskman/tasks.go @@ -423,7 +423,7 @@ func execITask(taskValue reflect.Value, task *STask, odata jsonutils.JSONObject, return } - log.Debugf("Call %s %s", task.TaskName, stageName) + log.Debugf("Call %s %s %#v", task.TaskName, stageName, params) funcValue.Call(params) // call save request context @@ -648,3 +648,11 @@ func (self *STask) GetObject() db.IStandaloneModel { func (self *STask) GetObjects() []db.IStandaloneModel { return self.taskObjects } + +func (task *STask) GetTaskRequestHeader() http.Header { + header := http.Header{} + header.Set(mcclient.AUTH_TOKEN, task.GetUserCred().GetTokenString()) + header.Set(mcclient.TASK_ID, task.GetTaskId()) + header.Set(mcclient.REGION_VERSION, "v2") + return header +} diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index a464146704..ff81090e9b 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -27,12 +27,12 @@ type ICloudProvider interface { GetIRegions() []ICloudRegion GetIRegionById(id string) (ICloudRegion, error) - GetOnPremiseIHosts() ([]ICloudHost, error) + GetOnPremiseIRegion() (ICloudRegion, error) - GetIHostById(id string) (ICloudHost, error) - GetIVpcById(id string) (ICloudVpc, error) - GetIStorageById(id string) (ICloudStorage, error) - GetIStoragecacheById(id string) (ICloudStoragecache, error) + // GetIHostById(id string) (ICloudHost, error) + // GetIVpcById(id string) (ICloudVpc, error) + // GetIStorageById(id string) (ICloudStorage, error) + // GetIStoragecacheById(id string) (ICloudStoragecache, error) GetBalance() (float64, error) diff --git a/pkg/cloudprovider/fakeregion.go b/pkg/cloudprovider/fakeregion.go new file mode 100644 index 0000000000..53020b35de --- /dev/null +++ b/pkg/cloudprovider/fakeregion.go @@ -0,0 +1,76 @@ +package cloudprovider + +import ( + "yunion.io/x/jsonutils" +) + +type SFakeOnPremiseRegion struct { +} + +func (region *SFakeOnPremiseRegion) GetId() string { + return "default" +} + +func (region *SFakeOnPremiseRegion) GetName() string { + return "Default" +} + +func (region *SFakeOnPremiseRegion) GetGlobalId() string { + return "default" +} + +func (region *SFakeOnPremiseRegion) GetStatus() string { + return "available" +} + +func (region *SFakeOnPremiseRegion) Refresh() error { + return nil +} + +func (region *SFakeOnPremiseRegion) IsEmulated() bool { + return true +} + +func (region *SFakeOnPremiseRegion) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (region *SFakeOnPremiseRegion) GetLatitude() float32 { + return 0.0 +} + +func (region *SFakeOnPremiseRegion) GetLongitude() float32 { + return 0.0 +} + +func (region *SFakeOnPremiseRegion) GetIZones() ([]ICloudZone, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) GetIZoneById(id string) (ICloudZone, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) GetIVpcById(id string) (ICloudVpc, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) GetIVpcs() ([]ICloudVpc, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) GetIEips() ([]ICloudEIP, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) GetIEipById(id string) (ICloudEIP, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error) { + return nil, ErrNotSupported +} + +func (region *SFakeOnPremiseRegion) CreateEIP(name string, bwMbps int, chargeType string) (ICloudEIP, error) { + return nil, ErrNotSupported +} diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 83a810f1c9..f49e7af6ef 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -36,20 +36,21 @@ type ICloudRegion interface { GetIZones() ([]ICloudZone, error) GetIVpcs() ([]ICloudVpc, error) GetIEips() ([]ICloudEIP, error) - GetISnapshots() ([]ICloudSnapshot, error) - - GetISnapshotById(snapshotId string) (ICloudSnapshot, error) - GetIZoneById(id string) (ICloudZone, error) GetIVpcById(id string) (ICloudVpc, error) - GetIHostById(id string) (ICloudHost, error) - GetIStorageById(id string) (ICloudStorage, error) - GetIStoragecacheById(id string) (ICloudStoragecache, error) + GetIZoneById(id string) (ICloudZone, error) + GetIEipById(id string) (ICloudEIP, error) CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error) - CreateEIP(name string, bwMbps int, chargeType string) (ICloudEIP, error) - GetIEipById(id string) (ICloudEIP, error) + GetISnapshots() ([]ICloudSnapshot, error) + GetISnapshotById(snapshotId string) (ICloudSnapshot, error) + + GetIHosts() ([]ICloudHost, error) + GetIHostById(id string) (ICloudHost, error) + + GetIStorages() ([]ICloudStorage, error) + GetIStorageById(id string) (ICloudStorage, error) GetProvider() string } @@ -69,7 +70,7 @@ type ICloudZone interface { type ICloudImage interface { ICloudResource - Delete() error + Delete(ctx context.Context) error GetIStoragecache() ICloudStoragecache } @@ -77,6 +78,9 @@ type ICloudStoragecache interface { ICloudResource GetIImages() ([]ICloudImage, error) + GetIImageById(extId string) (ICloudImage, error) + + GetPath() string GetManagerId() string @@ -104,7 +108,10 @@ type ICloudStorage interface { GetManagerId() string CreateIDisk(name string, sizeGb int, desc string) (ICloudDisk, error) - GetIDisk(idStr string) (ICloudDisk, error) + + GetIDiskById(idStr string) (ICloudDisk, error) + + GetMountPoint() string } type ICloudHost interface { @@ -186,10 +193,12 @@ type ICloudVM interface { DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error - ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error + ChangeConfig(ctx context.Context, ncpu int, vmem int) error GetVNCInfo() (jsonutils.JSONObject, error) AttachDisk(ctx context.Context, diskId string) error DetachDisk(ctx context.Context, diskId string) error + + CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error } type ICloudNic interface { @@ -245,13 +254,16 @@ type ICloudDisk interface { GetDriver() string GetCacheMode() string GetMountpoint() string + + GetAccessPath() string + Delete(ctx context.Context) error CreateISnapshot(ctx context.Context, name string, desc string) (ICloudSnapshot, error) GetISnapshot(idStr string) (ICloudSnapshot, error) GetISnapshots() ([]ICloudSnapshot, error) - Resize(ctx context.Context, newSize int64) error + Resize(ctx context.Context, newSizeMB int64) error Reset(ctx context.Context, snapshotId string) error } diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 9f119b98b2..6d5ead7901 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -11,7 +11,6 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -96,78 +95,6 @@ func (self *SAliyunGuestDriver) ValidateCreateData(ctx context.Context, userCred return data, nil } -type SDiskInfo struct { - DiskType string - Size int - Uuid string - BillingType string - FsFromat string - AutoDelete bool - TemplateId string - DiskFormat string - ExpiredAt time.Time - - Metadata map[string]string -} - -func fetchIVMinfo(desc SManagedVMCreateConfig, iVM cloudprovider.ICloudVM, guestId string, account, passwd string, action string) *jsonutils.JSONDict { - data := jsonutils.NewDict() - - data.Add(jsonutils.NewString(iVM.GetOSType()), "os") - - if len(passwd) > 0 { - encpasswd, err := utils.EncryptAESBase64(guestId, passwd) - if err != nil { - log.Errorf("encrypt password failed %s", err) - } - data.Add(jsonutils.NewString(account), "account") - data.Add(jsonutils.NewString(encpasswd), "key") - } - - if len(desc.OsDistribution) > 0 { - data.Add(jsonutils.NewString(desc.OsDistribution), "distro") - } - if len(desc.OsVersion) > 0 { - data.Add(jsonutils.NewString(desc.OsVersion), "version") - } - - idisks, err := iVM.GetIDisks() - - if err != nil { - log.Errorf("GetiDisks error %s", err) - } else { - diskInfo := make([]SDiskInfo, len(idisks)) - for i := 0; i < len(idisks); i += 1 { - dinfo := SDiskInfo{} - dinfo.Uuid = idisks[i].GetGlobalId() - dinfo.Size = idisks[i].GetDiskSizeMB() - dinfo.DiskType = idisks[i].GetDiskType() - dinfo.BillingType = idisks[i].GetBillingType() - dinfo.DiskFormat = idisks[i].GetDiskFormat() - dinfo.AutoDelete = idisks[i].GetIsAutoDelete() - if action == "create" { - dinfo.AutoDelete = true - } - dinfo.TemplateId = idisks[i].GetTemplateId() - dinfo.FsFromat = idisks[i].GetFsFormat() - dinfo.ExpiredAt = idisks[i].GetExpiredAt() - if metaData := idisks[i].GetMetadata(); metaData != nil { - dinfo.Metadata = make(map[string]string, 0) - if err := metaData.Unmarshal(dinfo.Metadata); err != nil { - log.Errorf("Get disk %s metadata info error: %v", idisks[i].GetName(), err) - } - } - diskInfo[i] = dinfo - } - data.Add(jsonutils.Marshal(&diskInfo), "disks") - } - - data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid") - data.Add(iVM.GetMetadata(), "metadata") - - return data -} - func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { config := guest.GetDeployConfigOnHost(ctx, host, task.GetParams()) log.Debugf("RequestDeployGuestOnHost: %s", config) @@ -243,65 +170,8 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu return nil, err } - /*if len(guest.SecgrpId) > 0 { - if err := iVM.SyncSecurityGroup(guest.SecgrpId, guest.GetSecgroupName(), guest.GetSecRules()); err != nil { - log.Errorf("SyncSecurityGroup error: %v", err) - return nil, err - } - }*/ - - /*if onfinish == "none" { - err = iVM.StartVM() - if err != nil { - return nil, err - } - }*/ - data := fetchIVMinfo(desc, iVM, guest.Id, "root", passwd, action) - /* data.Add(jsonutils.NewString(iVM.GetOSType()), "os") - - if len(passwd) > 0 { - encpasswd, err := utils.EncryptAESBase64(guest.Id, passwd) - if err != nil { - log.Errorf("encrypt password failed %s", err) - } - data.Add(jsonutils.NewString("root"), "account") - data.Add(jsonutils.NewString(encpasswd), "key") - } - - if len(desc.OsDistribution) > 0 { - data.Add(jsonutils.NewString(desc.OsDistribution), "distro") - } - if len(desc.OsVersion) > 0 { - data.Add(jsonutils.NewString(desc.OsVersion), "version") - } - - idisks, err := iVM.GetIDisks() - - if err != nil { - log.Errorf("GetiDisks error %s", err) - } else { - diskInfo := make([]SDiskInfo, len(idisks)) - for i := 0; i < len(idisks); i += 1 { - dinfo := SDiskInfo{} - dinfo.Uuid = idisks[i].GetGlobalId() - dinfo.Size = idisks[i].GetDiskSizeMB() - if metaData := idisks[i].GetMetadata(); metaData != nil { - dinfo.Metadata = make(map[string]string, 0) - if err := metaData.Unmarshal(dinfo.Metadata); err != nil { - log.Errorf("Get disk %s metadata info error: %v", idisks[i].GetName(), err) - } - } - diskInfo[i] = dinfo - } - data.Add(jsonutils.Marshal(&diskInfo), "disks") - } - - data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid") - data.Add(iVM.GetMetadata(), "metadata") - */ - return data, nil }) } else if action == "deploy" { @@ -346,20 +216,6 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu data := fetchIVMinfo(desc, iVM, guest.Id, "root", passwd, action) - /* - data := jsonutils.NewDict() - - if len(passwd) > 0 { - encpasswd, err := utils.EncryptAESBase64(guest.Id, passwd) - if err != nil { - log.Errorf("encrypt password failed %s", err) - } - - - data.Add(jsonutils.NewString("root"), "account") // 用户名 - data.Add(jsonutils.NewString(encpasswd), "key") // 密码 - }*/ - return data, nil }) } else if action == "rebuild" { @@ -432,75 +288,6 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu return nil } -func (self *SAliyunGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { - - if data.Contains("disks") { - diskInfo := make([]SDiskInfo, 0) - err := data.Unmarshal(&diskInfo, "disks") - if err != nil { - return err - } - disks := guest.GetDisks() - if len(disks) != len(diskInfo) { - msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) - log.Errorf(msg) - return fmt.Errorf(msg) - } - for i := 0; i < len(diskInfo); i += 1 { - disk := disks[i].GetDisk() - _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.DiskSize = diskInfo[i].Size - disk.ExternalId = diskInfo[i].Uuid - disk.DiskType = diskInfo[i].DiskType - disk.Status = models.DISK_READY - disk.BillingType = diskInfo[i].BillingType - disk.FsFormat = diskInfo[i].FsFromat - if diskInfo[i].AutoDelete { - disk.AutoDelete = true - } - // disk.TemplateId = diskInfo[i].TemplateId - disk.DiskFormat = diskInfo[i].DiskFormat - disk.ExpiredAt = diskInfo[i].ExpiredAt - if len(diskInfo[i].Metadata) > 0 { - for key, value := range diskInfo[i].Metadata { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - return nil - }) - if err != nil { - msg := fmt.Sprintf("save disk info failed %s", err) - log.Errorf(msg) - break - } else { - db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred()) - } - } - } - uuid, _ := data.GetString("uuid") - if len(uuid) > 0 { - guest.SetExternalId(uuid) - } - - if metaData, _ := data.Get("metadata"); metaData != nil { - meta := make(map[string]string, 0) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get guest %s metadata error: %v", guest.Name, err) - } else { - for key, value := range meta { - if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err) - } - } - } - } - - guest.SaveDeployInfo(ctx, task.GetUserCred(), data) - return nil -} - func (self *SAliyunGuestDriver) AllowReconfigGuest() bool { return true } diff --git a/pkg/compute/guestdrivers/aws.go b/pkg/compute/guestdrivers/aws.go index 0a9f101397..d0ecf9d556 100644 --- a/pkg/compute/guestdrivers/aws.go +++ b/pkg/compute/guestdrivers/aws.go @@ -9,7 +9,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -20,6 +19,11 @@ type SAwsGuestDriver struct { SManagedVirtualizedGuestDriver } +func init() { + driver := SAwsGuestDriver{} + models.RegisterGuestDriver(&driver) +} + func (self *SAwsGuestDriver) GetHypervisor() string { return models.HYPERVISOR_AWS } @@ -223,74 +227,3 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest return nil } - -func (self *SAwsGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { - if data.Contains("disks") { - diskInfo := make([]SDiskInfo, 0) - err := data.Unmarshal(&diskInfo, "disks") - if err != nil { - return err - } - disks := guest.GetDisks() - if len(disks) != len(diskInfo) { - msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) - log.Errorf(msg) - return fmt.Errorf(msg) - } - for i := 0; i < len(diskInfo); i += 1 { - disk := disks[i].GetDisk() - _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.DiskSize = diskInfo[i].Size - disk.ExternalId = diskInfo[i].Uuid - disk.DiskType = diskInfo[i].DiskType - disk.Status = models.DISK_READY - disk.BillingType = diskInfo[i].BillingType - disk.FsFormat = diskInfo[i].FsFromat - disk.AutoDelete = true - //disk.TemplateId = diskInfo[i].TemplateId - disk.DiskFormat = diskInfo[i].DiskFormat - disk.ExpiredAt = diskInfo[i].ExpiredAt - if len(diskInfo[i].Metadata) > 0 { - for key, value := range diskInfo[i].Metadata { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - return nil - }) - if err != nil { - msg := fmt.Sprintf("save disk info failed %s", err) - log.Errorf(msg) - break - } else { - db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred()) - } - } - } - uuid, _ := data.GetString("uuid") - if len(uuid) > 0 { - guest.SetExternalId(uuid) - } - - if metaData, _ := data.Get("metadata"); metaData != nil { - meta := make(map[string]string, 0) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get guest %s metadata error: %v", guest.Name, err) - } else { - for key, value := range meta { - if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err) - } - } - } - } - - guest.SaveDeployInfo(ctx, task.GetUserCred(), data) - return nil -} - -func init() { - driver := SAwsGuestDriver{} - models.RegisterGuestDriver(&driver) -} diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 695544f7be..09541353cb 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -14,7 +14,6 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -216,70 +215,3 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue } return nil } - -func (self *SAzureGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { - - if data.Contains("disks") { - diskInfo := make([]SDiskInfo, 0) - err := data.Unmarshal(&diskInfo, "disks") - if err != nil { - return err - } - disks := guest.GetDisks() - if len(disks) != len(diskInfo) { - msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) - log.Errorf(msg) - return fmt.Errorf(msg) - } - for i := 0; i < len(diskInfo); i++ { - disk := disks[i].GetDisk() - _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.DiskSize = diskInfo[i].Size - disk.ExternalId = diskInfo[i].Uuid - disk.DiskType = diskInfo[i].DiskType - disk.Status = models.DISK_READY - disk.BillingType = diskInfo[i].BillingType - disk.FsFormat = diskInfo[i].FsFromat - disk.AutoDelete = diskInfo[i].AutoDelete - // disk.TemplateId = diskInfo[i].TemplateId - disk.DiskFormat = diskInfo[i].DiskFormat - disk.ExpiredAt = diskInfo[i].ExpiredAt - if len(diskInfo[i].Metadata) > 0 { - for key, value := range diskInfo[i].Metadata { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - return nil - }) - if err != nil { - msg := fmt.Sprintf("save disk info failed %s", err) - log.Errorf(msg) - break - } else { - db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred()) - } - } - } - uuid, _ := data.GetString("uuid") - if len(uuid) > 0 { - guest.SetExternalId(uuid) - } - - if metaData, _ := data.Get("metadata"); metaData != nil { - meta := make(map[string]string, 0) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get guest %s metadata error: %v", guest.Name, err) - } else { - for key, value := range meta { - if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err) - } - } - } - } - - guest.SaveDeployInfo(ctx, task.GetUserCred(), data) - return nil -} diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 8d9207b7c2..a406790d43 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -185,9 +185,5 @@ func (self *SBaseGuestDriver) RequestReloadDiskSnapshot(ctx context.Context, gue } func (self *SBaseGuestDriver) getTaskRequestHeader(task taskman.ITask) http.Header { - header := http.Header{} - header.Set(mcclient.AUTH_TOKEN, task.GetUserCred().GetTokenString()) - header.Set(mcclient.TASK_ID, task.GetTaskId()) - header.Set(mcclient.REGION_VERSION, "v2") - return header + return task.GetTaskRequestHeader() } diff --git a/pkg/compute/guestdrivers/container.go b/pkg/compute/guestdrivers/container.go index 3d57546971..0a5b56e406 100644 --- a/pkg/compute/guestdrivers/container.go +++ b/pkg/compute/guestdrivers/container.go @@ -112,6 +112,10 @@ func (self *SContainerDriver) OnGuestDeployTaskComplete(ctx context.Context, gue return nil } +func (self *SContainerDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject { + return guest.GetJsonDescAtHypervisor(ctx, host) +} + func (self *SContainerDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { config := guest.GetDeployConfigOnHost(ctx, host, task.GetParams()) config.Add(jsonutils.JSONTrue, "k8s_pod") diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index 7d06890ba5..98010911a3 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -2,6 +2,12 @@ package guestdrivers import ( "context" + "fmt" + "net/http" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" @@ -33,6 +39,10 @@ func (self *SESXiGuestDriver) GetAttachDiskStatus() ([]string, error) { return []string{models.VM_READY}, nil } +func (self *SESXiGuestDriver) GetChangeConfigStatus() ([]string, error) { + return []string{models.VM_READY}, nil +} + func (self *SESXiGuestDriver) CanKeepDetachDisk() bool { return false } @@ -50,3 +60,107 @@ func (self *SESXiGuestDriver) RequestGuestHotAddIso(ctx context.Context, guest * task.ScheduleRun(nil) return nil } + +func (self *SESXiGuestDriver) GetRebuildRootStatus() ([]string, error) { + return []string{models.VM_READY}, nil +} + +func (self *SESXiGuestDriver) GetDeployStatus() ([]string, error) { + return []string{models.VM_READY}, nil +} + +func (self *SESXiGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error { + if !utils.IsInStringArray(guest.Status, []string{models.VM_READY}) { + return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status) + } + if disk.DiskType == models.DISK_TYPE_SYS { + return fmt.Errorf("Cannot resize system disk") + } + /*if !utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_PUBLIC_CLOUD, models.STORAGE_CLOUD_SSD, models.STORAGE_CLOUD_EFFICIENCY}) { + return fmt.Errorf("Cannot resize %s disk", storage.StorageType) + }*/ + return nil +} + +func (self *SESXiGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) +} + +func (self *SESXiGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject { + return guest.GetJsonDescAtHypervisor(ctx, host) +} + +func (self *SESXiGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { + config := guest.GetDeployConfigOnHost(ctx, host, task.GetParams()) + log.Debugf("RequestDeployGuestOnHost: %s", config) + + agent, err := host.GetEsxiAgentHost() + if err != nil { + return err + } + if agent == nil { + return fmt.Errorf("No ESXi agent host") + } + + diskCat := guest.CategorizeDisks() + if diskCat.Root == nil { + return fmt.Errorf("no root disk???") + } + storage := diskCat.Root.GetStorage() + if storage == nil { + return fmt.Errorf("root disk has no storage???") + } + + config.Add(jsonutils.NewString(host.AccessIp), "host_ip") + config.Add(jsonutils.NewString(guest.Id), "guest_id") + + accessInfo, err := host.GetCloudaccount().GetVCenterAccessInfo(storage.ExternalId) + if err != nil { + return err + } + config.Add(jsonutils.Marshal(accessInfo), "datastore") + + url := "/disks/agent/deploy" + + body := jsonutils.NewDict() + body.Add(config, "disk") + + header := http.Header{} + header.Add("X-Task-Id", task.GetTaskId()) + header.Add("X-Region-Version", "v2") + + _, err = agent.Request(task.GetUserCred(), "POST", url, header, body) + return err +} + +func (self *SESXiGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { + + if data.Contains("host_ip") { + hostIp, _ := data.GetString("host_ip") + host, err := models.HostManager.GetHostByIp(hostIp) + if err != nil { + log.Errorf("fail to find host with IP %s: %s", hostIp, err) + return err + } + if host.Id != guest.HostId { + models.HostManager.ClearSchedDescCache(host.Id) + models.HostManager.ClearSchedDescCache(guest.HostId) + guest.SetHostId(host.Id) + } + } + + return self.SManagedVirtualizedGuestDriver.OnGuestDeployTaskDataReceived(ctx, guest, task, data) +} + +func (self *SESXiGuestDriver) AllowReconfigGuest() bool { + return true +} + +func (self *SESXiGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + subtask, err := taskman.TaskManager.NewTask(ctx, "ESXiGuestCreateDiskTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil) + if err != nil { + return err + } + subtask.ScheduleRun(nil) + return nil +} diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 1cb9d0d586..4c3be6b1cd 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -179,6 +179,10 @@ func (self *SKVMGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, gue return nil } +func (self *SKVMGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject { + return guest.GetJsonDescAtHypervisor(ctx, host) +} + func (self *SKVMGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { config := guest.GetDeployConfigOnHost(ctx, host, task.GetParams()) log.Debugf("RequestDeployGuestOnHost: %s", config) @@ -207,7 +211,7 @@ func (self *SKVMGuestDriver) RequestStartOnHost(ctx context.Context, guest *mode header := self.getTaskRequestHeader(task) config := jsonutils.NewDict() - desc := self.GetJsonDescAtHost(ctx, guest, host) + desc := guest.GetDriver().GetJsonDescAtHost(ctx, guest, host) config.Add(desc, "desc") params := task.GetParams() if params.Length() > 0 { diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 4d0c3aa63d..9b28e82b0a 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/secrules" + "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -116,10 +117,6 @@ func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context return nil } -func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { - return nil -} - func (self *SManagedVirtualizedGuestDriver) RequestStartOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) (jsonutils.JSONObject, error) { ihost, e := host.GetIHost() if e != nil { @@ -149,18 +146,20 @@ func (self *SManagedVirtualizedGuestDriver) RequestUndeployGuestOnHost(ctx conte taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { ihost, err := host.GetIHost() if err != nil { + log.Errorf("host.GetIHost fail %s", err) return nil, err } ivm, err := ihost.GetIVMById(guest.ExternalId) if err != nil { if err == cloudprovider.ErrNotFound { return nil, nil - } else { - return nil, err } + log.Errorf("ihost.GetIVMById fail %s", err) + return nil, err } err = ivm.DeleteVM(ctx) if err != nil { + log.Errorf("ivm.DeleteVM fail %s", err) return nil, err } @@ -170,12 +169,13 @@ func (self *SManagedVirtualizedGuestDriver) RequestUndeployGuestOnHost(ctx conte if err != nil { if err == cloudprovider.ErrNotFound { continue - } else { - return nil, err } + log.Errorf("disk.GetIDisk fail %s", err) + return nil, err } err = idisk.Delete(ctx) if err != nil { + log.Errorf("idisk.Delete fail %s", err) return nil, err } } @@ -297,7 +297,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co } if int(guest.VcpuCount) != config.Cpu || guest.VmemSize != config.Memory { - err = iVM.ChangeConfig(ctx, config.InstanceId, config.Cpu, config.Memory) + err = iVM.ChangeConfig(ctx, config.Cpu, config.Memory) if err != nil { return err } @@ -372,3 +372,84 @@ func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Cont }) return nil } + +func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { + + if data.Contains("disks") { + diskInfo := make([]SDiskInfo, 0) + err := data.Unmarshal(&diskInfo, "disks") + if err != nil { + return err + } + + disks := guest.GetDisks() + if len(disks) != len(diskInfo) { + msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) + log.Errorf(msg) + return fmt.Errorf(msg) + } + for i := 0; i < len(diskInfo); i += 1 { + disk := disks[i].GetDisk() + _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { + disk.DiskSize = diskInfo[i].Size + disk.ExternalId = diskInfo[i].Uuid + disk.DiskType = diskInfo[i].DiskType + disk.Status = models.DISK_READY + disk.BillingType = diskInfo[i].BillingType + disk.FsFormat = diskInfo[i].FsFromat + if diskInfo[i].AutoDelete { + disk.AutoDelete = true + } + // disk.TemplateId = diskInfo[i].TemplateId + disk.AccessPath = diskInfo[i].Path + disk.DiskFormat = diskInfo[i].DiskFormat + disk.ExpiredAt = diskInfo[i].ExpiredAt + if len(diskInfo[i].Metadata) > 0 { + for key, value := range diskInfo[i].Metadata { + if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { + log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) + } + } + } + return nil + }) + if err != nil { + msg := fmt.Sprintf("save disk info failed %s", err) + log.Errorf(msg) + break + } + db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred()) + guestdisk := guest.GetGuestDisk(disk.Id) + _, err = guestdisk.GetModelManager().TableSpec().Update(guestdisk, func() error { + guestdisk.Driver = diskInfo[i].Driver + guestdisk.CacheMode = diskInfo[i].CacheMode + return nil + }) + if err != nil { + msg := fmt.Sprintf("save disk info failed %s", err) + log.Errorf(msg) + break + } + } + } + uuid, _ := data.GetString("uuid") + if len(uuid) > 0 { + guest.SetExternalId(uuid) + } + + if metaData, _ := data.Get("metadata"); metaData != nil { + meta := make(map[string]string, 0) + if err := metaData.Unmarshal(meta); err != nil { + log.Errorf("Get guest %s metadata error: %v", guest.Name, err) + } else { + for key, value := range meta { + if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { + log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err) + } + } + } + } + + guest.SaveDeployInfo(ctx, task.GetUserCred(), data) + return nil +} diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index 10eee31d5b..baa50e286c 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -12,7 +12,6 @@ import ( "yunion.io/x/pkg/util/sysutils" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -275,73 +274,6 @@ func (self *SQcloudGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu return nil } -func (self *SQcloudGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { - - if data.Contains("disks") { - diskInfo := make([]SDiskInfo, 0) - err := data.Unmarshal(&diskInfo, "disks") - if err != nil { - return err - } - disks := guest.GetDisks() - if len(disks) != len(diskInfo) { - msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) - log.Errorf(msg) - return fmt.Errorf(msg) - } - for i := 0; i < len(diskInfo); i += 1 { - disk := disks[i].GetDisk() - _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.DiskSize = diskInfo[i].Size - disk.ExternalId = diskInfo[i].Uuid - disk.DiskType = diskInfo[i].DiskType - disk.Status = models.DISK_READY - disk.BillingType = diskInfo[i].BillingType - disk.FsFormat = diskInfo[i].FsFromat - disk.AutoDelete = true - //disk.TemplateId = diskInfo[i].TemplateId - disk.DiskFormat = diskInfo[i].DiskFormat - disk.ExpiredAt = diskInfo[i].ExpiredAt - if len(diskInfo[i].Metadata) > 0 { - for key, value := range diskInfo[i].Metadata { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - return nil - }) - if err != nil { - msg := fmt.Sprintf("save disk info failed %s", err) - log.Errorf(msg) - break - } else { - db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred()) - } - } - } - uuid, _ := data.GetString("uuid") - if len(uuid) > 0 { - guest.SetExternalId(uuid) - } - - if metaData, _ := data.Get("metadata"); metaData != nil { - meta := make(map[string]string, 0) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get guest %s metadata error: %v", guest.Name, err) - } else { - for key, value := range meta { - if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err) - } - } - } - } - - guest.SaveDeployInfo(ctx, task.GetUserCred(), data) - return nil -} - func (self *SQcloudGuestDriver) AllowReconfigGuest() bool { return true } diff --git a/pkg/compute/guestdrivers/utils.go b/pkg/compute/guestdrivers/utils.go new file mode 100644 index 0000000000..ca594446ce --- /dev/null +++ b/pkg/compute/guestdrivers/utils.go @@ -0,0 +1,89 @@ +package guestdrivers + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SDiskInfo struct { + DiskType string + Size int + Uuid string + BillingType string + FsFromat string + AutoDelete bool + TemplateId string + DiskFormat string + Path string + Driver string + CacheMode string + ExpiredAt time.Time + + Metadata map[string]string +} + +func fetchIVMinfo(desc SManagedVMCreateConfig, iVM cloudprovider.ICloudVM, guestId string, account, passwd string, action string) *jsonutils.JSONDict { + data := jsonutils.NewDict() + + data.Add(jsonutils.NewString(iVM.GetOSType()), "os") + + if len(passwd) > 0 { + encpasswd, err := utils.EncryptAESBase64(guestId, passwd) + if err != nil { + log.Errorf("encrypt password failed %s", err) + } + data.Add(jsonutils.NewString(account), "account") + data.Add(jsonutils.NewString(encpasswd), "key") + } + + if len(desc.OsDistribution) > 0 { + data.Add(jsonutils.NewString(desc.OsDistribution), "distro") + } + if len(desc.OsVersion) > 0 { + data.Add(jsonutils.NewString(desc.OsVersion), "version") + } + + idisks, err := iVM.GetIDisks() + + if err != nil { + log.Errorf("GetiDisks error %s", err) + } else { + diskInfo := make([]SDiskInfo, len(idisks)) + for i := 0; i < len(idisks); i += 1 { + dinfo := SDiskInfo{} + dinfo.Uuid = idisks[i].GetGlobalId() + dinfo.Size = idisks[i].GetDiskSizeMB() + dinfo.DiskType = idisks[i].GetDiskType() + dinfo.BillingType = idisks[i].GetBillingType() + dinfo.DiskFormat = idisks[i].GetDiskFormat() + dinfo.AutoDelete = idisks[i].GetIsAutoDelete() + if action == "create" { + dinfo.AutoDelete = true + } + dinfo.Path = idisks[i].GetAccessPath() + dinfo.Driver = idisks[i].GetDriver() + dinfo.CacheMode = idisks[i].GetCacheMode() + dinfo.TemplateId = idisks[i].GetTemplateId() + dinfo.FsFromat = idisks[i].GetFsFormat() + dinfo.ExpiredAt = idisks[i].GetExpiredAt() + if metaData := idisks[i].GetMetadata(); metaData != nil { + dinfo.Metadata = make(map[string]string, 0) + if err := metaData.Unmarshal(dinfo.Metadata); err != nil { + log.Errorf("Get disk %s metadata info error: %v", idisks[i].GetName(), err) + } + } + diskInfo[i] = dinfo + } + data.Add(jsonutils.Marshal(&diskInfo), "disks") + } + + data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid") + data.Add(iVM.GetMetadata(), "metadata") + + return data +} diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 51ba216d1b..dd9aff8208 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -185,10 +185,6 @@ func (self *SVirtualizedGuestDriver) ValidateCreateHostData(ctx context.Context, return data, nil } -func (self *SVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject { - return guest.GetJsonDescAtHypervisor(ctx, host) -} - func (self *SVirtualizedGuestDriver) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, data *jsonutils.JSONDict) error { return guest.StartGueststartTask(ctx, userCred, data, "") } diff --git a/pkg/compute/hostdrivers/aliyun.go b/pkg/compute/hostdrivers/aliyun.go index bff39e84af..6d7fc57c7d 100644 --- a/pkg/compute/hostdrivers/aliyun.go +++ b/pkg/compute/hostdrivers/aliyun.go @@ -1,22 +1,11 @@ package hostdrivers import ( - "context" - "fmt" - "os" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/httperrors" ) type SAliyunHostDriver struct { - SBaseHostDriver + SManagedVirtualizationHostDriver } func init() { @@ -27,190 +16,3 @@ func init() { func (self *SAliyunHostDriver) GetHostType() string { return models.HOST_TYPE_ALIYUN } - -func (self *SAliyunHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { - params := task.GetParams() - imageId, err := params.GetString("image_id") - if err != nil { - return err - } - - osArch, _ := params.GetString("os_arch") - osType, _ := params.GetString("os_type") - osDist, _ := params.GetString("os_distribution") - - isForce := jsonutils.QueryBoolean(params, "is_force", false) - userCred := task.GetUserCred() - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - - lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) - - iStorageCache, err := storageCache.GetIStorageCache() - if err != nil { - return nil, err - } - - extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce) - - if err != nil { - return nil, err - } else { - scimg.SetExternalId(extImgId) - - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(extImgId), "image_id") - return ret, nil - } - }) - return nil -} - -func (self *SAliyunHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { - task.ScheduleRun(nil) - return nil -} - -func (self *SAliyunHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { - if iDisk, err := disk.GetIDisk(); err != nil { - return err - } else if iStorage, err := disk.GetIStorage(); err != nil { - return err - } else if iStoragecache := iStorage.GetIStoragecache(); iStoragecache == nil { - return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) - } else { - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - if snapshot, err := iDisk.CreateISnapshot(ctx, fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage"); err != nil { - return nil, err - } else { - params := task.GetParams() - osType, _ := params.GetString("properties", "os_type") - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) - if scimg.Status != models.CACHED_IMAGE_STATUS_READY { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") - } - if iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, ""); err != nil { - log.Errorf("fail to create iImage: %v", err) - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - scimg.SetExternalId(iImage.GetId()) - if _, err := os.Stat(options.Options.TempPath); os.IsNotExist(err) { - if err = os.MkdirAll(options.Options.TempPath, 0755); err != nil { - return nil, err - } - } - if result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath); err != nil { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - if err := iImage.Delete(); err != nil { - log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) - } - if err := snapshot.Delete(); err != nil { - log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) - } - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") - return result, nil - } - } - } - }) - } - return nil -} - -func (self *SAliyunHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else { - if size, err := content.Int("size"); err != nil { - return err - } else { - size = size >> 10 - if iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), ""); err != nil { - return err - } else { - if _, err := disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.ExternalId = iDisk.GetGlobalId() - - if metaData := iDisk.GetMetadata(); metaData != nil { - meta := make(map[string]string) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get disk %s Metadata error: %v", disk.Name, err) - } else { - for key, value := range meta { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - } - - return nil - }); err != nil { - log.Errorf("Update disk externalId err: %v", err) - return err - } - data := jsonutils.NewDict() - data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size") - data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format") - task.ScheduleRun(data) - } - } - } - return nil -} - -func (self *SAliyunHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { - data := jsonutils.NewDict() - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - if err == cloudprovider.ErrNotFound { - task.ScheduleRun(data) - return nil - } - return err - } else if err := iDisk.Delete(ctx); err != nil { - return err - } - task.ScheduleRun(data) - return nil -} - -func (self *SAliyunHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) -} - -func (self *SAliyunHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - return err - } else if err := iDisk.Resize(ctx, size>>10); err != nil { - return err - } else { - task.ScheduleRun(jsonutils.Marshal(map[string]int64{"disk_size": size})) - } - return nil -} - -func (self *SAliyunHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error { - iDisk, err := disk.GetIDisk() - if err != nil { - return err - } - snapshotId, err := params.GetString("snapshot_id") - if err != nil { - return err - } - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - err := iDisk.Reset(ctx, snapshotId) - return nil, err - }) - return nil -} diff --git a/pkg/compute/hostdrivers/aws.go b/pkg/compute/hostdrivers/aws.go index c482cc4086..4a7fa74563 100644 --- a/pkg/compute/hostdrivers/aws.go +++ b/pkg/compute/hostdrivers/aws.go @@ -1,210 +1,18 @@ package hostdrivers import ( - "context" - "fmt" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/httperrors" - - "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" ) type SAwsHostDriver struct { - SBaseHostDriver -} - -func (self *SAwsHostDriver) GetHostType() string { - return models.HOST_TYPE_AWS -} - -func (self *SAwsHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { - params := task.GetParams() - imageId, err := params.GetString("image_id") - if err != nil { - return err - } - - osArch, _ := params.GetString("os_arch") - osType, _ := params.GetString("os_type") - osDist, _ := params.GetString("os_distribution") - - isForce := jsonutils.QueryBoolean(params, "is_force", false) - userCred := task.GetUserCred() - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - - lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) - - iStorageCache, err := storageCache.GetIStorageCache() - if err != nil { - return nil, err - } - - extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce) - - if err != nil { - return nil, err - } else { - scimg.SetExternalId(extImgId) - - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(extImgId), "image_id") - return ret, nil - } - }) - return nil -} - -func (self *SAwsHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { - task.ScheduleRun(nil) - return nil -} - -func (self *SAwsHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { - if iDisk, err := disk.GetIDisk(); err != nil { - return err - } else if iStorage, err := disk.GetIStorage(); err != nil { - return err - } else if iStoragecache := iStorage.GetIStoragecache(); iStoragecache == nil { - return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) - } else { - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - if snapshot, err := iDisk.CreateISnapshot(ctx, fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage"); err != nil { - return nil, err - } else { - params := task.GetParams() - osType, _ := params.GetString("properties", "os_type") - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) - if scimg.Status != models.CACHED_IMAGE_STATUS_READY { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") - } - if iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, ""); err != nil { - log.Errorf("fail to create iImage: %v", err) - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - scimg.SetExternalId(iImage.GetId()) - if result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath); err != nil { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - if err := iImage.Delete(); err != nil { - log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) - } - if err := snapshot.Delete(); err != nil { - log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) - } - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") - return result, nil - } - } - } - }) - } - return nil -} - -func (self *SAwsHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else { - if size, err := content.Int("size"); err != nil { - return err - } else { - size = size >> 10 - if iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), ""); err != nil { - return err - } else { - if _, err := disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.ExternalId = iDisk.GetGlobalId() - - if metaData := iDisk.GetMetadata(); metaData != nil { - meta := make(map[string]string) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get disk %s Metadata error: %v", disk.Name, err) - } else { - for key, value := range meta { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - } - - return nil - }); err != nil { - log.Errorf("Update disk externalId err: %v", err) - return err - } - data := jsonutils.NewDict() - data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size") - data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format") - task.ScheduleRun(data) - } - } - } - return nil -} - -func (self *SAwsHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { - data := jsonutils.NewDict() - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - if err == cloudprovider.ErrNotFound { - task.ScheduleRun(data) - return nil - } - return err - } else if err := iDisk.Delete(ctx); err != nil { - return err - } - task.ScheduleRun(data) - return nil -} - -func (self *SAwsHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) -} - -func (self *SAwsHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - return err - } else if err := iDisk.Resize(ctx, size>>10); err != nil { - return err - } else { - task.ScheduleRun(jsonutils.Marshal(map[string]int64{"disk_size": size})) - } - return nil -} - -func (self *SAwsHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error { - iDisk, err := disk.GetIDisk() - if err != nil { - return err - } - snapshotId, err := params.GetString("snapshot_id") - if err != nil { - return err - } - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - err := iDisk.Reset(snapshotId) - return nil, err - }) - return nil + SManagedVirtualizationHostDriver } func init() { driver := SAwsHostDriver{} models.RegisterHostDriver(&driver) } + +func (self *SAwsHostDriver) GetHostType() string { + return models.HOST_TYPE_AWS +} diff --git a/pkg/compute/hostdrivers/azure.go b/pkg/compute/hostdrivers/azure.go index 93581da592..d2552d309c 100644 --- a/pkg/compute/hostdrivers/azure.go +++ b/pkg/compute/hostdrivers/azure.go @@ -2,22 +2,15 @@ package hostdrivers import ( "context" - "fmt" - "os" - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) type SAzureHostDriver struct { - SBaseHostDriver + SManagedVirtualizationHostDriver } func init() { @@ -36,174 +29,6 @@ func (self *SAzureHostDriver) ValidateUpdateDisk(ctx context.Context, userCred m return data, nil } -func (self *SAzureHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { - params := task.GetParams() - imageId, err := params.GetString("image_id") - if err != nil { - return err - } - - osArch, _ := params.GetString("os_arch") - osType, _ := params.GetString("os_type") - osDist, _ := params.GetString("os_distribution") - - isForce := jsonutils.QueryBoolean(params, "is_force", false) - userCred := task.GetUserCred() - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) - iStorageCache, err := storageCache.GetIStorageCache() - if err != nil { - return nil, err - } - - extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce) - if err != nil { - return nil, err - } else { - scimg.SetExternalId(extImgId) - - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(extImgId), "image_id") - return ret, nil - } - }) - return nil -} - -func (self *SAzureHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else { - if size, err := content.Int("size"); err != nil { - return err - } else { - size = size >> 10 - if iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), ""); err != nil { - return err - } else { - if _, err := disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.ExternalId = iDisk.GetGlobalId() - - if metaData := iDisk.GetMetadata(); metaData != nil { - meta := make(map[string]string) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get disk %s Metadata error: %v", disk.Name, err) - } else { - for key, value := range meta { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - } - - return nil - }); err != nil { - log.Errorf("Update disk externalId err: %v", err) - return err - } - data := jsonutils.NewDict() - data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size") - data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format") - task.ScheduleRun(data) - } - } - } - return nil -} - -func (self *SAzureHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { - data := jsonutils.NewDict() - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - if err == cloudprovider.ErrNotFound { - task.ScheduleRun(data) - return nil - } - return err - } else if err := iDisk.Delete(ctx); err != nil { - return err - } - task.ScheduleRun(data) - return nil -} - -func (self *SAzureHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) -} - -func (self *SAzureHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - return err - } else if err := iDisk.Resize(ctx, size>>10); err != nil { - return err - } else { - task.ScheduleRun(jsonutils.Marshal(map[string]int64{"disk_size": size})) - } - return nil -} - -func (self *SAzureHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { - task.ScheduleRun(nil) - return nil -} - -func (self *SAzureHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { - if iDisk, err := disk.GetIDisk(); err != nil { - return err - } else if iStorage, err := disk.GetIStorage(); err != nil { - return err - } else if iStoragecache := iStorage.GetIStoragecache(); iStoragecache == nil { - return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) - } else { - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - if snapshot, err := iDisk.CreateISnapshot(ctx, fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage"); err != nil { - return nil, err - } else { - params := task.GetParams() - osType, _ := params.GetString("properties", "os_type") - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) - if scimg.Status != models.CACHED_IMAGE_STATUS_READY { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") - } - if iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, ""); err != nil { - log.Errorf("fail to create iImage: %v", err) - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - scimg.SetExternalId(iImage.GetId()) - if _, err := os.Stat(options.Options.TempPath); os.IsNotExist(err) { - if err = os.MkdirAll(options.Options.TempPath, 0755); err != nil { - return nil, err - } - } - if result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath); err != nil { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } else { - if err := iImage.Delete(); err != nil { - log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) - } - if err := snapshot.Delete(); err != nil { - log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) - } - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") - return result, nil - } - } - } - }) - } - return nil -} - func (self *SAzureHostDriver) RequestDeleteSnapshotWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error { return httperrors.NewNotImplementedError("not implement") } diff --git a/pkg/compute/hostdrivers/esxi.go b/pkg/compute/hostdrivers/esxi.go new file mode 100644 index 0000000000..d7d1158007 --- /dev/null +++ b/pkg/compute/hostdrivers/esxi.go @@ -0,0 +1,259 @@ +package hostdrivers + +import ( + "context" + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SESXiHostDriver struct { + SManagedVirtualizationHostDriver +} + +func init() { + driver := SESXiHostDriver{} + models.RegisterHostDriver(&driver) +} + +func (self *SESXiHostDriver) GetHostType() string { + return models.HOST_TYPE_ESXI +} + +func (self *SESXiHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { + params := task.GetParams() + imageId, err := params.GetString("image_id") + if err != nil { + return err + } + isForce := jsonutils.QueryBoolean(params, "is_force", false) + obj, err := models.CachedimageManager.FetchById(imageId) + if err != nil { + return err + } + cacheImage := obj.(*models.SCachedimage) + srcHostCacheImage, err := cacheImage.ChooseSourceStoragecacheInRange(models.HOST_TYPE_ESXI, []string{host.Id}, + []interface{}{host.GetZone(), host.GetCloudprovider()}) + if err != nil { + return err + } + + type contentStruct struct { + ImageId string + HostId string + HostIp string + SrcHostIp string + SrcPath string + SrcDatastore models.SVCenterAccessInfo + Datastore models.SVCenterAccessInfo + Format string + IsForce bool + StoragecacheId string + } + + content := contentStruct{} + content.ImageId = imageId + content.HostId = host.Id + content.HostIp = host.AccessIp + content.Format = cacheImage.GetFormat() + + storage := host.GetStorageByFilePath(storageCache.Path) + accessInfo, err := host.GetCloudaccount().GetVCenterAccessInfo(storage.ExternalId) + if err != nil { + return err + } + content.Datastore = accessInfo + + if srcHostCacheImage != nil { + err = srcHostCacheImage.AddDownloadRefcount() + if err != nil { + return err + } + srcHost, err := srcHostCacheImage.GetHost() + if err != nil { + return err + } + content.SrcHostIp = srcHost.AccessIp + content.SrcPath = srcHostCacheImage.Path + srcStorage := srcHost.GetStorageByFilePath(srcHostCacheImage.Path) + accessInfo, err := srcHost.GetCloudaccount().GetVCenterAccessInfo(srcStorage.ExternalId) + if err != nil { + return err + } + content.SrcDatastore = accessInfo + } + + agent, err := host.GetEsxiAgentHost() + if err != nil { + log.Errorf("find ESXi agent fail: %s", err) + return err + } + + if agent == nil { + return fmt.Errorf("fail to find valid ESXi agent") + } + + url := fmt.Sprintf("%s/disks/image_cache", agent.ManagerUri) + + if isForce { + content.IsForce = true + } + content.StoragecacheId = storageCache.Id + + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(&content), "disk") + + header := task.GetTaskRequestHeader() + + _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false) + if err != nil { + return err + } + return nil +} + +func (self *SESXiHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { + agent, err := host.GetEsxiAgentHost() + if err != nil { + log.Errorf("find ESXi agent fail: %s", err) + return err + } + + if agent == nil { + return fmt.Errorf("fail to find valid ESXi agent") + } + + type specStruct struct { + Datastore models.SVCenterAccessInfo + HostIp string + Format string + } + + spec := specStruct{} + spec.HostIp = host.AccessIp + spec.Format = "vmdk" + + accessInfo, err := host.GetCloudaccount().GetVCenterAccessInfo(storage.ExternalId) + if err != nil { + return err + } + spec.Datastore = accessInfo + + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(&spec), "disk") + + url := fmt.Sprintf("/disks/agent/create/%s", disk.Id) + + header := task.GetTaskRequestHeader() + + _, err = agent.Request(task.GetUserCred(), "POST", url, header, body) + return err +} + +func (self *SESXiHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { + agent, err := host.GetEsxiAgentHost() + if err != nil { + log.Errorf("find ESXi agent fail: %s", err) + return err + } + + if agent == nil { + return fmt.Errorf("fail to find valid ESXi agent") + } + + guests := disk.GetGuests() + if len(guests) == 0 { + return fmt.Errorf("No VM associate with this disk") + } + + if len(guests) > 1 { + return fmt.Errorf("The disk is attached to multiple guests") + } + + guest := guests[0] + + if guest.HostId != host.Id { + return fmt.Errorf("The only guest is not on the host????") + } + + type specStruct struct { + Vm models.SVCenterAccessInfo + Disk models.SVCenterAccessInfo + HostIp string + ImageId string + } + + spec := specStruct{} + spec.HostIp = host.AccessIp + spec.ImageId = imageId + + account := host.GetCloudaccount() + accessInfo, err := account.GetVCenterAccessInfo(guest.ExternalId) + if err != nil { + return err + } + spec.Vm = accessInfo + + accessInfo, err = account.GetVCenterAccessInfo(disk.ExternalId) + if err != nil { + return err + } + spec.Disk = accessInfo + + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(&spec), "disk") + + url := fmt.Sprintf("/disks/agent/save-prepare/%s", disk.Id) + header := task.GetTaskRequestHeader() + + _, err = agent.Request(task.GetUserCred(), "POST", url, header, body) + return err +} + +func (self *SESXiHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { + + imagePath, _ := data.GetString("backup") + if len(imagePath) == 0 { + return fmt.Errorf("missing parameter backup") + } + agentId, _ := data.GetString("agent_id") + if len(agentId) == 0 { + return fmt.Errorf("missing parameter agent_id") + } + + agent := models.HostManager.FetchHostById(agentId) + if agent == nil { + return fmt.Errorf("cannot find host with id %s", agentId) + } + + storage := disk.GetStorage() + + type specStruct struct { + ImagePath string + ImageId string + StorageId string + StoragecacheId string + Compress bool `json:",allowempty"` + } + + spec := specStruct{} + spec.ImageId = imageId + spec.ImagePath = imagePath + spec.StorageId = storage.Id + spec.StoragecacheId = storage.StoragecacheId + spec.Compress = false + + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(&spec), "disk") + + url := "/disks/agent/upload" + + header := task.GetTaskRequestHeader() + + _, err := agent.Request(task.GetUserCred(), "POST", url, header, body) + return err +} diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index 93b5cab4b6..0eb2149043 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -3,7 +3,6 @@ package hostdrivers import ( "context" "fmt" - "net/http" "net/url" "yunion.io/x/jsonutils" @@ -17,7 +16,7 @@ import ( ) type SKVMHostDriver struct { - SBaseHostDriver + SVirtualizationHostDriver } func init() { @@ -46,8 +45,16 @@ func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, host *mod return err } - content := jsonutils.NewDict() - content.Add(jsonutils.NewString(imageId), "image_id") + type contentStruct struct { + ImageId string + SrcUrl string + IsForce bool + StoragecacheId string + } + + content := contentStruct{} + content.ImageId = imageId + if srcHostCacheImage != nil { err = srcHostCacheImage.AddDownloadRefcount() if err != nil { @@ -57,21 +64,19 @@ func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, host *mod if err != nil { return err } - srcUrl := fmt.Sprintf("%s/download/images/%s", srcHost.ManagerUri, imageId) - content.Add(jsonutils.NewString(srcUrl), "src_url") + content.SrcUrl = fmt.Sprintf("%s/download/images/%s", srcHost.ManagerUri, imageId) } url := fmt.Sprintf("%s/disks/image_cache", host.ManagerUri) if isForce { - content.Add(jsonutils.NewBool(true), "is_force") + content.IsForce = true } - content.Add(jsonutils.NewString(storageCache.Id), "storagecache_id") + content.StoragecacheId = storageCache.Id body := jsonutils.NewDict() - body.Add(content, "disk") - header := http.Header{} - header.Set("X-Auth-Token", task.GetUserCred().GetTokenString()) - header.Set("X-Task-Id", task.GetTaskId()) - header.Set("X-Region-Version", "v2") + body.Add(jsonutils.Marshal(&content), "disk") + + header := task.GetTaskRequestHeader() + _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false) if err != nil { return err @@ -79,10 +84,39 @@ func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, host *mod return nil } +func (self *SKVMHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { + type contentStruct struct { + ImageId string + StoragecacheId string + } + + params := task.GetParams() + imageId, err := params.GetString("image_id") + if err != nil { + return err + } + + content := contentStruct{} + content.ImageId = imageId + content.StoragecacheId = storageCache.Id + + url := fmt.Sprintf("%s/disks/image_cache", host.ManagerUri) + + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(&content), "disk") + + header := task.GetTaskRequestHeader() + + _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "DELETE", url, header, body, false) + if err != nil { + return err + } + return nil +} + func (self *SKVMHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") + header := task.GetTaskRequestHeader() + url := fmt.Sprintf("/disks/%s/create/%s", storage.Id, disk.Id) body := jsonutils.NewDict() body.Add(content, "disk") @@ -92,38 +126,36 @@ func (self *SKVMHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, ho func (self *SKVMHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { log.Infof("Deallocating disk on host %s", host.GetName()) - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") + header := task.GetTaskRequestHeader() + url := fmt.Sprintf("/disks/%s/delete/%s", storage.Id, disk.Id) body := jsonutils.NewDict() _, err := host.Request(task.GetUserCred(), "POST", url, header, body) return err } -func (self *SKVMHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") +func (self *SKVMHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error { + header := task.GetTaskRequestHeader() + url := fmt.Sprintf("/disks/%s/resize/%s", storage.Id, disk.Id) body := jsonutils.NewDict() content := jsonutils.NewDict() - content.Add(jsonutils.NewInt(size), "size") + content.Add(jsonutils.NewInt(sizeMb), "size") body.Add(content, "disk") _, err := host.Request(task.GetUserCred(), "POST", url, header, body) return err } -func (self *SKVMHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") +func (self *SKVMHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error { + self.RequestResizeDiskOnHost(ctx, host, storage, disk, sizeMb, task) + + header := task.GetTaskRequestHeader() + for _, guest := range disk.GetAttachedGuests() { guestdisk := guest.GetGuestDisk(disk.GetId()) url := fmt.Sprintf("/servers/%s/monitor", guest.GetId()) body := jsonutils.NewDict() - cmd := fmt.Sprintf("block_resize drive_%d %dM", guestdisk.Index, size) + cmd := fmt.Sprintf("block_resize drive_%d %dM", guestdisk.Index, sizeMb) body.Add(jsonutils.NewString(cmd), "cmd") host.Request(task.GetUserCred(), "POST", url, header, body) } @@ -134,7 +166,9 @@ func (self *SKVMHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, ho body := jsonutils.NewDict() body.Add(jsonutils.Marshal(map[string]string{"image_id": imageId}), "disk") url := fmt.Sprintf("/disks/%s/save-prepare/%s", disk.StorageId, disk.Id) - header := http.Header{"X-Task-Id": []string{task.GetTaskId()}, "X-Region-Version": []string{"v2"}} + + header := task.GetTaskRequestHeader() + _, err := host.Request(task.GetUserCred(), "POST", url, header, body) return err } @@ -148,7 +182,9 @@ func (self *SKVMHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, ho } body.Add(jsonutils.Marshal(content), "disk") url := fmt.Sprintf("/disks/%s/upload", disk.StorageId) - header := http.Header{"X-Task-Id": []string{task.GetTaskId()}, "X-Region-Version": []string{"v2"}} + + header := task.GetTaskRequestHeader() + _, err := host.Request(task.GetUserCred(), "POST", url, header, body) return err } @@ -157,27 +193,27 @@ func (self *SKVMHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Contex url := fmt.Sprintf("/storages/%s/delete-snapshots", snapshot.StorageId) body := jsonutils.NewDict() body.Set("disk_id", jsonutils.NewString(snapshot.DiskId)) - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") + + header := task.GetTaskRequestHeader() + _, err := host.Request(task.GetUserCred(), "POST", url, header, body) return err } func (self *SKVMHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error { url := fmt.Sprintf("/disks/%s/reset/%s", disk.StorageId, disk.Id) - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") + + header := task.GetTaskRequestHeader() + _, err := host.Request(task.GetUserCred(), "POST", url, header, params) return err } func (self *SKVMHostDriver) RequestCleanUpDiskSnapshots(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error { url := fmt.Sprintf("/disks/%s/cleanup-snapshots/%s", disk.StorageId, disk.Id) - header := http.Header{} - header.Add("X-Task-Id", task.GetTaskId()) - header.Add("X-Region-Version", "v2") + + header := task.GetTaskRequestHeader() + _, err := host.Request(task.GetUserCred(), "POST", url, header, params) return err } diff --git a/pkg/compute/hostdrivers/managedvirtual.go b/pkg/compute/hostdrivers/managedvirtual.go new file mode 100644 index 0000000000..fa0bf40e7f --- /dev/null +++ b/pkg/compute/hostdrivers/managedvirtual.go @@ -0,0 +1,289 @@ +package hostdrivers + +import ( + "context" + "fmt" + "os" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/options" + + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SManagedVirtualizationHostDriver struct { + SVirtualizationHostDriver +} + +func (self *SManagedVirtualizationHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { + params := task.GetParams() + imageId, err := params.GetString("image_id") + if err != nil { + return err + } + + osArch, _ := params.GetString("os_arch") + osType, _ := params.GetString("os_type") + osDist, _ := params.GetString("os_distribution") + + isForce := jsonutils.QueryBoolean(params, "is_force", false) + userCred := task.GetUserCred() + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + + lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) + defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) + + scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) + + iStorageCache, err := storageCache.GetIStorageCache() + if err != nil { + return nil, err + } + + extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce) + + if err != nil { + return nil, err + } + + // scimg.SetExternalId(extImgId) + + ret := jsonutils.NewDict() + ret.Add(jsonutils.NewString(extImgId), "image_id") + return ret, nil + }) + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestUncacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { + params := task.GetParams() + imageId, err := params.GetString("image_id") + if err != nil { + return err + } + + scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) + if scimg == nil { + task.ScheduleRun(nil) + return nil + } + + if len(scimg.ExternalId) == 0 { + log.Errorf("cached image has not external ID???") + task.ScheduleRun(nil) + return nil + } + + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) + defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) + + iStorageCache, err := storageCache.GetIStorageCache() + if err != nil { + log.Errorf("GetIStorageCache fail %s", err) + return nil, err + } + + iImage, err := iStorageCache.GetIImageById(scimg.ExternalId) + if err != nil { + if err == cloudprovider.ErrNotFound { + return nil, nil + } + log.Errorf("GetIImageById fail %s", err) + return nil, err + } + + err = iImage.Delete(ctx) + if err != nil { + log.Errorf("iImage Delete fail %s", err) + return nil, err + } + + return nil, nil + }) + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { + task.ScheduleRun(nil) + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { + iDisk, err := disk.GetIDisk() + if err != nil { + return err + } + iStorage, err := disk.GetIStorage() + if err != nil { + return err + } + iStoragecache := iStorage.GetIStoragecache() + if iStoragecache == nil { + return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) + } + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + snapshot, err := iDisk.CreateISnapshot(ctx, fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage") + if err != nil { + return nil, err + } + params := task.GetParams() + osType, _ := params.GetString("properties", "os_type") + + scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) + if scimg.Status != models.CACHED_IMAGE_STATUS_READY { + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") + } + iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, "") + if err != nil { + log.Errorf("fail to create iImage: %v", err) + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) + return nil, err + } + scimg.SetExternalId(iImage.GetId()) + if _, err := os.Stat(options.Options.TempPath); os.IsNotExist(err) { + if err = os.MkdirAll(options.Options.TempPath, 0755); err != nil { + return nil, err + } + } + result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath) + if err != nil { + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) + return nil, err + } + if err := iImage.Delete(ctx); err != nil { + log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) + } + if err := snapshot.Delete(); err != nil { + log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) + } + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") + return result, nil + }) + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { + return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) +} + +func (self *SManagedVirtualizationHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error { + iCloudStorage, err := storage.GetIStorage() + if err != nil { + log.Errorf("storage.GetIStorage fail %s", err) + return err + } + + iDisk, err := iCloudStorage.GetIDiskById(disk.GetExternalId()) + if err != nil { + log.Errorf("iCloudStorage.GetIDisk fail %s", err) + return err + } + + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + err = iDisk.Resize(ctx, sizeMb) + if err != nil { + log.Errorf("iDisk.Resize fail %s", err) + return nil, err + } + return jsonutils.Marshal(map[string]int64{"disk_size": sizeMb}), nil + }) + + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { + iCloudStorage, err := storage.GetIStorage() + if err != nil { + return err + } + size, err := content.Int("size") + if err != nil { + return err + } + size = size >> 10 + + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), "") + if err != nil { + return nil, err + } + _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { + disk.ExternalId = iDisk.GetGlobalId() + return nil + }) + if err != nil { + log.Errorf("Update disk externalId err: %v", err) + return nil, err + } + + if metaData := iDisk.GetMetadata(); metaData != nil { + meta := make(map[string]string) + if err := metaData.Unmarshal(meta); err != nil { + log.Errorf("Get disk %s Metadata error: %v", disk.Name, err) + } else { + for key, value := range meta { + if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { + log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) + } + } + } + } + + data := jsonutils.NewDict() + data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size") + data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format") + + return data, nil + }) + + return nil +} + +func (self *SManagedVirtualizationHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { + data := jsonutils.NewDict() + + iCloudStorage, err := storage.GetIStorage() + if err != nil { + return err + } + + iDisk, err := iCloudStorage.GetIDiskById(disk.GetExternalId()) + if err != nil { + if err == cloudprovider.ErrNotFound { + task.ScheduleRun(data) + return nil + } + return err + } + + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + err := iDisk.Delete(ctx) + return nil, err + }) + + return nil +} + +func (self *SAliyunHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error { + iDisk, err := disk.GetIDisk() + if err != nil { + return err + } + snapshotId, err := params.GetString("snapshot_id") + if err != nil { + return err + } + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + err := iDisk.Reset(ctx, snapshotId) + return nil, err + }) + return nil +} diff --git a/pkg/compute/hostdrivers/qcloud.go b/pkg/compute/hostdrivers/qcloud.go index 7a30ca306a..0cacf12199 100644 --- a/pkg/compute/hostdrivers/qcloud.go +++ b/pkg/compute/hostdrivers/qcloud.go @@ -2,21 +2,13 @@ package hostdrivers import ( "context" - "fmt" - "os" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" ) type SQcloudHostDriver struct { - SBaseHostDriver + SManagedVirtualizationHostDriver } func init() { @@ -28,182 +20,6 @@ func (self *SQcloudHostDriver) GetHostType() string { return models.HOST_TYPE_QCLOUD } -func (self *SQcloudHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { - params := task.GetParams() - imageId, err := params.GetString("image_id") - if err != nil { - return err - } - - osArch, _ := params.GetString("os_arch") - osType, _ := params.GetString("os_type") - osDist, _ := params.GetString("os_distribution") - - isForce := jsonutils.QueryBoolean(params, "is_force", false) - userCred := task.GetUserCred() - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId)) - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId) - iStorageCache, err := storageCache.GetIStorageCache() - if err != nil { - return nil, err - } - - extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce) - if err != nil { - return nil, err - } - scimg.SetExternalId(extImgId) - - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(extImgId), "image_id") - return ret, nil - }) - return nil -} - -func (self *SQcloudHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { - iCloudStorage, err := storage.GetIStorage() - if err != nil { - return err - } - size, err := content.Int("size") - if err != nil { - return err - } - size = size >> 10 - iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), "") - if err != nil { - return err - } - _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { - disk.ExternalId = iDisk.GetGlobalId() - - if metaData := iDisk.GetMetadata(); metaData != nil { - meta := make(map[string]string) - if err := metaData.Unmarshal(meta); err != nil { - log.Errorf("Get disk %s Metadata error: %v", disk.Name, err) - } else { - for key, value := range meta { - if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { - log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err) - } - } - } - } - - return nil - }) - if err != nil { - log.Errorf("Update disk externalId err: %v", err) - return err - } - data := jsonutils.NewDict() - data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size") - data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format") - task.ScheduleRun(data) - return nil -} - -func (self *SQcloudHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error { - data := jsonutils.NewDict() - if iCloudStorage, err := storage.GetIStorage(); err != nil { - return err - } else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil { - if err == cloudprovider.ErrNotFound { - task.ScheduleRun(data) - return nil - } - return err - } else if err := iDisk.Delete(ctx); err != nil { - return err - } - task.ScheduleRun(data) - return nil -} - -func (self *SQcloudHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task) -} - -func (self *SQcloudHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error { - iCloudStorage, err := storage.GetIStorage() - if err != nil { - return err - } - iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()) - if err != nil { - return err - } - err = iDisk.Resize(ctx, size>>10) - if err != nil { - return err - } - task.ScheduleRun(jsonutils.Marshal(map[string]int64{"disk_size": size})) - return nil -} - -func (self *SQcloudHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { - task.ScheduleRun(nil) - return nil -} - -func (self *SQcloudHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { - iDisk, err := disk.GetIDisk() - if err != nil { - return err - } - iStorage, err := disk.GetIStorage() - if err != nil { - return err - } - iStoragecache := iStorage.GetIStoragecache() - if iStoragecache == nil { - return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) - } - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - snapshot, err := iDisk.CreateISnapshot(ctx, fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage") - if err != nil { - return nil, err - } - params := task.GetParams() - osType, _ := params.GetString("properties", "os_type") - - scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) - if scimg.Status != models.CACHED_IMAGE_STATUS_READY { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") - } - iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, "") - if err != nil { - log.Errorf("fail to create iImage: %v", err) - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } - scimg.SetExternalId(iImage.GetId()) - if _, err := os.Stat(options.Options.TempPath); os.IsNotExist(err) { - if err = os.MkdirAll(options.Options.TempPath, 0755); err != nil { - return nil, err - } - } - result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath) - if err != nil { - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - return nil, err - } - if err := iImage.Delete(); err != nil { - log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) - } - if err := snapshot.Delete(); err != nil { - log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) - } - scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") - return result, nil - }) - return nil -} - func (self *SQcloudHostDriver) RequestDeleteSnapshotWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error { return httperrors.NewNotImplementedError("not implement") } diff --git a/pkg/compute/hostdrivers/virtualization.go b/pkg/compute/hostdrivers/virtualization.go new file mode 100644 index 0000000000..d91c5105a5 --- /dev/null +++ b/pkg/compute/hostdrivers/virtualization.go @@ -0,0 +1,5 @@ +package hostdrivers + +type SVirtualizationHostDriver struct { + SBaseHostDriver +} diff --git a/pkg/compute/models/cachedimages.go b/pkg/compute/models/cachedimages.go index 3d49d59128..4093d90ba2 100644 --- a/pkg/compute/models/cachedimages.go +++ b/pkg/compute/models/cachedimages.go @@ -60,7 +60,7 @@ func (self *SCachedimage) ValidateDeleteCondition(ctx context.Context) error { if self.getStoragecacheCount() > 0 { return httperrors.NewNotEmptyError("The image has been cached on storages") } - if self.getStatus() == "active" && !self.isReferenceSessionExpire() { + if self.GetStatus() == "active" && !self.isReferenceSessionExpire() { return httperrors.NewConflictError("the image reference session has not been expired!") } return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx) @@ -82,27 +82,27 @@ func (self *SCachedimage) isRefreshSessionExpire() bool { } } -func (self *SCachedimage) getName() string { +func (self *SCachedimage) GetName() string { name, _ := self.Info.GetString("name") return name } -func (self *SCachedimage) getOwner() string { +func (self *SCachedimage) GetOwner() string { owner, _ := self.Info.GetString("owner") return owner } -func (self *SCachedimage) getFormat() string { +func (self *SCachedimage) GetFormat() string { format, _ := self.Info.GetString("disk_format") return format } -func (self *SCachedimage) getStatus() string { +func (self *SCachedimage) GetStatus() string { status, _ := self.Info.GetString("status") return status } -func (self *SCachedimage) getOSType() string { +func (self *SCachedimage) GetOSType() string { osType, _ := self.Info.GetString("properties", "os_type") return osType } @@ -116,7 +116,7 @@ func (self *SCachedimage) getStoragecacheCount() int { return self.getStoragecacheQuery().Count() } -func (self *SCachedimage) getImage() (*SImage, error) { +func (self *SCachedimage) GetImage() (*SImage, error) { image := SImage{} err := self.Info.Unmarshal(&image) @@ -183,8 +183,8 @@ func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred m imgObj, _ := manager.FetchById(imageId) if imgObj != nil { cachedImage := imgObj.(*SCachedimage) - if cachedImage.getStatus() == "active" && len(cachedImage.getOSType()) > 0 && cachedImage.isRefreshSessionExpire() { - return cachedImage.getImage() + if cachedImage.GetStatus() == "active" && len(cachedImage.GetOSType()) > 0 && cachedImage.isRefreshSessionExpire() { + return cachedImage.GetImage() } } } @@ -198,7 +198,7 @@ func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred m if err != nil { return nil, err } - return cachedImage.getImage() + return cachedImage.GetImage() } func (manager *SCachedimageManager) getImageByName(ctx context.Context, userCred mcclient.TokenCredential, imageId string) (*SImage, error) { @@ -211,7 +211,7 @@ func (manager *SCachedimageManager) getImageByName(ctx context.Context, userCred if err != nil { return nil, err } - return cachedImage.getImage() + return cachedImage.GetImage() } func (manager *SCachedimageManager) getImageInfo(ctx context.Context, userCred mcclient.TokenCredential, imageId string, refresh bool) (*SImage, error) { @@ -225,10 +225,10 @@ func (manager *SCachedimageManager) getImageInfo(ctx context.Context, userCred m func (self *SCachedimage) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { extra := self.SStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) - extra.Add(jsonutils.NewString(self.getName()), "name") - extra.Add(jsonutils.NewString(self.getOwner()), "owner") - extra.Add(jsonutils.NewString(self.getFormat()), "format") - extra.Add(jsonutils.NewString(self.getStatus()), "status") + extra.Add(jsonutils.NewString(self.GetName()), "name") + extra.Add(jsonutils.NewString(self.GetOwner()), "owner") + extra.Add(jsonutils.NewString(self.GetFormat()), "format") + extra.Add(jsonutils.NewString(self.GetStatus()), "status") for _, k := range []string{"os_type", "os_distribution", "os_version", "hypervisor"} { val, _ := self.Info.GetString("properties", k) if len(val) > 0 { @@ -252,7 +252,7 @@ func (self *SCachedimage) PerformRefresh(ctx context.Context, userCred mcclient. } func (self *SCachedimage) addRefCount() { - if self.getStatus() != "active" { + if self.GetStatus() != "active" { return } _, err := CachedimageManager.TableSpec().Update(self, func() error { @@ -294,7 +294,7 @@ func (self *SCachedimage) ChooseSourceStoragecacheInRange(hostType string, exclu for _, obj := range v { q = q.Filter(sqlchemy.Equals(host.Field("zone_id"), obj.Id)) } - case []*SVCenter: + case []*SCloudprovider: for _, obj := range v { q = q.Filter(sqlchemy.Equals(host.Field("manager_id"), obj.Id)) } diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index f3f65d5784..34e6949406 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -13,6 +13,8 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "net/url" + "strconv" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -478,7 +480,9 @@ func (manager *SCloudaccountManager) FetchCloudaccountByIdOrName(accountId strin } func (self *SCloudaccount) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict { - extra.Add(jsonutils.Marshal(self.GetCloudproviders()), "accounts") + providers := self.GetCloudproviders() + extra.Add(jsonutils.NewInt(int64(len(providers))), "account_count") + extra.Add(jsonutils.Marshal(providers), "accounts") return extra } @@ -602,3 +606,54 @@ func (self *SCloudaccount) GetDetailsBalance(ctx context.Context, userCred mccli ret.Add(jsonutils.NewFloat(balance), "balance") return ret, nil } + +func (self *SCloudaccount) getHostPort() (string, int, error) { + urlComponent, err := url.Parse(self.AccessUrl) + if err != nil { + return "", 0, err + } + host := urlComponent.Hostname() + portStr := urlComponent.Port() + port := 0 + if len(portStr) > 0 { + port, err = strconv.Atoi(portStr) + if err != nil { + return "", 0, err + } + } + if port == 0 { + if urlComponent.Scheme == "http" { + port = 80 + } else if urlComponent.Scheme == "https" { + port = 443 + } + } + return host, port, nil +} + +type SVCenterAccessInfo struct { + VcenterId string + Host string + Port int + Account string + Password string + PrivateId string +} + +func (self *SCloudaccount) GetVCenterAccessInfo(privateId string) (SVCenterAccessInfo, error) { + info := SVCenterAccessInfo{} + + host, port, err := self.getHostPort() + if err != nil { + return info, err + } + + info.VcenterId = self.Id + info.Host = host + info.Port = port + info.Account = self.Account + info.Password = self.Secret + info.PrivateId = privateId + + return info, nil +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index c5bf013aca..c1125abc29 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -600,22 +600,24 @@ func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCre } func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - if storage := self.GetStorage(); storage == nil { + storage := self.GetStorage() + if storage == nil { return nil, httperrors.NewResourceNotFoundError("fail to find storage for disk %s", self.GetName()) - } else if provider, err := storage.GetDriver(); err != nil { - return nil, err - } else { - return provider.GetIStorageById(storage.GetExternalId()) } + istorage, err := storage.GetIStorage() + if err != nil { + return nil, err + } + return istorage, nil } func (self *SDisk) GetIDisk() (cloudprovider.ICloudDisk, error) { - if iStorage, err := self.GetIStorage(); err != nil { + iStorage, err := self.GetIStorage() + if err != nil { log.Errorf("fail to find iStorage: %v", err) return nil, err - } else { - return iStorage.GetIDisk(self.GetExternalId()) } + return iStorage.GetIDiskById(self.GetExternalId()) } func (self *SDisk) GetZone() *SZone { @@ -839,6 +841,7 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke self.Status = extDisk.GetStatus() self.DiskFormat = extDisk.GetDiskFormat() self.DiskSize = extDisk.GetDiskSizeMB() + self.AccessPath = extDisk.GetAccessPath() if extDisk.GetIsAutoDelete() { self.AutoDelete = true } @@ -1199,9 +1202,9 @@ func (self *SDisk) GetCustomizeColumns(ctx context.Context, userCred mcclient.To return self.getMoreDetails(extra) } -func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, size int64, parentTaskId string, pendingUsage quotas.IQuota) error { +func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int64, parentTaskId string, pendingUsage quotas.IQuota) error { params := jsonutils.NewDict() - params.Add(jsonutils.NewInt(size), "size") + params.Add(jsonutils.NewInt(sizeMb), "size") if task, err := taskman.TaskManager.NewTask(ctx, "DiskResizeTask", self, userCred, params, parentTaskId, "", pendingUsage); err != nil { return err } else { diff --git a/pkg/compute/models/guestdisks.go b/pkg/compute/models/guestdisks.go index cb5834f328..becf1938aa 100644 --- a/pkg/compute/models/guestdisks.go +++ b/pkg/compute/models/guestdisks.go @@ -202,7 +202,7 @@ func (self *SGuestdisk) GetDetailedJson() *jsonutils.JSONDict { cachedImageObj, _ := CachedimageManager.FetchById(imageId) if cachedImageObj != nil { cachedImage := cachedImageObj.(*SCachedimage) - desc.Add(jsonutils.NewString(cachedImage.getName()), "image") + desc.Add(jsonutils.NewString(cachedImage.GetName()), "image") } } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index fef2cebfc6..246b9405ca 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3199,6 +3199,9 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T return nil, httperrors.NewBadRequestError("Params vcpu_count parse error") } addCpu = int(nVcpu - int64(self.VcpuCount)) + if addCpu < 0 { + addCpu = 0 + } } vmemSize, err := data.GetString("vmem_size") if err == nil { @@ -3214,6 +3217,9 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T return nil, httperrors.NewBadRequestError("Params vmem_size parse error") } addMem = nVmem - self.VmemSize + if addMem < 0 { + addMem = 0 + } } disks := self.GetDisks() var addDisk int diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 606f730639..2e490fc365 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -12,7 +12,10 @@ import ( type IHostDriver interface { GetHostType() string + CheckAndSetCacheImage(ctx context.Context, host *SHost, storagecache *SStoragecache, task taskman.ITask) error + RequestUncacheImage(ctx context.Context, host *SHost, storageCache *SStoragecache, task taskman.ITask) error + ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) RequestPrepareSaveDiskOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask) error RequestSaveUploadImageOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 880e064ca1..5371c46890 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -2,6 +2,7 @@ package models import ( "context" + "database/sql" "fmt" "net/http" "net/url" @@ -10,6 +11,8 @@ import ( "strings" "time" + "github.com/serialx/hashring" + "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/tristate" @@ -21,7 +24,6 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" - "database/sql" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -459,6 +461,19 @@ func (self *SHost) GetHoststorageOfId(storageId string) *SHoststorage { return &hoststorage } +func (self *SHost) GetStorageByFilePath(path string) *SStorage { + hoststorages := self.GetHoststorages() + if hoststorages == nil { + return nil + } + for i := 0; i < len(hoststorages); i += 1 { + if strings.HasPrefix(path, hoststorages[i].MountPoint) { + return hoststorages[i].GetStorage() + } + } + return nil +} + func (self *SHost) GetBaremetalstorage() *SHoststorage { if !self.IsBaremetal { return nil @@ -1125,7 +1140,9 @@ func (manager *SHostManager) newFromCloudHost(extHost cloudprovider.ICloudHost, return &host, nil } -func (self *SHost) SyncHostStorages(ctx context.Context, userCred mcclient.TokenCredential, storages []cloudprovider.ICloudStorage) compare.SyncResult { +func (self *SHost) SyncHostStorages(ctx context.Context, userCred mcclient.TokenCredential, storages []cloudprovider.ICloudStorage) ([]SStorage, []cloudprovider.ICloudStorage, compare.SyncResult) { + localStorages := make([]SStorage, 0) + remoteStorages := make([]cloudprovider.ICloudStorage, 0) syncResult := compare.SyncResult{} dbStorages := make([]SStorage, 0) @@ -1150,7 +1167,7 @@ func (self *SHost) SyncHostStorages(ctx context.Context, userCred mcclient.Token err := compare.CompareSets(dbStorages, storages, &removed, &commondb, &commonext, &added) if err != nil { syncResult.Error(err) - return syncResult + return nil, nil, syncResult } for i := 0; i < len(removed); i += 1 { @@ -1166,29 +1183,34 @@ func (self *SHost) SyncHostStorages(ctx context.Context, userCred mcclient.Token for i := 0; i < len(commondb); i += 1 { log.Infof("host %s is still connected with %s, to update ...", self.Id, commondb[i].Id) - err := self.syncWithCloudHostStorage(commonext[i]) + err := self.syncWithCloudHostStorage(&commondb[i], commonext[i]) if err != nil { syncResult.UpdateError(err) } else { syncResult.Update() } + localStorages = append(localStorages, commondb[i]) + remoteStorages = append(remoteStorages, commonext[i]) } for i := 0; i < len(added); i += 1 { log.Infof("host %s is found connected with %s, to add ...", self.Id, added[i].GetId()) - err := self.newCloudHostStorage(ctx, userCred, added[i]) + local, err := self.newCloudHostStorage(ctx, userCred, added[i]) if err != nil { syncResult.AddError(err) } else { syncResult.Add() } + localStorages = append(localStorages, *local) + remoteStorages = append(remoteStorages, added[i]) } - return syncResult + return localStorages, remoteStorages, syncResult } -func (self *SHost) syncWithCloudHostStorage(extStorage cloudprovider.ICloudStorage) error { +func (self *SHost) syncWithCloudHostStorage(localStorage *SStorage, extStorage cloudprovider.ICloudStorage) error { // do nothing - return nil + hs := self.GetHoststorageOfId(localStorage.Id) + return hs.syncWithCloudHostStorage(extStorage) } func (self *SHost) Attach2Storage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage, mountPoint string) error { @@ -1207,25 +1229,25 @@ func (self *SHost) Attach2Storage(ctx context.Context, userCred mcclient.TokenCr return nil } -func (self *SHost) newCloudHostStorage(ctx context.Context, userCred mcclient.TokenCredential, extStorage cloudprovider.ICloudStorage) error { +func (self *SHost) newCloudHostStorage(ctx context.Context, userCred mcclient.TokenCredential, extStorage cloudprovider.ICloudStorage) (*SStorage, error) { storageObj, err := StorageManager.FetchByExternalId(extStorage.GetGlobalId()) if err != nil { if err == sql.ErrNoRows { // no cloud storage found, this may happen for on-premise host - // create the storage + // create the storage right now storageObj, err = StorageManager.newFromCloudStorage(extStorage, self.GetZone()) if err != nil { log.Errorf("create by cloud storage fail %s", err) - return err + return nil, err } } else { log.Errorf("%s", err) - return err + return nil, err } } storage := storageObj.(*SStorage) - err = self.Attach2Storage(ctx, userCred, storage, "") - return err + err = self.Attach2Storage(ctx, userCred, storage, extStorage.GetMountPoint()) + return storage, err } func (self *SHost) SyncHostWires(ctx context.Context, userCred mcclient.TokenCredential, wires []cloudprovider.ICloudWire) compare.SyncResult { @@ -1656,7 +1678,23 @@ func (self *SHost) GetIHost() (cloudprovider.ICloudHost, error) { if err != nil { return nil, fmt.Errorf("No cloudprovide for host: %s", err) } - ihost, err := provider.GetIHostById(self.ExternalId) + var iregion cloudprovider.ICloudRegion + if provider.IsOnPremiseInfrastructure() { + iregion, err = provider.GetOnPremiseIRegion() + } else { + region := self.GetRegion() + if region == nil { + msg := "fail to find region of host???" + log.Errorf(msg) + return nil, fmt.Errorf(msg) + } + iregion, err = provider.GetIRegionById(region.ExternalId) + } + if err != nil { + log.Errorf("fail to find iregion: %s", err) + return nil, err + } + ihost, err := iregion.GetIHostById(self.ExternalId) if err != nil { log.Errorf("fail to find ihost by id %s %s", self.ExternalId, err) return nil, fmt.Errorf("fail to find ihost by id %s", err) @@ -3122,3 +3160,57 @@ func (host *SHost) SyncHostExternalNics(ctx context.Context, userCred mcclient.T return result } + +func (manager *SHostManager) GetEsxiAgentHostId(key string) (string, error) { + q := HostManager.Query("id") + q = q.Equals("host_status", HOST_ONLINE) + q = q.Equals("host_type", HOST_TYPE_HYPERVISOR) + q = q.IsTrue("enabled") + + rows, err := q.Rows() + if err != nil { + return "", err + } + + var hostId string + hostIds := make([]string, 0) + for rows.Next() { + err = rows.Scan(&hostId) + if err != nil { + return "", err + } + hostIds = append(hostIds, hostId) + } + + ring := hashring.New(hostIds) + ret, _ := ring.GetNode(key) + return ret, nil +} + +func (manager *SHostManager) GetEsxiAgentHost(key string) (*SHost, error) { + hostId, err := manager.GetEsxiAgentHostId(key) + if err != nil { + return nil, err + } + return manager.FetchHostById(hostId), nil +} + +func (host *SHost) GetEsxiAgentHost() (*SHost, error) { + return HostManager.GetEsxiAgentHost(host.Id) +} + +func (manager *SHostManager) GetHostByIp(hostIp string) (*SHost, error) { + q := manager.Query() + q = q.Equals("access_ip", hostIp) + + host, err := db.NewModelObject(manager) + if err != nil { + return nil, err + } + err = q.First(host) + if err != nil { + return nil, err + } + + return host.(*SHost), nil +} diff --git a/pkg/compute/models/hoststorages.go b/pkg/compute/models/hoststorages.go index 8da2193ddb..a6d982719d 100644 --- a/pkg/compute/models/hoststorages.go +++ b/pkg/compute/models/hoststorages.go @@ -5,11 +5,13 @@ import ( "fmt" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/pkg/tristate" "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" ) type SHoststorageManager struct { @@ -159,3 +161,11 @@ func (manager *SHoststorageManager) GetStorages(hostId string) ([]SHoststorage, } return hoststorage, nil } + +func (self *SHoststorage) syncWithCloudHostStorage(extStorage cloudprovider.ICloudStorage) error { + _, err := self.GetModelManager().TableSpec().Update(self, func() error { + self.MountPoint = extStorage.GetMountPoint() + return nil + }) + return err +} diff --git a/pkg/compute/models/managedresource.go b/pkg/compute/models/managedresource.go index fc6c7a0153..3b490b17da 100644 --- a/pkg/compute/models/managedresource.go +++ b/pkg/compute/models/managedresource.go @@ -19,6 +19,14 @@ func (self *SManagedResourceBase) GetCloudprovider() *SCloudprovider { return nil } +func (self *SManagedResourceBase) GetCloudaccount() *SCloudaccount { + cp := self.GetCloudprovider() + if cp == nil { + return nil + } + return cp.GetCloudaccount() +} + func (self *SManagedResourceBase) GetDriver() (cloudprovider.ICloudProvider, error) { provider := self.GetCloudprovider() if provider == nil { diff --git a/pkg/compute/models/storagecachedimages.go b/pkg/compute/models/storagecachedimages.go index 4a646c146d..a91cc895b1 100644 --- a/pkg/compute/models/storagecachedimages.go +++ b/pkg/compute/models/storagecachedimages.go @@ -153,7 +153,7 @@ func (self *SStoragecachedimage) getExtraDetails(extra *jsonutils.JSONDict) *jso } cachedImage := self.GetCachedimage() if cachedImage != nil { - extra.Add(jsonutils.NewString(cachedImage.getName()), "image") + extra.Add(jsonutils.NewString(cachedImage.GetName()), "image") extra.Add(jsonutils.NewInt(cachedImage.Size), "size") } extra.Add(jsonutils.NewInt(int64(self.getReferenceCount())), "reference") @@ -237,7 +237,8 @@ func (self *SStoragecachedimage) markDeleting(ctx context.Context, userCred mccl lockman.LockJointObject(ctx, cache, image) defer lockman.ReleaseJointObject(ctx, cache, image) - if !isForce && !utils.IsInStringArray(self.Status, []string{CACHED_IMAGE_STATUS_READY, CACHED_IMAGE_STATUS_DELETING}) { + if !isForce && !utils.IsInStringArray(self.Status, + []string{CACHED_IMAGE_STATUS_READY, CACHED_IMAGE_STATUS_DELETING, CACHED_IMAGE_STATUS_CACHE_FAILED}) { return httperrors.NewInvalidStatusError("Cannot uncache in status %s", self.Status) } _, err = self.GetModelManager().TableSpec().Update(self, func() error { diff --git a/pkg/compute/models/storagecaches.go b/pkg/compute/models/storagecaches.go index 240a99782b..c34fb61d9f 100644 --- a/pkg/compute/models/storagecaches.go +++ b/pkg/compute/models/storagecaches.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/log" "yunion.io/x/sqlchemy" + "fmt" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -40,7 +41,7 @@ type SStoragecache struct { SInfrastructure SManagedResourceBase - Path string `width:"256" charset:"utf8" nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // = Column(VARCHAR(256, charset='utf8'), nullable=True) + Path string `width:"256" charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional"` // = Column(VARCHAR(256, charset='utf8'), nullable=True) } func (self *SStoragecache) getStorages() []SStorage { @@ -141,6 +142,8 @@ func (manager *SStoragecacheManager) newFromCloudStoragecache(cloudCache cloudpr local.IsEmulated = cloudCache.IsEmulated() local.ManagerId = cloudCache.GetManagerId() + local.Path = cloudCache.GetPath() + err := manager.TableSpec().Insert(&local) if err != nil { return nil, err @@ -153,6 +156,8 @@ func (self *SStoragecache) syncWithCloudStoragecache(cloudCache cloudprovider.IC _, err := self.GetModelManager().TableSpec().Update(self, func() error { self.Name = cloudCache.GetName() + self.Path = cloudCache.GetPath() + self.IsEmulated = cloudCache.IsEmulated() self.ManagerId = cloudCache.GetManagerId() @@ -197,7 +202,9 @@ func (self *SStoragecache) getCachedImageSize() int64 { var size int64 = 0 for _, img := range images { imginfo := img.GetCachedimage() - size += imginfo.Size + if imginfo != nil { + size += imginfo.Size + } } return size } @@ -237,13 +244,6 @@ func (self *SStoragecache) StartImageCacheTask(ctx context.Context, userCred mcc } func (self *SStoragecache) StartImageUncacheTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, isForce bool, parentTaskId string) error { - if !isForce { - err := self.ValidateDeleteCondition(ctx) - if err != nil { - return err - } - } - data := jsonutils.NewDict() data.Add(jsonutils.NewString(imageId), "image_id") if isForce { @@ -258,12 +258,18 @@ func (self *SStoragecache) StartImageUncacheTask(ctx context.Context, userCred m } func (self *SStoragecache) GetIStorageCache() (cloudprovider.ICloudStoragecache, error) { - provider, err := self.GetDriver() + storages := self.getStorages() + if len(storages) == 0 { + msg := "no storages for this storagecache???" + log.Errorf(msg) + return nil, fmt.Errorf(msg) + } + istorage, err := storages[0].GetIStorage() if err != nil { - log.Errorf("fail to find cloud provider") + log.Errorf("fail to find istorage for storage %s", err) return nil, err } - return provider.GetIStoragecacheById(self.GetExternalId()) + return istorage.GetIStoragecache(), nil } func (manager *SStoragecacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index b7be546d7d..b4261c63d7 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -3,6 +3,7 @@ package models import ( "context" + "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -258,6 +259,14 @@ func (self *SStorage) getZone() *SZone { return nil } +func (self *SStorage) GetRegion() *SCloudregion { + zone := self.getZone() + if zone == nil { + return nil + } + return zone.GetRegion() +} + func (self *SStorage) GetReserved() int { return self.Reserved } @@ -705,7 +714,28 @@ func (self *SStorage) GetIStorage() (cloudprovider.ICloudStorage, error) { log.Errorf("fail to find cloud provider") return nil, err } - return provider.GetIStorageById(self.GetExternalId()) + var iRegion cloudprovider.ICloudRegion + if provider.IsOnPremiseInfrastructure() { + iRegion, err = provider.GetOnPremiseIRegion() + } else { + region := self.GetRegion() + if region == nil { + msg := "cannot find region for storage???" + log.Errorf(msg) + return nil, fmt.Errorf(msg) + } + iRegion, err = provider.GetIRegionById(region.ExternalId) + } + if err != nil { + log.Errorf("provider.GetIRegionById fail %s", err) + return nil, err + } + istore, err := iRegion.GetIStorageById(self.GetExternalId()) + if err != nil { + log.Errorf("iRegion.GetIStorageById fail %s", err) + return nil, err + } + return istore, nil } func (manager *SStorageManager) FetchStorageById(storageId string) *SStorage { @@ -807,3 +837,20 @@ func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy. return q, err } + +func (self *SStorage) ClearSchedDescCache() error { + hosts := self.GetAllAttachingHosts() + if hosts == nil { + msg := "get attaching host error" + log.Errorf(msg) + return fmt.Errorf(msg) + } + for i := 0; i < len(hosts); i += 1 { + err := hosts[i].ClearSchedDescCache() + if err != nil { + log.Errorf("host CleanHostSchedCache error: %v", err) + return err + } + } + return nil +} diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index 20b3eaad36..19672f747d 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -411,7 +411,28 @@ func (self *SVpc) GetIVpc() (cloudprovider.ICloudVpc, error) { log.Errorf("fail to find cloud provider") return nil, err } - return provider.GetIVpcById(self.GetExternalId()) + var iregion cloudprovider.ICloudRegion + if provider.IsOnPremiseInfrastructure() { + iregion, err = provider.GetOnPremiseIRegion() + } else { + region := self.GetRegion() + if region == nil { + msg := "fail to find region of host???" + log.Errorf(msg) + return nil, fmt.Errorf(msg) + } + iregion, err = provider.GetIRegionById(region.ExternalId) + } + if err != nil { + log.Errorf("fail to find iregion: %s", err) + return nil, err + } + ivpc, err := iregion.GetIVpcById(self.ExternalId) + if err != nil { + log.Errorf("fail to find ivpc by id %s %s", self.ExternalId, err) + return nil, fmt.Errorf("fail to find ivpc by id %s", err) + } + return ivpc, nil } func (self *SVpc) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index b12942501b..e24d743669 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -381,7 +381,7 @@ func syncHostStorages(ctx context.Context, provider *models.SCloudprovider, task logSyncFailed(provider, task, msg) return } - result := localHost.SyncHostStorages(ctx, task.UserCred, storages) + localStorages, remoteStorages, result := localHost.SyncHostStorages(ctx, task.UserCred, storages) msg := result.Result() notes := fmt.Sprintf("SyncHostStorages for host %s result: %s", localHost.Name, msg) log.Infof(notes) @@ -391,6 +391,10 @@ func syncHostStorages(ctx context.Context, provider *models.SCloudprovider, task } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) + + for i := 0; i < len(localStorages); i += 1 { + syncStorageCaches(ctx, provider, task, &localStorages[i], remoteStorages[i]) + } } func syncHostWires(ctx context.Context, provider *models.SCloudprovider, task taskman.ITask, localHost *models.SHost, remoteHost cloudprovider.ICloudHost) { diff --git a/pkg/compute/tasks/cloud_provider_sync_onpremise_info_task.go b/pkg/compute/tasks/cloud_provider_sync_onpremise_info_task.go index b0f07904ed..ceb15a3f7c 100644 --- a/pkg/compute/tasks/cloud_provider_sync_onpremise_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_onpremise_info_task.go @@ -14,15 +14,23 @@ import ( ) func syncOnPremiseCloudProviderInfo(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, driver cloudprovider.ICloudProvider, syncRange *models.SSyncRange) { - ihosts, err := driver.GetOnPremiseIHosts() + iregion, err := driver.GetOnPremiseIRegion() if err != nil { - msg := fmt.Sprintf("GetOnPremiseIHosts for provider %s failed %s", provider.GetName(), err) + msg := fmt.Sprintf("GetOnPremiseIRegion for provider %s failed %s", provider.GetName(), err) log.Errorf(msg) logSyncFailed(provider, task, msg) return } - localHosts, remoteHosts, result := models.HostManager.SyncHosts(ctx, task.UserCred, provider, nil, ihosts) + ihosts, err := iregion.GetIHosts() + if err != nil { + msg := fmt.Sprintf("GetIHosts for provider %s failed %s", provider.GetName(), err) + log.Errorf(msg) + logSyncFailed(provider, task, msg) + return + } + + localHosts, remoteHosts, result := models.HostManager.SyncHosts(ctx, task.UserCred, provider, nil, ihosts, syncRange.ProjectSync) msg := result.Result() notes := fmt.Sprintf("SyncHosts for provider %s result: %s", provider.Name, msg) log.Infof(notes) diff --git a/pkg/compute/tasks/disk_base_task.go b/pkg/compute/tasks/disk_base_task.go index 083f78d85d..29133ab173 100644 --- a/pkg/compute/tasks/disk_base_task.go +++ b/pkg/compute/tasks/disk_base_task.go @@ -3,8 +3,6 @@ package tasks import ( "context" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -35,14 +33,5 @@ func (self *SDiskBaseTask) finalReleasePendingUsage(ctx context.Context) { } func (self *SDiskBaseTask) CleanHostSchedCache(disk *models.SDisk) { - storage := disk.GetStorage() - if hosts := storage.GetAllAttachingHosts(); hosts == nil { - log.Errorf("get attaching host error") - } else { - for _, h := range hosts { - if err := h.ClearSchedDescCache(); err != nil { - log.Errorf("host CleanHostSchedCache error: %v", err) - } - } - } + disk.GetStorage().ClearSchedDescCache() } diff --git a/pkg/compute/tasks/disk_resize_task.go b/pkg/compute/tasks/disk_resize_task.go index 9724a171d8..443caf9bdd 100644 --- a/pkg/compute/tasks/disk_resize_task.go +++ b/pkg/compute/tasks/disk_resize_task.go @@ -49,12 +49,12 @@ func (self *DiskResizeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, func (self *DiskResizeTask) StartResizeDisk(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, online bool) { log.Infof("Resizing disk on host %s ...", host.GetName()) self.SetStage("on_disk_resize_complete", nil) - size, _ := self.GetParams().Int("size") + sizeMb, _ := self.GetParams().Int("size") proc := host.GetHostDriver().RequestResizeDiskOnHost if online { proc = host.GetHostDriver().RequestResizeDiskOnHostOnline } - if err := proc(ctx, host, storage, disk, size, self); err != nil { + if err := proc(ctx, host, storage, disk, sizeMb, self); err != nil { log.Errorf("request_resize_disk_on_host: %v", err) self.OnStartResizeDiskFailed(ctx, disk, err) return @@ -80,7 +80,7 @@ func (self *DiskResizeTask) OnDiskResizeComplete(ctx context.Context, disk *mode self.OnStartResizeDiskFailed(ctx, disk, err) return } - size, err := jSize.Int() + sizeMb, err := jSize.Int() if err != nil { log.Errorf("OnDiskResizeComplete error: %s", err.Error()) self.OnStartResizeDiskFailed(ctx, disk, err) @@ -89,7 +89,7 @@ func (self *DiskResizeTask) OnDiskResizeComplete(ctx context.Context, disk *mode oldStatus := disk.Status _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { disk.Status = models.DISK_READY - disk.DiskSize = int(size) + disk.DiskSize = int(sizeMb) return nil }) if err != nil { @@ -107,8 +107,8 @@ func (self *DiskResizeTask) OnDiskResizeComplete(ctx context.Context, disk *mode self.finalReleasePendingUsage(ctx) } -func (self *DiskResizeTask) OnDiskResizeCompleteFailed(ctx context.Context, disk *models.SDisk, reason error) { - disk.SetDiskReady(ctx, self.GetUserCred(), reason.Error()) +func (self *DiskResizeTask) OnDiskResizeCompleteFailed(ctx context.Context, disk *models.SDisk, reason jsonutils.JSONObject) { + disk.SetDiskReady(ctx, self.GetUserCred(), reason.String()) db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, disk.GetShortDesc(), self.UserCred) - logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason.Error(), self.UserCred, false) + logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason.String(), self.UserCred, false) } diff --git a/pkg/compute/tasks/guest_change_config_task.go b/pkg/compute/tasks/guest_change_config_task.go index 6c1a9ea3da..4586541dcb 100644 --- a/pkg/compute/tasks/guest_change_config_task.go +++ b/pkg/compute/tasks/guest_change_config_task.go @@ -2,6 +2,7 @@ package tasks import ( "context" + "fmt" "yunion.io/x/jsonutils" @@ -32,69 +33,63 @@ func (self *GuestChangeConfigTask) OnInit(ctx context.Context, obj db.IStandalon } func (self *GuestChangeConfigTask) OnDisksResizeComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + iResizeDisks, err := self.Params.Get("resize") if iResizeDisks == nil || err != nil { - self.markStageFailed(obj, ctx, err.Error()) + self.markStageFailed(ctx, guest, err.Error()) return } resizeDisks := iResizeDisks.(*jsonutils.JSONArray) for i := 0; i < resizeDisks.Length(); i++ { iResizeSet, err := resizeDisks.GetAt(i) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("resizeDisks.GetAt fail %s", err)) return } resizeSet := iResizeSet.(*jsonutils.JSONArray) diskId, err := resizeSet.GetAt(0) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("resizeSet.GetAt(0) fail %s", err)) return } idStr, err := diskId.GetString() if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("diskId.GetString fail %s", err)) return } jSize, err := resizeSet.GetAt(1) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("resizeSet.GetAt(1) fail %s", err)) return } size, err := jSize.Int() if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("jSize.Int fail %s", err)) return } iDisk, err := models.DiskManager.FetchById(idStr) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("models.DiskManager.FetchById(idStr) fail %s", err)) return } disk := iDisk.(*models.SDisk) - if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(disk, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) - return - } if disk.DiskSize < int(size) { var pendingUsage models.SQuota err = self.GetPendingUsage(&pendingUsage) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(disk, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("self.GetPendingUsage(&pendingUsage) fail %s", err)) + return + } + err = disk.StartDiskResizeTask(ctx, self.UserCred, size, self.GetTaskId(), &pendingUsage) + if err != nil { + self.markStageFailed(ctx, guest, fmt.Sprintf("disk.StartDiskResizeTask fail %s", err)) return } - disk.StartDiskResizeTask(ctx, self.UserCred, size, self.GetTaskId(), &pendingUsage) return } } - guest := obj.(*models.SGuest) + self.DoCreateDisksTask(ctx, guest) } @@ -107,12 +102,11 @@ func (self *GuestChangeConfigTask) DoCreateDisksTask(ctx context.Context, guest data := (iCreateData).(*jsonutils.JSONDict) self.SetStage("on_create_disks_complete", nil) guest.StartGuestCreateDiskTask(ctx, self.UserCred, data, self.GetTaskId()) - } func (self *GuestChangeConfigTask) OnCreateDisksCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { - self.markStageFailed(obj, ctx, err.String()) - logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + guest := obj.(*models.SGuest) + self.markStageFailed(ctx, guest, fmt.Sprintf("OnCreateDisksCompleteFailed %s", err)) } func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -125,23 +119,20 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob if iVcpuCount != nil { vcpuCount, err = iVcpuCount.Int() if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("iVcpuCount.Int() fail %s", err)) return } } if iVmemSize != nil { vmemSize, err = iVmemSize.Int() if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("iVmemSize.Int fail %s", err)) return } } err = guest.GetDriver().RequestChangeVmConfig(ctx, guest, self, vcpuCount, vmemSize) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("guest.GetDriver().RequestChangeVmConfig fail %s", err)) return } var addCpu, addMem = 0, 0 @@ -167,15 +158,13 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob return nil }) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("Update fail %s", err)) return } var pendingUsage models.SQuota err = self.GetPendingUsage(&pendingUsage) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("GetPendingUsage %s", err)) return } // ownerCred := guest.GetOwnerUserCred() @@ -192,22 +181,19 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, &cancelUsage) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("CancelPendingUsage fail %s", err)) return } err = self.SetPendingUsage(&pendingUsage) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("SetPendingUsage fail %s", err)) return } } self.SetStage("on_sync_status_complete", nil) err = guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) if err != nil { - self.markStageFailed(obj, ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) + self.markStageFailed(ctx, guest, fmt.Sprintf("StartSyncstatus fail %s", err)) return } } @@ -221,8 +207,8 @@ func (self *GuestChangeConfigTask) OnSyncStatusComplete(ctx context.Context, obj } else { dt := jsonutils.NewDict() dt.Add(jsonutils.NewString(guest.Id), "id") - self.SetStageComplete(ctx, dt) logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, "", self.UserCred, true) + self.SetStageComplete(ctx, dt) } } @@ -233,8 +219,9 @@ func (self *GuestChangeConfigTask) OnGuestStartComplete(ctx context.Context, obj self.SetStageComplete(ctx, dt) } -func (self *GuestChangeConfigTask) markStageFailed(obj db.IStandaloneModel, ctx context.Context, reason string) { - guest := obj.(*models.SGuest) +func (self *GuestChangeConfigTask) markStageFailed(ctx context.Context, guest *models.SGuest, reason string) { guest.SetStatus(self.UserCred, models.VM_CHANGE_FLAVOR_FAIL, reason) + db.OpsLog.LogEvent(guest, db.ACT_CHANGE_FLAVOR_FAIL, reason, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, reason, self.UserCred, false) self.SetStageFailed(ctx, reason) } diff --git a/pkg/compute/tasks/guest_create_disk_task.go b/pkg/compute/tasks/guest_create_disk_task.go index 76502bc2e3..4afe217e10 100644 --- a/pkg/compute/tasks/guest_create_disk_task.go +++ b/pkg/compute/tasks/guest_create_disk_task.go @@ -105,7 +105,7 @@ func (self *KVMGuestCreateDiskTask) OnKvmDiskPrepared(ctx context.Context, obj d guest := obj.(*models.SGuest) if guest.Status == models.VM_RUNNING { self.SetStage("on_config_sync_complete", nil) - err := guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) + err := guest.StartSyncTask(ctx, self.UserCred, false, self.GetTaskId()) if err != nil { self.SetStageFailed(ctx, err.Error()) } @@ -184,15 +184,9 @@ func (self *ManagedGuestCreateDiskTask) OnManagedDiskPrepared(ctx context.Contex break } - ihost, err := guest.GetHost().GetIHost() - if err != nil { - self.SetStageFailed(ctx, "Host not found") - return - } - - iVM, e := ihost.GetIVMById(guest.GetExternalId()) + iVM, e := guest.GetIVM() if e != nil { - self.SetStageFailed(ctx, "Aliyun VM not found") + self.SetStageFailed(ctx, "iVM not found") return } @@ -205,7 +199,7 @@ func (self *ManagedGuestCreateDiskTask) OnManagedDiskPrepared(ctx context.Contex diskIndex += 1 } - if diskReady { + /*if diskReady { if guest.Status == models.VM_RUNNING { self.SetStage("on_config_sync_complete", nil) err := guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) @@ -213,16 +207,90 @@ func (self *ManagedGuestCreateDiskTask) OnManagedDiskPrepared(ctx context.Contex self.SetStageFailed(ctx, err.Error()) } } else { - self.SetStageComplete(ctx, nil) - } - } -} -func (self *ManagedGuestCreateDiskTask) OnConfigSyncComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + } + }*/ + self.SetStageComplete(ctx, nil) } -func (self *ManagedGuestCreateDiskTask) AttachManagedDisks(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { +/* +func (self *ManagedGuestCreateDiskTask) OnConfigSyncComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} +*/ + +type ESXiGuestCreateDiskTask struct { + SGuestBaseTask +} + +func (self *ESXiGuestCreateDiskTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + host := guest.GetHost() + if host == nil { + self.SetStageFailed(ctx, "no valid host") + return + } + + diskIndex := 0 + for { + diskKey := fmt.Sprintf("disk.%d.id", diskIndex) + if !self.Params.Contains(diskKey) { + break + } + diskId, _ := self.Params.GetString(diskKey) + diskIndex += 1 + guestDisk := guest.GetGuestDisk(diskId) + if guestDisk == nil { + self.SetStageFailed(ctx, "fail to find guestdisk") + return + } + disk := guestDisk.GetDisk() + if disk == nil { + self.SetStageFailed(ctx, fmt.Sprintf("Disk %s not found", diskId)) + return + } + if disk.Status != models.DISK_INIT { + self.SetStageFailed(ctx, fmt.Sprintf("Disk %s already created??", diskId)) + return + } + ivm, err := guest.GetIVM() + if err != nil { + self.SetStageFailed(ctx, fmt.Sprintf("fail to find iVM for %s", guest.GetName())) + return + } + err = ivm.CreateDisk(ctx, disk.DiskSize, disk.Id, guestDisk.Driver) + if err != nil { + self.SetStageFailed(ctx, fmt.Sprintf("ivm.CreateDisk fail %s", guest.GetName())) + return + } + idisks, err := ivm.GetIDisks() + if err != nil { + self.SetStageFailed(ctx, fmt.Sprintf("ivm.GetIDisks fail %s", err)) + return + } + + log.Debugf("diskcount after create: %d", len(idisks)) + + vdisk := idisks[len(idisks)-1] + + _, err = disk.GetModelManager().TableSpec().Update(disk, func() error { + disk.DiskSize = vdisk.GetDiskSizeMB() + disk.AccessPath = vdisk.GetAccessPath() + disk.ExternalId = vdisk.GetGlobalId() + return nil + }) + if err != nil { + self.SetStageFailed(ctx, fmt.Sprintf("disk.GetModelManager().TableSpec().Update fail %s", err)) + return + } + + disk.SetStatus(self.UserCred, models.DISK_READY, "create disk success") + disk.GetStorage().ClearSchedDescCache() + db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), self.UserCred) + db.OpsLog.LogAttachEvent(guest, disk, self.UserCred, disk.GetShortDesc()) + } + self.SetStageComplete(ctx, nil) } @@ -230,4 +298,5 @@ func init() { taskman.RegisterTask(GuestCreateDiskTask{}) taskman.RegisterTask(KVMGuestCreateDiskTask{}) taskman.RegisterTask(ManagedGuestCreateDiskTask{}) + taskman.RegisterTask(ESXiGuestCreateDiskTask{}) } diff --git a/pkg/compute/tasks/storage_cache_image_task.go b/pkg/compute/tasks/storage_cache_image_task.go index bd3d476fab..3b226aa9f7 100644 --- a/pkg/compute/tasks/storage_cache_image_task.go +++ b/pkg/compute/tasks/storage_cache_image_task.go @@ -46,8 +46,8 @@ func (self *StorageCacheImageTask) OnImageCacheComplete(ctx context.Context, obj storageCache := obj.(*models.SStoragecache) imageId, _ := self.Params.GetString("image_id") scimg := models.StoragecachedimageManager.Register(ctx, self.UserCred, storageCache.Id, imageId) - // extImgId, _ := data.GetString("image_id") - self.OnCacheSucc(ctx, storageCache, imageId, scimg) + extImgId, _ := data.GetString("image_id") + self.OnCacheSucc(ctx, storageCache, imageId, scimg, extImgId) } func (self *StorageCacheImageTask) OnImageCacheCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -55,14 +55,15 @@ func (self *StorageCacheImageTask) OnImageCacheCompleteFailed(ctx context.Contex imageId, _ := self.Params.GetString("image_id") scimg := models.StoragecachedimageManager.Register(ctx, self.UserCred, storageCache.Id, imageId) err := fmt.Errorf(data.String()) - self.OnCacheFailed(ctx, storageCache, imageId, scimg, err) + extImgId, _ := data.GetString("image_id") + self.OnCacheFailed(ctx, storageCache, imageId, scimg, err, extImgId) } -func (self *StorageCacheImageTask) OnCacheFailed(ctx context.Context, cache *models.SStoragecache, imageId string, scimg *models.SStoragecachedimage, err error) { +func (self *StorageCacheImageTask) OnCacheFailed(ctx context.Context, cache *models.SStoragecache, imageId string, scimg *models.SStoragecachedimage, err error, extImgId string) { scimg.SetStatus(self.UserCred, models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) - /* if len(extImgId) > 0 && scimg.ExternalId != extImgId { + if len(extImgId) > 0 && scimg.ExternalId != extImgId { scimg.SetExternalId(extImgId) - }*/ + } body := jsonutils.NewDict() body.Add(jsonutils.NewString(err.Error()), "reason") body.Add(jsonutils.NewString(imageId), "image_id") @@ -70,8 +71,11 @@ func (self *StorageCacheImageTask) OnCacheFailed(ctx context.Context, cache *mod self.SetStageFailed(ctx, err.Error()) } -func (self *StorageCacheImageTask) OnCacheSucc(ctx context.Context, cache *models.SStoragecache, imageId string, scimg *models.SStoragecachedimage) { +func (self *StorageCacheImageTask) OnCacheSucc(ctx context.Context, cache *models.SStoragecache, imageId string, scimg *models.SStoragecachedimage, extImgId string) { scimg.SetStatus(self.UserCred, models.CACHED_IMAGE_STATUS_READY, "cached") + if len(extImgId) > 0 && scimg.ExternalId != extImgId { + scimg.SetExternalId(extImgId) + } models.CachedimageManager.ImageAddRefCount(imageId) db.OpsLog.LogEvent(cache, db.ACT_CACHED_IMAGE, imageId, self.UserCred) self.SetStageComplete(ctx, nil) diff --git a/pkg/compute/tasks/storage_uncache_image_task.go b/pkg/compute/tasks/storage_uncache_image_task.go index 7e4e9743b9..63020d977a 100644 --- a/pkg/compute/tasks/storage_uncache_image_task.go +++ b/pkg/compute/tasks/storage_uncache_image_task.go @@ -2,11 +2,15 @@ package tasks import ( "context" + "fmt" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + + "yunion.io/x/onecloud/pkg/util/logclient" ) type StorageUncacheImageTask struct { @@ -23,15 +27,74 @@ func (self *StorageUncacheImageTask) OnInit(ctx context.Context, obj db.IStandal storageCache := obj.(*models.SStoragecache) + db.OpsLog.LogEvent(storageCache, db.ACT_UNCACHING_IMAGE, imageId, self.UserCred) + scimg := models.StoragecachedimageManager.Register(ctx, self.UserCred, storageCache.Id, imageId) - db.OpsLog.LogEvent(storageCache, db.ACT_UNCACHED_IMAGE, imageId, self.UserCred) + if scimg == nil || len(scimg.Path) == 0 { + // "image is not cached on this storage" + self.OnImageUncacheComplete(ctx, storageCache, nil) + } if isForce { - scimg.Detach(ctx, self.UserCred) - self.SetStageComplete(ctx, nil) + self.OnImageUncacheComplete(ctx, obj, data) return } - // TODO + host, err := storageCache.GetHost() + if err != nil { + self.OnTaskFailed(ctx, storageCache, fmt.Sprintf("fail to get host %s", err)) + return + } + + if host == nil { + self.OnImageUncacheComplete(ctx, obj, data) + return + } + + self.SetStage("OnImageUncacheComplete", nil) + + err = host.GetHostDriver().RequestUncacheImage(ctx, host, storageCache, self) + + if err != nil { + self.OnTaskFailed(ctx, storageCache, fmt.Sprintf("fail to uncache image %s", err)) + } +} + +func (self *StorageUncacheImageTask) OnTaskFailed(ctx context.Context, storageCache *models.SStoragecache, reason string) { + body := jsonutils.NewDict() + body.Add(jsonutils.NewString(reason), "reason") + imageId, _ := self.Params.GetString("image_id") + body.Add(jsonutils.NewString(imageId), "image_id") + + db.OpsLog.LogEvent(storageCache, db.ACT_UNCACHE_IMAGE_FAIL, body, self.UserCred) + + logclient.AddActionLog(storageCache, logclient.ACT_UNCACHED_IMAGE, body, self.UserCred, false) + + self.SetStageFailed(ctx, reason) +} + +func (self *StorageUncacheImageTask) OnImageUncacheCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + storageCache := obj.(*models.SStoragecache) + + self.OnTaskFailed(ctx, storageCache, data.String()) +} + +func (self *StorageUncacheImageTask) OnImageUncacheComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + log.Infof("Uncached image task success: %s", data) + storageCache := obj.(*models.SStoragecache) + + imageId, _ := self.Params.GetString("image_id") + scimg := models.StoragecachedimageManager.Register(ctx, self.UserCred, storageCache.Id, imageId) + if scimg != nil { + scimg.Detach(ctx, self.UserCred) + } + + body := jsonutils.NewDict() + body.Add(jsonutils.NewString(imageId), "image_id") + db.OpsLog.LogEvent(storageCache, db.ACT_UNCACHED_IMAGE, body, self.UserCred) + + logclient.AddActionLog(storageCache, db.ACT_UNCACHED_IMAGE, body, self.UserCred, true) + + self.SetStageComplete(ctx, nil) } diff --git a/pkg/mcclient/modules/managers.go b/pkg/mcclient/modules/managers.go index f1cc0ded38..62c7cb6d1a 100644 --- a/pkg/mcclient/modules/managers.go +++ b/pkg/mcclient/modules/managers.go @@ -155,4 +155,4 @@ func NewCloudmetaManager(keyword, keywordPlural string, columns, adminColumns [] adminColumns: adminColumns, serviceType: "cloudmeta"}, Keyword: keyword, KeywordPlural: keywordPlural} -} \ No newline at end of file +} diff --git a/pkg/mcclient/modules/resource.go b/pkg/mcclient/modules/resource.go index 35399fa2a2..65528750c4 100644 --- a/pkg/mcclient/modules/resource.go +++ b/pkg/mcclient/modules/resource.go @@ -297,7 +297,7 @@ func (this *ResourceManager) params2Body(s *mcclient.ClientSession, params jsonu return body } -func (this *ResourceManager)Create(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (this *ResourceManager) Create(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { return this.CreateInContexts(session, params, nil) } diff --git a/pkg/util/aliyun/aliyun.go b/pkg/util/aliyun/aliyun.go index 79fb5b905e..ddb092deb3 100644 --- a/pkg/util/aliyun/aliyun.go +++ b/pkg/util/aliyun/aliyun.go @@ -192,15 +192,3 @@ func (self *SAliyunClient) GetIStorageById(id string) (cloudprovider.ICloudStora } return nil, cloudprovider.ErrNotFound } - -func (self *SAliyunClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - for i := 0; i < len(self.iregions); i += 1 { - ihost, err := self.iregions[i].GetIStoragecacheById(id) - if err == nil { - return ihost, nil - } else if err != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index c1189f130c..0f1507dd45 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -122,8 +122,8 @@ func (self *SDisk) Delete(ctx context.Context) error { return self.storage.zone.region.deleteDisk(self.DiskId) } -func (self *SDisk) Resize(ctx context.Context, size int64) error { - return self.storage.zone.region.resizeDisk(self.DiskId, size) +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.resizeDisk(self.DiskId, sizeMb) } func (self *SDisk) GetName() string { @@ -262,14 +262,15 @@ func (self *SRegion) DeleteDisk(diskId string) error { return err } -func (self *SRegion) resizeDisk(diskId string, size int64) error { +func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { + sizeGb := sizeMb / 1024 params := make(map[string]string) params["DiskId"] = diskId - params["NewSize"] = fmt.Sprintf("%d", size) + params["NewSize"] = fmt.Sprintf("%d", sizeGb) _, err := self.ecsRequest("ResizeDisk", params) if err != nil { - log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, size, err) + log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, sizeGb, err) return err } @@ -377,3 +378,7 @@ func (self *SDisk) GetBillingType() string { func (self *SDisk) GetExpiredAt() time.Time { return self.ExpiredTime } + +func (self *SDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/aliyun/image.go b/pkg/util/aliyun/image.go index 3f6947e89e..a34713576f 100644 --- a/pkg/util/aliyun/image.go +++ b/pkg/util/aliyun/image.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "context" "github.com/aliyun/aliyun-oss-go-sdk/oss" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -85,7 +86,7 @@ func (self *SImage) IsEmulated() bool { return false } -func (self *SImage) Delete() error { +func (self *SImage) Delete(ctx context.Context) error { return self.storageCache.region.DeleteImage(self.ImageId) } diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index 52aa481a3e..d352d2a869 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -467,7 +467,7 @@ func (self *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd s return diskId, nil } -func (self *SInstance) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { +func (self *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, ncpu, vmem, nil) } @@ -861,3 +861,7 @@ func (self *SInstance) GetExpiredAt() time.Time { func (self *SInstance) UpdateUserData(userData string) error { return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) } + +func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/util/aliyun/provider/provider.go b/pkg/util/aliyun/provider/provider.go index fe5a4a1813..6b3d2efa99 100644 --- a/pkg/util/aliyun/provider/provider.go +++ b/pkg/util/aliyun/provider/provider.go @@ -83,24 +83,8 @@ func (self *SAliyunProvider) GetIRegions() []cloudprovider.ICloudRegion { return self.client.GetIRegions() } -func (self *SAliyunProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SAliyunProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return self.client.GetIHostById(id) -} - -func (self *SAliyunProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - return self.client.GetIVpcById(id) -} - -func (self *SAliyunProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.client.GetIStorageById(id) -} - -func (self *SAliyunProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - return self.client.GetIStoragecacheById(id) +func (self *SAliyunProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) } func (self *SAliyunProvider) GetBalance() (float64, error) { @@ -111,6 +95,6 @@ func (self *SAliyunProvider) GetBalance() (float64, error) { return balance.AvailableAmount, nil } -func (self *SAliyunProvider) GetOnPremiseIHosts() ([]cloudprovider.ICloudHost, error) { +func (self *SAliyunProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index fecb4d90cb..42e0cecec3 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -550,6 +550,40 @@ func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, er return nil, cloudprovider.ErrNotFound } +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { storageCache := self.getStoragecache() if storageCache.GetGlobalId() == id { diff --git a/pkg/util/aliyun/storage.go b/pkg/util/aliyun/storage.go index d8dec31739..26c1a729c2 100644 --- a/pkg/util/aliyun/storage.go +++ b/pkg/util/aliyun/storage.go @@ -118,7 +118,7 @@ func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudpr return disk, nil } -func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { if disk, err := self.zone.region.getDisk(idStr); err != nil { return nil, err } else { @@ -126,3 +126,7 @@ func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { return disk, nil } } + +func (self *SStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/aliyun/storagecache.go b/pkg/util/aliyun/storagecache.go index 231d5d3623..a1318f5bd0 100644 --- a/pkg/util/aliyun/storagecache.go +++ b/pkg/util/aliyun/storagecache.go @@ -87,6 +87,22 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { return self.iimages, nil } +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + parts, _, err := self.region.GetImages(ImageStatusType(""), ImageOwnerSelf, []string{extId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + parts[0].storageCache = self + return &parts[0], nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) { if len(extId) > 0 { diff --git a/pkg/util/aws/aws.go b/pkg/util/aws/aws.go index cbdfc5bf06..65224a5c37 100644 --- a/pkg/util/aws/aws.go +++ b/pkg/util/aws/aws.go @@ -185,18 +185,6 @@ func (self *SAwsClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, return nil, cloudprovider.ErrNotFound } -func (self *SAwsClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - for i := 0; i < len(self.iregions); i += 1 { - ihost, err := self.iregions[i].GetIStoragecacheById(id) - if err == nil { - return ihost, nil - } else if err != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - type SAccountBalance struct { AvailableAmount float64 AvailableCashAmount float64 diff --git a/pkg/util/aws/disk.go b/pkg/util/aws/disk.go index f11e2912bc..20308db644 100644 --- a/pkg/util/aws/disk.go +++ b/pkg/util/aws/disk.go @@ -215,8 +215,8 @@ func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { return isnapshots, nil } -func (self *SDisk) Resize(ctx context.Context, newSize int64) error { - return self.storage.zone.region.resizeDisk(self.DiskId, newSize) +func (self *SDisk) Resize(ctx context.Context, newSizeMb int64) error { + return self.storage.zone.region.resizeDisk(self.DiskId, newSizeMb) } func (self *SDisk) Reset(ctx context.Context, snapshotId string) error { @@ -344,14 +344,15 @@ func (self *SRegion) DeleteDisk(diskId string) error { return err } -func (self *SRegion) resizeDisk(diskId string, size int64) error { +func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { // https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/volume_constraints.html // MBR -> 2 TiB // GPT -> 16 TiB // size unit GiB + sizeGb := sizeMb / 1024 params := &ec2.ModifyVolumeInput{} - if size > 0 { - params.SetSize(size) + if sizeGb > 0 { + params.SetSize(sizeGb) } else { return fmt.Errorf("size should great than 0") } @@ -440,3 +441,7 @@ func (self *SRegion) CreateDisk(zoneId string, category string, name string, siz } return StrVal(ret.VolumeId), nil } + +func (disk *SDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/aws/image.go b/pkg/util/aws/image.go index 700e43692b..d77deabae1 100644 --- a/pkg/util/aws/image.go +++ b/pkg/util/aws/image.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "context" "github.com/aws/aws-sdk-go/service/ec2" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -115,7 +116,7 @@ func (self *SImage) GetMetadata() *jsonutils.JSONDict { return data } -func (self *SImage) Delete() error { +func (self *SImage) Delete(ctx context.Context) error { // todo: implement me return self.storageCache.region.DeleteImage(self.ImageId) } diff --git a/pkg/util/aws/instance.go b/pkg/util/aws/instance.go index de1e3c9f48..4d72a804de 100644 --- a/pkg/util/aws/instance.go +++ b/pkg/util/aws/instance.go @@ -369,7 +369,7 @@ func (self *SInstance) DeployVM(ctx context.Context, name string, password strin return self.host.zone.region.DeployVM(self.InstanceId, name, password, publicKey, deleteKeypair, description) } -func (self *SInstance) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { +func (self *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, ncpu, vmem, nil) } @@ -819,3 +819,7 @@ func (self *SRegion) AttachDisk(instanceId string, diskId string, deviceName str _, err := self.ec2Client.AttachVolume(params) return err } + +func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/util/aws/provider/provider.go b/pkg/util/aws/provider/provider.go index 20c6327245..fc44072ac3 100644 --- a/pkg/util/aws/provider/provider.go +++ b/pkg/util/aws/provider/provider.go @@ -66,22 +66,6 @@ func (self *SAwsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, return self.client.GetIRegionById(id) } -func (self *SAwsProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return self.client.GetIHostById(id) -} - -func (self *SAwsProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - return self.client.GetIVpcById(id) -} - -func (self *SAwsProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.client.GetIStorageById(id) -} - -func (self *SAwsProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - return self.client.GetIStoragecacheById(id) -} - func (self *SAwsProvider) GetBalance() (float64, error) { balance, err := self.client.QueryAccountBalance() if err != nil { @@ -90,6 +74,6 @@ func (self *SAwsProvider) GetBalance() (float64, error) { return balance.AvailableAmount, nil } -func (self *SAwsProvider) GetOnPremiseIHosts() ([]cloudprovider.ICloudHost, error) { +func (self *SAwsProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } diff --git a/pkg/util/aws/region.go b/pkg/util/aws/region.go index 910bae7767..3206112667 100644 --- a/pkg/util/aws/region.go +++ b/pkg/util/aws/region.go @@ -348,6 +348,40 @@ func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, er return nil, cloudprovider.ErrNotFound } +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { if self.storageCache == nil { self.storageCache = &SStoragecache{region: self} diff --git a/pkg/util/aws/storage.go b/pkg/util/aws/storage.go index 35d7081df8..937598edcc 100644 --- a/pkg/util/aws/storage.go +++ b/pkg/util/aws/storage.go @@ -114,7 +114,7 @@ func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudpr return disk, nil } -func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { if disk, err := self.zone.region.GetDisk(idStr); err != nil { return nil, err } else { @@ -122,3 +122,7 @@ func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { return disk, nil } } + +func (self *SStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/aws/storagecache.go b/pkg/util/aws/storagecache.go index b1a42471bd..c43e88ec6f 100644 --- a/pkg/util/aws/storagecache.go +++ b/pkg/util/aws/storagecache.go @@ -61,6 +61,22 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { return self.iimages, nil } +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + parts, _, err := self.region.GetImages(ImageStatusType(""), ImageOwnerSelf, []string{extId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + parts[0].storageCache = self + return &parts[0], nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + func (self *SStoragecache) GetManagerId() string { return self.region.client.providerId } diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index ad7268feb6..95e08cd7ea 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -707,18 +707,6 @@ func (self *SAzureClient) GetIStorageById(id string) (cloudprovider.ICloudStorag return nil, cloudprovider.ErrNotFound } -func (self *SAzureClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - for i := 0; i < len(self.iregions); i += 1 { - ihost, err := self.iregions[i].GetIStoragecacheById(id) - if err == nil { - return ihost, nil - } else if err != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - type SAccountBalance struct { AvailableAmount float64 AvailableCashAmount float64 diff --git a/pkg/util/azure/classic_disk.go b/pkg/util/azure/classic_disk.go index 3ead009503..895a937bc3 100644 --- a/pkg/util/azure/classic_disk.go +++ b/pkg/util/azure/classic_disk.go @@ -209,6 +209,10 @@ func (self *SClassicDisk) Reset(ctx context.Context, snapshotId string) error { return cloudprovider.ErrNotSupported } -func (self *SClassicDisk) Resize(ctx context.Context, size int64) error { +func (self *SClassicDisk) Resize(ctx context.Context, sizeMb int64) error { return cloudprovider.ErrNotSupported } + +func (disk *SClassicDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index a53a3da659..6a7006c578 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -270,11 +270,8 @@ func (self *SClassicInstance) DetachDisk(ctx context.Context, diskId string) err return cloudprovider.WaitStatus(self, self.GetStatus(), 10*time.Second, 300*time.Second) } -func (self *SClassicInstance) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { - if err := self.host.zone.region.ChangeVMConfig(ctx, instanceId, ncpu, vmem); err != nil { - return err - } - return cloudprovider.WaitStatus(self, self.GetStatus(), 10*time.Second, 300*time.Second) +func (self *SClassicInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { + return cloudprovider.ErrNotImplemented } func (self *SClassicInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error { @@ -462,3 +459,7 @@ func (self *SClassicInstance) GetExpiredAt() time.Time { func (self *SClassicInstance) UpdateUserData(userData string) error { return cloudprovider.ErrNotSupported } + +func (self *SClassicInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/util/azure/classic_storage.go b/pkg/util/azure/classic_storage.go index 7f33ce8012..329f965637 100644 --- a/pkg/util/azure/classic_storage.go +++ b/pkg/util/azure/classic_storage.go @@ -66,7 +66,7 @@ func (self *SClassicStorage) CreateIDisk(name string, sizeGb int, desc string) ( return nil, cloudprovider.ErrNotImplemented } -func (self *SClassicStorage) GetIDisk(diskId string) (cloudprovider.ICloudDisk, error) { +func (self *SClassicStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { disks, err := self.GetIDisks() if err != nil { return nil, err @@ -125,3 +125,7 @@ func (self *SClassicStorage) Refresh() error { // do nothing return nil } + +func (self *SClassicStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go index 06cb70e2fb..57b7490183 100644 --- a/pkg/util/azure/disk.go +++ b/pkg/util/azure/disk.go @@ -173,8 +173,8 @@ func (self *SDisk) Delete(ctx context.Context) error { return self.storage.zone.region.deleteDisk(self.ID) } -func (self *SDisk) Resize(ctx context.Context, size int64) error { - return self.storage.zone.region.ResizeDisk(self.ID, int32(size)) +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.ResizeDisk(self.ID, int32(sizeMb/1024)) } func (self *SDisk) GetName() string { @@ -321,3 +321,7 @@ func (self *SDisk) Reset(ctx context.Context, snapshotId string) error { func (self *SRegion) resetDisk(diskId, snapshotId string) error { return cloudprovider.ErrNotSupported } + +func (disk *SDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/azure/image.go b/pkg/util/azure/image.go index a5fe3a2c30..8c53edcefd 100644 --- a/pkg/util/azure/image.go +++ b/pkg/util/azure/image.go @@ -3,6 +3,7 @@ package azure import ( "strings" + "context" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -141,6 +142,20 @@ func (self *SRegion) GetImageByName(name string) (*SImage, error) { return nil, cloudprovider.ErrNotFound } +func (self *SRegion) GetImageById(idstr string) (*SImage, error) { + images := []SImage{} + err := self.client.ListAll("Microsoft.Compute/images", &images) + if err != nil { + return nil, err + } + for i := 0; i < len(images); i++ { + if images[i].ID == idstr { + return &images[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + func (self *SRegion) CreateImageByBlob(imageName, osType, blobURI string, diskSizeGB int32) (*SImage, error) { if diskSizeGB < 1 || diskSizeGB > 4095 { diskSizeGB = 30 @@ -207,7 +222,7 @@ func (self *SImage) GetBlobUri() string { return self.Properties.StorageProfile.OsDisk.BlobURI } -func (self *SImage) Delete() error { +func (self *SImage) Delete(ctx context.Context) error { return self.storageCache.region.DeleteImage(self.ID) } diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index b9aaf9d93f..7effd68a8f 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -548,7 +548,7 @@ func (region *SRegion) DetachDisk(instanceId, diskId string) error { return region.client.Update(jsonutils.Marshal(instance), nil) } -func (self *SInstance) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { +func (self *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { for _, vmSize := range self.host.zone.region.getHardwareProfile(ncpu, vmem) { self.Properties.HardwareProfile.VMSize = vmSize self.Properties.ProvisioningState = "" @@ -567,7 +567,7 @@ func (region *SRegion) ChangeVMConfig(ctx context.Context, instanceId string, nc if err != nil { return err } - return instacen.ChangeConfig(ctx, instanceId, ncpu, vmem) + return instacen.ChangeConfig(ctx, ncpu, vmem) } func (self *SInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error { @@ -1041,3 +1041,7 @@ func (self *SInstance) GetExpiredAt() time.Time { func (self *SInstance) UpdateUserData(userData string) error { return cloudprovider.ErrNotSupported } + +func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/util/azure/provider/provider.go b/pkg/util/azure/provider/provider.go index 214877edd3..a4925b2395 100644 --- a/pkg/util/azure/provider/provider.go +++ b/pkg/util/azure/provider/provider.go @@ -67,22 +67,6 @@ func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegio return self.client.GetIRegionById(id) } -func (self *SAzureProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return self.client.GetIHostById(id) -} - -func (self *SAzureProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - return self.client.GetIVpcById(id) -} - -func (self *SAzureProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.client.GetIStorageById(id) -} - -func (self *SAzureProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - return self.client.GetIStoragecacheById(id) -} - func (self *SAzureProvider) GetBalance() (float64, error) { balance, err := self.client.QueryAccountBalance() if err != nil { @@ -91,6 +75,6 @@ func (self *SAzureProvider) GetBalance() (float64, error) { return balance.AvailableAmount, nil } -func (self *SAzureProvider) GetOnPremiseIHosts() ([]cloudprovider.ICloudHost, error) { +func (self *SAzureProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } diff --git a/pkg/util/azure/region.go b/pkg/util/azure/region.go index ff634bdb8c..fbba907727 100644 --- a/pkg/util/azure/region.go +++ b/pkg/util/azure/region.go @@ -175,6 +175,40 @@ func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, er return nil, cloudprovider.ErrNotFound } +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { storageCache := self.getStoragecache() if storageCache.GetGlobalId() == id { diff --git a/pkg/util/azure/storage.go b/pkg/util/azure/storage.go index 660b3bd69d..964a501fb8 100644 --- a/pkg/util/azure/storage.go +++ b/pkg/util/azure/storage.go @@ -68,7 +68,7 @@ func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudpr return disk, nil } -func (self *SStorage) GetIDisk(diskId string) (cloudprovider.ICloudDisk, error) { +func (self *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { if disk, err := self.zone.region.GetDisk(diskId); err != nil { return nil, err } else { @@ -157,3 +157,7 @@ func (self *SStorage) Refresh() error { // do nothing return nil } + +func (self *SStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/azure/storagecache.go b/pkg/util/azure/storagecache.go index 0715ea4393..d5f1955237 100644 --- a/pkg/util/azure/storagecache.go +++ b/pkg/util/azure/storagecache.go @@ -84,6 +84,19 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { return self.iimages, nil } +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + img, err := self.region.GetImageById(extId) + if err != nil { + return nil, err + } + img.storageCache = self + return img, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) { if len(extId) > 0 { log.Debugf("UploadImage: Image external ID exists %s", extId) diff --git a/pkg/util/esxi/datacenter.go b/pkg/util/esxi/datacenter.go index 652facd020..1a6a5c0124 100644 --- a/pkg/util/esxi/datacenter.go +++ b/pkg/util/esxi/datacenter.go @@ -1,7 +1,10 @@ package esxi import ( + "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" ) @@ -26,6 +29,10 @@ func (dc *SDatacenter) getDatacenter() *mo.Datacenter { return dc.object.(*mo.Datacenter) } +func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter { + return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) +} + func (dc *SDatacenter) scanHosts() error { if dc.ihosts == nil { var hosts []mo.HostSystem @@ -51,15 +58,11 @@ func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) { func (dc *SDatacenter) scanDatastores() error { if dc.istorages == nil { - stores := make([]mo.Datastore, 0) + var stores []mo.Datastore dsList := dc.getDatacenter().Datastore - for i := 0; i < len(dsList); i += 1 { - var ds mo.Datastore - err := dc.manager.reference2Object(dsList[i], DATASTORE_PROPS, &ds) - if err != nil { - return err - } - stores = append(stores, ds) + err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores) + if err != nil { + return err } dc.istorages = make([]cloudprovider.ICloudStorage, len(stores)) for i := 0; i < len(stores); i += 1 { @@ -102,3 +105,22 @@ func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStor } return nil, cloudprovider.ErrNotFound } + +func (dc *SDatacenter) getDcObj() *object.Datacenter { + return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) +} + +func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudVM, error) { + var vms []mo.VirtualMachine + err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &vms) + if err != nil { + log.Errorf("references2Objects fail %s", err) + return nil, err + } + + retVms := make([]cloudprovider.ICloudVM, len(vms)) + for i := 0; i < len(vms); i += 1 { + retVms[i] = NewVirtualMachine(dc.manager, &vms[i], dc) + } + return retVms, nil +} diff --git a/pkg/util/esxi/devtools.go b/pkg/util/esxi/devtools.go new file mode 100644 index 0000000000..ec66271fd7 --- /dev/null +++ b/pkg/util/esxi/devtools.go @@ -0,0 +1,43 @@ +package esxi + +import ( + "github.com/vmware/govmomi/vim25/types" +) + +func NewDiskDev(sizeMb int64, templatePath string, uuid string, index int32, key int32, controlKey int32) *types.VirtualDisk { + device := types.VirtualDisk{} + + var backFile *types.VirtualDiskFlatVer2BackingInfo + if len(templatePath) > 0 { + backFile = &types.VirtualDiskFlatVer2BackingInfo{} + backFile.FileName = templatePath + } + + diskFile := types.VirtualDiskFlatVer2BackingInfo{} + diskFile.DiskMode = "persistent" + thinProvisioned := true + diskFile.ThinProvisioned = &thinProvisioned + diskFile.Uuid = uuid + if backFile != nil { + diskFile.Parent = backFile + } + + device.Backing = &diskFile + + if sizeMb > 0 { + device.CapacityInKB = sizeMb * 1024 + } + + device.ControllerKey = controlKey + device.Key = key + index + device.UnitNumber = &index + + return &device +} + +func addDevSpec(device types.BaseVirtualDevice) *types.VirtualDeviceConfigSpec { + spec := types.VirtualDeviceConfigSpec{} + spec.Operation = types.VirtualDeviceConfigSpecOperationAdd + spec.Device = device + return &spec +} diff --git a/pkg/util/esxi/fakeregion.go b/pkg/util/esxi/fakeregion.go new file mode 100644 index 0000000000..da0fe948cd --- /dev/null +++ b/pkg/util/esxi/fakeregion.go @@ -0,0 +1,69 @@ +package esxi + +import ( + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" +) + +func (cli *SESXiClient) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (cli *SESXiClient) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (cli *SESXiClient) GetIHosts() ([]cloudprovider.ICloudHost, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, err + } + + ihosts := make([]cloudprovider.ICloudHost, 0) + for i := 0; i < len(dcs); i += 1 { + dcIHosts, err := dcs[i].GetIHosts() + if err != nil { + return nil, err + } + ihosts = append(ihosts, dcIHosts...) + } + return ihosts, nil +} + +func (cli *SESXiClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + return cli.FindHostByIp(id) +} + +func (cli *SESXiClient) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, err + } + + iStorages := make([]cloudprovider.ICloudStorage, 0) + for i := 0; i < len(dcs); i += 1 { + dcIStorages, err := dcs[i].GetIStorages() + if err != nil { + return nil, err + } + iStorages = append(iStorages, dcIStorages...) + } + return iStorages, nil +} + +func (cli *SESXiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + iStorages, err := cli.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(iStorages); i += 1 { + if iStorages[i].GetGlobalId() == id { + return iStorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (cli *SESXiClient) GetProvider() string { + return models.CLOUD_PROVIDER_VMWARE +} diff --git a/pkg/util/esxi/guestos.go b/pkg/util/esxi/guestos.go new file mode 100644 index 0000000000..a5c77f185b --- /dev/null +++ b/pkg/util/esxi/guestos.go @@ -0,0 +1,211 @@ +package esxi + +type TOSType string + +type TOSArch string + +const ( + LINUX = TOSType("Linux") + WINDOWS = TOSType("Windows") + MACOS = TOSType("macOS") + FREEBSD = TOSType("FreeBSD") + SOLARIS = TOSType("Solaris") + VMWARE = TOSType("VMware") + + X86 = TOSArch("x86") + X86_64 = TOSArch("x86_64") +) + +type SOsInfo struct { + OsType TOSType + OsDistribution string + OsVersion string + OsArch TOSArch +} + +func asian(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Asianux Server", ver, arch} +} + +func centos(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "CentOS", "4/5", arch} +} + +func macos(ver string, arch TOSArch) SOsInfo { + return SOsInfo{MACOS, "Mac OS", ver, arch} +} + +func debian(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Debian", ver, arch} + +} + +func fedora(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Fedora", ver, arch} +} + +func freebsd(arch TOSArch) SOsInfo { + return SOsInfo{FREEBSD, "FreeBSD", "", arch} +} + +func rhel(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "RedHat Enterprise Linux", ver, arch} + +} + +func suse(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "SuSE", ver, arch} +} + +func opensuse(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "OpenSuSE", "?", arch} + +} + +func oracle(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Oracle", ver, arch} +} + +func linux(ver string, arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Generic", ver, arch} +} + +func windows(dist string, arch TOSArch) SOsInfo { + return SOsInfo{WINDOWS, dist, "", arch} +} + +func solaris(ver string, arch TOSArch) SOsInfo { + return SOsInfo{SOLARIS, "Solaris", ver, arch} +} + +func turbo(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Turbo Linux", "?", arch} +} + +func ubuntu(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Ubuntu", "?", arch} +} + +func mandriva(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Mandriva", "?", arch} +} + +func mandrake(arch TOSArch) SOsInfo { + return SOsInfo{LINUX, "Mandrake", "?", arch} +} + +func vmware(ver string) SOsInfo { + return SOsInfo{VMWARE, "ESX", ver, X86_64} +} + +var ( + GuestOsInfo = map[string]SOsInfo{ + "asianux3_64Guest": asian("3", X86_64), + "asianux3Guest": asian("3", X86), + "asianux4_64Guest": asian("4", X86_64), + "asianux4Guest": asian("4", X86), + "centos64Guest": centos(X86_64), + "centosGuest": centos(X86), + "darwin10_64Guest": macos("10.6", X86_64), + "darwin10Guest": macos("10.6", X86), + "darwin11_64Guest": macos("10.7", X86_64), + "darwin11Guest": macos("10.7", X86), + "darwin12_64Guest": macos("10.8", X86_64), + "darwin13_64Guest": macos("10.9", X86_64), + "darwin64Guest": macos("10.5", X86_64), + "darwinGuest": macos("10.5", X86), + "debian4_64Guest": debian("4", X86_64), + "debian4Guest": debian("4", X86), + "debian5_64Guest": debian("5", X86_64), + "debian5Guest": debian("5", X86), + "debian6_64Guest": debian("6", X86_64), + "debian6Guest": debian("6", X86), + "debian7_64Guest": debian("7", X86_64), + "debian7Guest": debian("7", X86), + "fedora64Guest": fedora("?", X86_64), + "fedoraGuest": fedora("?", X86), + "freebsd64Guest": freebsd(X86_64), + "freebsdGuest": freebsd(X86), + "genericLinuxGuest": linux("?", X86), + "mandrakeGuest": mandrake(X86), + "mandriva64Guest": mandriva(X86_64), + "mandrivaGuest": mandriva(X86), + "opensuse64Guest": opensuse(X86_64), + "opensuseGuest": opensuse(X86), + "oracleLinux64Guest": oracle("4/5", X86_64), + "oracleLinuxGuest": oracle("4/5", X86), + "other24xLinux64Guest": linux("2.4", X86_64), + "other24xLinuxGuest": linux("2.4", X86), + "other26xLinux64Guest": linux("2.6", X86_64), + "other26xLinuxGuest": linux("2.6", X86), + "other3xLinux64Guest": linux("3.x", X86_64), + "other3xLinuxGuest": linux("3.x", X86_64), + "otherLinux64Guest": linux("2.2", X86_64), + "otherLinuxGuest": linux("2.2", X86), + "redhatGuest": rhel("2.1", X86), + "rhel2Guest": rhel("2", X86), + "rhel3_64Guest": rhel("3", X86_64), + "rhel3Guest": rhel("3", X86), + "rhel4_64Guest": rhel("4", X86_64), + "rhel4Guest": rhel("4", X86), + "rhel5_64Guest": rhel("5", X86_64), + "rhel5Guest": rhel("5", X86), + "rhel6_64Guest": rhel("6", X86_64), + "rhel6Guest": rhel("6", X86), + "rhel7_64Guest": rhel("7", X86_64), + "rhel7Guest": rhel("7", X86), + "sles10_64Guest": suse("10", X86_64), + "sles10Guest": suse("10", X86), + "sles11_64Guest": suse("11", X86_64), + "sles11Guest": suse("11", X86), + "sles12_64Guest": suse("12", X86_64), + "sles12Guest": suse("12", X86), + "sles64Guest": suse("9", X86_64), + "slesGuest": suse("9", X86), + "solaris10_64Guest": solaris("10", X86_64), + "solaris10Guest": solaris("10", X86), + "solaris11_64Guest": solaris("11", X86_64), + "solaris6Guest": solaris("6", X86), + "solaris7Guest": solaris("7", X86), + "solaris8Guest": solaris("8", X86), + "solaris9Guest": solaris("9", X86), + "suse64Guest": suse("?", X86_64), + "suseGuest": suse("?", X86), + "turboLinux64Guest": turbo(X86_64), + "turboLinuxGuest": turbo(X86), + "ubuntu64Guest": ubuntu(X86_64), + "ubuntuGuest": ubuntu(X86), + "vmkernel5Guest": vmware("5"), + "vmkernelGuest": vmware("4"), + "win2000AdvServGuest": windows("Windows 2000 Advanced Server", X86), + "win2000ProGuest": windows("Windows 2000 Professional", X86), + "win2000ServGuest": windows("Windows 2000 Server", X86), + "win31Guest": windows("Windows 3.1", X86), + "win95Guest": windows("Windows 95", X86), + "win98Guest": windows("Windows 98", X86), + "windows7_64Guest": windows("Windows 7", X86_64), + "windows7Guest": windows("Windows 7", X86_64), + "windows7Server64Guest": windows("Windows Server 2008 R2", X86_64), + "windows8_64Guest": windows("Windows 8", X86_64), + "windows8Guest": windows("Windows 8", X86), + "windows8Server64Guest": windows("Windows 8 Server", X86_64), + "windowsHyperVGuest": windows("Windows Hyper-V", X86_64), + "winLonghorn64Guest": windows("Windows Longhorn", X86_64), + "winLonghornGuest": windows("Windows Longhorn", X86), + "winMeGuest": windows("Windows Millenium Edition", X86), + "winNetBusinessGuest": windows("Windows Small Business Server 2003", X86), + "winNetDatacenter64Guest": windows("Windows Server 2003 Datacenter Edition", X86_64), + "winNetDatacenterGuest": windows("Windows Server 2003 Datacenter Edition", X86), + "winNetEnterprise64Guest": windows("Windows Server 2003 Enterprise Edition", X86_64), + "winNetEnterpriseGuest": windows("Windows Server 2003 Enterprise Edition", X86), + "winNetStandard64Guest": windows("Windows Server 2003 Standard Edition", X86_64), + "winNetStandardGuest": windows("Windows Server 2003 Standard Edition", X86), + "winNetWebGuest": windows("Windows Server 2003 Web Edition", X86), + "winNTGuest": windows("Windows NT 4", X86), + "winVista64Guest": windows("Windows Vista", X86_64), + "winVistaGuest": windows("Windows Vista", X86), + "winXPHomeGuest": windows("Windows XP Home Edition", X86), + "winXPPro64Guest": windows("Windows XP Professional Edition", X86_64), + "winXPProGuest": windows("Windows XP Professional", X86), + } +) diff --git a/pkg/util/esxi/host.go b/pkg/util/esxi/host.go index fc4581fb9e..b387b8306e 100644 --- a/pkg/util/esxi/host.go +++ b/pkg/util/esxi/host.go @@ -1,17 +1,19 @@ package esxi import ( + "context" + "fmt" + "strings" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" "yunion.io/x/jsonutils" - - "fmt" - "github.com/vmware/govmomi/vim25/types" - "strings" "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/pkg/util/netutils" ) var HOST_SYSTEM_PROPS = []string{"name", "parent", "summary", "config", "hardware", "vm", "datastore"} @@ -65,6 +67,8 @@ type SHost struct { datastores []cloudprovider.ICloudStorage + storageCache *SDatastoreImageCache + vms []cloudprovider.ICloudVM } @@ -102,7 +106,15 @@ func (self *SHost) GetStatus() string { } func (self *SHost) Refresh() error { - self.vms = nil + base := self.SManagedObject + var moObj mo.HostSystem + err := self.manager.reference2Object(self.object.Reference(), HOST_SYSTEM_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SHost{} + self.SManagedObject = base return nil } @@ -114,21 +126,23 @@ func (self *SHost) fetchVMs() error { if self.vms != nil { return nil } - var vms []mo.VirtualMachine - err := self.manager.references2Objects(self.getHostSystem().Vm, VIRTUAL_MACHINE_PROPS, &vms) - if err != nil { - return err - } dc, err := self.GetDatacenter() if err != nil { return err } - self.vms = make([]cloudprovider.ICloudVM, len(vms)) - for i := 0; i < len(vms); i += 1 { - self.vms[i] = NewVirtualMachine(self.manager, &vms[i], dc, self) + hostVms := self.getHostSystem().Vm + if len(hostVms) == 0 { + // log.Errorf("host VMs are nil!!!!!") + return nil } + + vms, err := dc.fetchVms(hostVms) + if err != nil { + return err + } + self.vms = vms return nil } @@ -497,3 +511,54 @@ func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error } return inics, nil } + +func (host *SHost) getLocalStorageCache() (*SDatastoreImageCache, error) { + if host.storageCache == nil { + sc, err := host.newLocalStorageCache() + if err != nil { + return nil, err + } + host.storageCache = sc + } + return host.storageCache, nil +} + +func (host *SHost) newLocalStorageCache() (*SDatastoreImageCache, error) { + ctx := context.Background() + + istorages, err := host.GetIStorages() + if err != nil { + return nil, err + } + var cacheDs *SDatastore + var maxDs *SDatastore + var maxCapacity int + for i := 0; i < len(istorages); i += 1 { + ds := istorages[i].(*SDatastore) + if !ds.isLocalVMFS() { + continue + } + _, err := ds.CheckFile(ctx, IMAGE_CACHE_DIR_NAME) + if err != nil { + if err != cloudprovider.ErrNotFound { + return nil, err + } + if maxCapacity < ds.GetCapacityMB() { + maxCapacity = ds.GetCapacityMB() + maxDs = ds + } + } else { + cacheDs = ds + break + } + } + if cacheDs == nil { + // if no existing image cache dir found, use the one with maximal capacilty + cacheDs = maxDs + } + + return &SDatastoreImageCache{ + datastore: cacheDs, + host: host, + }, nil +} diff --git a/pkg/util/esxi/image.go b/pkg/util/esxi/image.go new file mode 100644 index 0000000000..378c2d2c5b --- /dev/null +++ b/pkg/util/esxi/image.go @@ -0,0 +1,71 @@ +package esxi + +import ( + "context" + "path" + + "github.com/vmware/govmomi/object" + + "strings" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SImage struct { + cache *SDatastoreImageCache + filename string +} + +func (self *SImage) getDatacenter() *object.Datacenter { + return self.cache.datastore.datacenter.getDcObj() +} + +func (self *SImage) getFullFilename() string { + return self.cache.datastore.getPathString(self.filename) +} + +func (self *SImage) GetId() string { + idstr := path.Base(self.filename) + if strings.HasSuffix(idstr, ".vmdk") { + idstr = idstr[:len(idstr)-5] + } + return strings.ToLower(idstr) +} + +func (self *SImage) GetName() string { + return path.Base(self.filename) +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetStatus() string { + dm := object.NewVirtualDiskManager(self.cache.datastore.manager.client.Client) + ctx := context.Background() + _, err := dm.QueryVirtualDiskInfo(ctx, self.getFullFilename(), self.getDatacenter(), true) + if err != nil { + return "saving" + } + return "active" +} + +func (self *SImage) Refresh() error { + return nil +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.cache.datastore.DeleteVmdk(ctx, self.filename) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} diff --git a/pkg/util/esxi/manager.go b/pkg/util/esxi/manager.go index 9b1f83da1b..e3ef4f4252 100644 --- a/pkg/util/esxi/manager.go +++ b/pkg/util/esxi/manager.go @@ -27,6 +27,8 @@ const ( ) type SESXiClient struct { + cloudprovider.SFakeOnPremiseRegion + providerId string providerName string host string @@ -180,6 +182,7 @@ func (cli *SESXiClient) references2Objects(refs []types.ManagedObjectReference, pc := property.DefaultCollector(cli.client.Client) err := pc.Retrieve(cli.context, refs, props, dst) if err != nil { + log.Errorf("pc.Retrieve fail %s", err) return err } return nil @@ -187,7 +190,12 @@ func (cli *SESXiClient) references2Objects(refs []types.ManagedObjectReference, func (cli *SESXiClient) reference2Object(ref types.ManagedObjectReference, props []string, dst interface{}) error { pc := property.DefaultCollector(cli.client.Client) - return pc.RetrieveOne(cli.context, ref, props, dst) + err := pc.RetrieveOne(cli.context, ref, props, dst) + if err != nil { + log.Errorf("pc.RetrieveOne fail %s", err) + return err + } + return nil } func (cli *SESXiClient) GetDatacenters() ([]*SDatacenter, error) { diff --git a/pkg/util/esxi/provider/provider.go b/pkg/util/esxi/provider/provider.go index de481a0188..f294f864f5 100644 --- a/pkg/util/esxi/provider/provider.go +++ b/pkg/util/esxi/provider/provider.go @@ -13,7 +13,6 @@ import ( ) type SESXiProviderFactory struct { - providerTable map[string]*SESXiProvider } func (self *SESXiProviderFactory) GetId() string { @@ -39,10 +38,6 @@ func parseHostPort(host string, defPort int) (string, int, error) { } func (self *SESXiProviderFactory) GetProvider(providerId, providerName, urlStr, account, secret string) (cloudprovider.ICloudProvider, error) { - provider, ok := self.providerTable[providerId] - if ok { - return provider, nil - } parts, err := url.Parse(urlStr) if err != nil { return nil, err @@ -56,14 +51,11 @@ func (self *SESXiProviderFactory) GetProvider(providerId, providerName, urlStr, if err != nil { return nil, err } - self.providerTable[providerId] = &SESXiProvider{client: client} - return self.providerTable[providerId], nil + return &SESXiProvider{client: client}, nil } func init() { - factory := SESXiProviderFactory{ - providerTable: make(map[string]*SESXiProvider), - } + factory := SESXiProviderFactory{} cloudprovider.RegisterFactory(&factory) } @@ -103,44 +95,10 @@ func (self *SESXiProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion return nil, cloudprovider.ErrNotSupported } -func (self *SESXiProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.client.FindHostByIp(id) - if err != nil { - return nil, err - } else { - return host, nil - } -} - -func (self *SESXiProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SESXiProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SESXiProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - return nil, cloudprovider.ErrNotSupported -} - func (self *SESXiProvider) GetBalance() (float64, error) { return 0.0, nil } -func (self *SESXiProvider) GetOnPremiseIHosts() ([]cloudprovider.ICloudHost, error) { - dcs, err := self.client.GetDatacenters() - if err != nil { - return nil, err - } - - ihosts := make([]cloudprovider.ICloudHost, 0) - for i := 0; i < len(dcs); i += 1 { - dcIHosts, err := dcs[i].GetIHosts() - if err != nil { - return nil, err - } - ihosts = append(ihosts, dcIHosts...) - } - return ihosts, nil +func (self *SESXiProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { + return self.client, nil } diff --git a/pkg/util/esxi/shell/store.go b/pkg/util/esxi/shell/store.go index ec5efa21e2..068931368c 100644 --- a/pkg/util/esxi/shell/store.go +++ b/pkg/util/esxi/shell/store.go @@ -2,12 +2,25 @@ package shell import ( "context" + "fmt" "os" "yunion.io/x/onecloud/pkg/util/esxi" "yunion.io/x/onecloud/pkg/util/printutils" "yunion.io/x/onecloud/pkg/util/shellutils" ) +func getDatastore(cli *esxi.SESXiClient, dcId string, dsId string) (*esxi.SDatastore, error) { + dc, err := cli.FindDatacenterByMoId(dcId) + if err != nil { + return nil, err + } + ds, err := dc.GetIStorageByMoId(dsId) + if err != nil { + return nil, err + } + return ds.(*esxi.SDatastore), nil +} + func init() { type DatastoreListOptions struct { DATACENTER string `help:"List datastores in datacenter"` @@ -30,11 +43,7 @@ func init() { DSID string `help:"Datastore ID""` } shellutils.R(&DatastoreShowOptions{}, "ds-show", "Show details of a datastore", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) + ds, err := getDatastore(cli, args.DATACENTER, args.DSID) if err != nil { return err } @@ -42,22 +51,41 @@ func init() { return nil }) + shellutils.R(&DatastoreShowOptions{}, "ds-cache-show", "Show details of a datastore image cache", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { + ds, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + cache := ds.GetIStoragecache() + printObject(cache) + return nil + }) + + shellutils.R(&DatastoreShowOptions{}, "ds-cache-list", "Show image list of a datastore image cache", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { + ds, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + cache := ds.GetIStoragecache() + images, err := cache.GetIImages() + if err != nil { + return err + } + printList(images, []string{}) + return nil + }) + type DatastoreListDirOptions struct { DATACENTER string `help:"Datacenter"` DSID string `help:"Datastore ID""` DIR string `help:"directory"` } shellutils.R(&DatastoreListDirOptions{}, "ds-list-dir", "List directory of a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) if err != nil { return err } ctx := context.Background() - dsObj := ds.(*esxi.SDatastore) fileList, err := dsObj.ListDir(ctx, args.DIR) if err != nil { return err @@ -67,16 +95,11 @@ func init() { }) shellutils.R(&DatastoreListDirOptions{}, "ds-check-file", "Check file status in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) if err != nil { return err } ctx := context.Background() - dsObj := ds.(*esxi.SDatastore) file, err := dsObj.CheckFile(ctx, args.DIR) if err != nil { return err @@ -86,20 +109,72 @@ func init() { }) shellutils.R(&DatastoreListDirOptions{}, "ds-delete-file", "Delete file in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) if err != nil { return err } ctx := context.Background() - dsObj := ds.(*esxi.SDatastore) err = dsObj.Delete(ctx, args.DIR) if err != nil { return err } + fmt.Println("success") + return nil + }) + + shellutils.R(&DatastoreListDirOptions{}, "ds-check-vmdk", "Check vmdk file status in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + ctx := context.Background() + err = dsObj.CheckVmdk(ctx, args.DIR) + if err != nil { + return err + } + fmt.Println("valid") + return nil + }) + + shellutils.R(&DatastoreListDirOptions{}, "ds-delete-vmdk", "Delete vmdk file from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + ctx := context.Background() + err = dsObj.DeleteVmdk(ctx, args.DIR) + if err != nil { + return err + } + fmt.Println("success") + return nil + }) + + shellutils.R(&DatastoreListDirOptions{}, "ds-mkdir", "Delete vmdk directory from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + ctx := context.Background() + path, err := dsObj.MakeDir(ctx, args.DIR) + if err != nil { + return err + } + fmt.Println("Make dir success", path) + return nil + }) + + shellutils.R(&DatastoreListDirOptions{}, "ds-rmdir", "Remove vmdk directory from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { + dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) + if err != nil { + return err + } + ctx := context.Background() + err = dsObj.RemoveDir(ctx, args.DIR) + if err != nil { + return err + } + fmt.Println("Remove dir success") return nil }) diff --git a/pkg/util/esxi/shell/virtualmachine.go b/pkg/util/esxi/shell/virtualmachine.go index 4d1ace464b..0313cad264 100644 --- a/pkg/util/esxi/shell/virtualmachine.go +++ b/pkg/util/esxi/shell/virtualmachine.go @@ -1,6 +1,8 @@ package shell import ( + "context" + "fmt" "yunion.io/x/onecloud/pkg/util/esxi" "yunion.io/x/onecloud/pkg/util/printutils" "yunion.io/x/onecloud/pkg/util/shellutils" @@ -74,6 +76,33 @@ func init() { return nil }) + type VirtualMachineDiskResizeOptions struct { + HOSTIP string `help:"host ip"` + VMID string `help:"virtual machine UUID"` + DISKIDX int `help:"disk index"` + SIZEGB int64 `help:"new size of disk"` + } + shellutils.R(&VirtualMachineDiskResizeOptions{}, "vm-disk-resize", "Resize a vm disk", func(cli *esxi.SESXiClient, args *VirtualMachineDiskResizeOptions) error { + host, err := cli.FindHostByIp(args.HOSTIP) + if err != nil { + return err + } + vm, err := host.GetIVMById(args.VMID) + if err != nil { + return err + } + vmdisks, err := vm.GetIDisks() + if err != nil { + return err + } + if args.DISKIDX < 0 || args.DISKIDX >= len(vmdisks) { + return fmt.Errorf("Out of index: %d", args.DISKIDX) + } + disk := vmdisks[args.DISKIDX] + ctx := context.Background() + return disk.Resize(ctx, args.SIZEGB*1024) + }) + shellutils.R(&VirtualMachineShowOptions{}, "vm-vnc", "Show vm VNC details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { host, err := cli.FindHostByIp(args.HOSTIP) if err != nil { diff --git a/pkg/util/esxi/storage.go b/pkg/util/esxi/storage.go index 0b0b2576d2..34c786b937 100644 --- a/pkg/util/esxi/storage.go +++ b/pkg/util/esxi/storage.go @@ -5,6 +5,7 @@ import ( "context" "fmt" + "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/vim25/types" "io" "io/ioutil" @@ -22,12 +23,16 @@ import ( "yunion.io/x/onecloud/pkg/util/vmdkutils" ) -var DATASTORE_PROPS = []string{"name", "parent", "info", "summary", "host"} +var DATASTORE_PROPS = []string{"name", "parent", "info", "summary", "host", "vm"} type SDatastore struct { SManagedObject + // vms []cloudprovider.ICloudVM + ihosts []cloudprovider.ICloudHost + + storageCache *SDatastoreImageCache } func NewDatastore(manager *SESXiClient, ds *mo.Datastore, dc *SDatacenter) *SDatastore { @@ -76,7 +81,16 @@ func (self *SDatastore) GetStatus() string { } func (self *SDatastore) Refresh() error { - return cloudprovider.ErrNotImplemented + base := self.SManagedObject + var moObj mo.Datastore + err := self.manager.reference2Object(self.object.Reference(), DATASTORE_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SDatastore{} + self.SManagedObject = base + return nil } func (self *SDatastore) IsEmulated() bool { @@ -179,19 +193,80 @@ func (self *SDatastore) getLocalHost() (cloudprovider.ICloudHost, error) { } func (self *SDatastore) GetIStoragecache() cloudprovider.ICloudStoragecache { - return nil + if self.isLocalVMFS() { + ihost, err := self.getLocalHost() + if err != nil { + log.Errorf("GetIStoragecache getLocalHost fail %s", err) + return nil + } + host := ihost.(*SHost) + sc, err := host.getLocalStorageCache() + if err != nil { + log.Errorf("GetIStoragecache getLocalStorageCache fail %s", err) + return nil + } + return sc + } else { + return self.getStorageCache() + } +} + +func (self *SDatastore) getStorageCache() *SDatastoreImageCache { + if self.storageCache == nil { + self.storageCache = &SDatastoreImageCache{ + datastore: self, + } + } + return self.storageCache } func (self *SDatastore) GetIZone() cloudprovider.ICloudZone { return nil } -func (self *SDatastore) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented +func (self *SDatastore) getVMs() ([]cloudprovider.ICloudVM, error) { + dc, err := self.GetDatacenter() + if err != nil { + log.Errorf("SDatastore GetDatacenter fail %s", err) + return nil, err + } + vms := self.getDatastore().Vm + if len(vms) == 0 { + return nil, nil + } + return dc.fetchVms(vms) +} + +func (self *SDatastore) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + vms, err := self.getVMs() + if err != nil { + log.Errorf("self.getVMs fail %s", err) + return nil, err + } + for i := 0; i < len(vms); i += 1 { + vm := vms[i].(*SVirtualMachine) + disk, err := vm.GetIDiskById(idStr) + if err == nil { + return disk, nil + } + } + return nil, cloudprovider.ErrNotFound } func (self *SDatastore) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented + vms, err := self.getVMs() + if err != nil { + return nil, err + } + allDisks := make([]cloudprovider.ICloudDisk, 0) + for i := 0; i < len(vms); i += 1 { + disks, err := vms[i].GetIDisks() + if err != nil { + return nil, err + } + allDisks = append(allDisks, disks...) + } + return allDisks, nil } func (self *SDatastore) isLocalVMFS() bool { @@ -259,6 +334,10 @@ func (self *SDatastore) GetUrl() string { return self.getDatastore().Info.GetDatastoreInfo().Url } +func (self *SDatastore) GetMountPoint() string { + return self.GetUrl() +} + func (self *SDatastore) cleanPath(remotePath string) string { dsName := fmt.Sprintf("[%s]", self.SManagedObject.GetName()) dsUrl := self.GetUrl() @@ -298,6 +377,11 @@ func (self *SDatastore) getPathString(path string) string { return fmt.Sprintf("[%s] %s", self.SManagedObject.GetName(), path) } +func (self *SDatastore) getFullPath(remotePath string) string { + remotePath = self.cleanPath(remotePath) + return path.Join(self.GetUrl(), remotePath) +} + func (self *SDatastore) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) { return nil, cloudprovider.ErrNotImplemented } @@ -396,6 +480,9 @@ func (self *SDatastore) CheckFile(ctx context.Context, remotePath string) (*SDat err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { if resp.StatusCode >= 400 { + if resp.StatusCode == 404 { + return cloudprovider.ErrNotFound + } return fmt.Errorf("%s", resp.Status) } sizeStr := resp.Header.Get("Content-Length") @@ -502,6 +589,13 @@ func (self *SDatastore) Delete(ctx context.Context, remotePath string) error { } func (self *SDatastore) DeleteVmdk(ctx context.Context, remotePath string) error { + info, err := self.CheckFile(ctx, remotePath) + if err != nil { + return err + } + if info.Size > 4096 { + return fmt.Errorf("not a valid vmdk file") + } vmdkContent, err := self.FileGetContent(ctx, remotePath) if err != nil { return err @@ -515,10 +609,59 @@ func (self *SDatastore) DeleteVmdk(ctx context.Context, remotePath string) error return err } if len(vmdkInfo.ExtentFile) > 0 { - err = self.Delete(ctx, path.Join(remotePath, vmdkInfo.ExtentFile)) + err = self.Delete(ctx, path.Join(path.Dir(remotePath), vmdkInfo.ExtentFile)) if err != nil { return err } } return nil } + +func (self *SDatastore) CheckVmdk(ctx context.Context, remotePath string) error { + dm := object.NewVirtualDiskManager(self.manager.client.Client) + defer dm.Destroy(ctx) + + dc, err := self.GetDatacenter() + if err != nil { + return err + } + + dcObj := dc.getObjectDatacenter() + + infoList, err := dm.QueryVirtualDiskInfo(ctx, self.getPathString(remotePath), dcObj, true) + if err != nil { + return err + } + + log.Debugf("%#v", infoList) + return nil +} + +func (self *SDatastore) getDatastoreObj() *object.Datastore { + return object.NewDatastore(self.manager.client.Client, self.getDatastore().Self) +} + +func (self *SDatastore) MakeDir(ctx context.Context, remotePath string) (string, error) { + dnm := object.NewDatastoreNamespaceManager(self.manager.client.Client) + + remotePath = self.cleanPath(remotePath) + + objDS := self.getDatastoreObj() + + return dnm.CreateDirectory(ctx, objDS, remotePath, "") +} + +func (self *SDatastore) RemoveDir(ctx context.Context, remotePath string) error { + dnm := object.NewDatastoreNamespaceManager(self.manager.client.Client) + + remotePath = self.getFullPath(remotePath) + + dc, err := self.GetDatacenter() + if err != nil { + return err + } + + dcObj := dc.getObjectDatacenter() + + return dnm.DeleteDirectory(ctx, dcObj, remotePath) +} diff --git a/pkg/util/esxi/storagecache.go b/pkg/util/esxi/storagecache.go new file mode 100644 index 0000000000..a2268b27a9 --- /dev/null +++ b/pkg/util/esxi/storagecache.go @@ -0,0 +1,132 @@ +package esxi + +import ( + "context" + "fmt" + "path" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" +) + +const ( + IMAGE_CACHE_DIR_NAME = "image_cache" +) + +type SDatastoreImageCache struct { + datastore *SDatastore + host *SHost +} + +func (self *SDatastoreImageCache) GetId() string { + if self.host != nil { + return self.host.GetGlobalId() + } else { + return self.datastore.GetGlobalId() + } +} + +func (self *SDatastoreImageCache) GetName() string { + if self.host != nil { + return fmt.Sprintf("storage-cache-%s", self.host.GetName()) + } else { + return fmt.Sprintf("storage-cache-%s", self.datastore.GetName()) + } +} + +func (self *SDatastoreImageCache) GetGlobalId() string { + return self.GetId() +} + +func (self *SDatastoreImageCache) GetStatus() string { + return "available" +} + +func (self *SDatastoreImageCache) Refresh() error { + return nil +} + +func (self *SDatastoreImageCache) IsEmulated() bool { + return false +} + +func (self *SDatastoreImageCache) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SDatastoreImageCache) GetPath() string { + return path.Join(self.datastore.GetMountPoint(), IMAGE_CACHE_DIR_NAME) +} + +func (self *SDatastoreImageCache) GetIImages() ([]cloudprovider.ICloudImage, error) { + ctx := context.Background() + + files, err := self.datastore.ListDir(ctx, IMAGE_CACHE_DIR_NAME) + if err != nil { + log.Errorf("GetIImages ListDir fail %s", err) + return nil, err + } + + ret := make([]cloudprovider.ICloudImage, 0) + + validFilenames := make(map[string]bool) + + for i := 0; i < len(files); i += 1 { + filename := path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name) + if err := self.datastore.CheckVmdk(ctx, filename); err != nil { + continue + } + image := SImage{ + cache: self, + filename: filename, + } + ret = append(ret, &image) + vmdkName := files[i].Name + vmdkExtName := fmt.Sprintf("%s-flat.vmdk", vmdkName[:len(vmdkName)-5]) + validFilenames[vmdkName] = true + validFilenames[vmdkExtName] = true + } + + log.Debugf("storage cache contains %#v", validFilenames) + // cleanup storage cache!!! + for i := 0; i < len(files); i += 1 { + if _, ok := validFilenames[files[i].Name]; !ok { + log.Debugf("delete invalid vmdk file %s!!!", files[i].Name) + self.datastore.Delete(ctx, path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name)) + } + } + + return ret, nil +} + +func (self *SDatastoreImageCache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + images, err := self.GetIImages() + if err != nil { + return nil, err + } + for i := 0; i < len(images); i += 1 { + if images[i].GetGlobalId() == extId { + return images[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SDatastoreImageCache) GetManagerId() string { + return self.datastore.manager.providerId +} + +func (self *SDatastoreImageCache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastoreImageCache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastoreImageCache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) { + return "", cloudprovider.ErrNotImplemented +} diff --git a/pkg/util/esxi/utils_test.go b/pkg/util/esxi/utils_test.go new file mode 100644 index 0000000000..93d0c83405 --- /dev/null +++ b/pkg/util/esxi/utils_test.go @@ -0,0 +1,31 @@ +package esxi + +import "testing" + +func TestInitValue(t *testing.T) { + type testStruct struct { + member1 int + member2 string + Member3 int + Member4 string + } + + dst := testStruct{} + + dst.member1 = 1 + dst.member2 = "2" + dst.Member3 = 3 + dst.Member4 = "4" + + pDst := &dst + t.Logf("%p %#v", pDst, pDst) + + *pDst = testStruct{} + + t.Logf("%p %#v", pDst, pDst) + + new := testStruct{} + if dst != new { + t.Errorf("dst != new") + } +} diff --git a/pkg/util/esxi/vdisk.go b/pkg/util/esxi/vdisk.go index 8334b7d22b..0d0c63b97b 100644 --- a/pkg/util/esxi/vdisk.go +++ b/pkg/util/esxi/vdisk.go @@ -1,17 +1,17 @@ package esxi import ( + "context" "fmt" "path" + "strings" + "time" "github.com/vmware/govmomi/vim25/types" "yunion.io/x/jsonutils" "yunion.io/x/log" - "context" - "strings" - "time" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -90,8 +90,14 @@ func (disk *SVirtualDisk) GetDiskSizeMB() int { return int(capa / 1024 / 1024) } -func (disk *SVirtualDisk) getFilename() string { - return disk.getBackingInfo().FileName +func (disk *SVirtualDisk) GetAccessPath() string { + istore, err := disk.GetIStorage() + if err != nil { + log.Errorf("disk.GetIStorage fail %s", err) + return "" + } + ds := istore.(*SDatastore) + return ds.getFullPath(disk.getBackingInfo().FileName) } func (disk *SVirtualDisk) GetDiskFormat() string { @@ -127,7 +133,6 @@ func (disk *SVirtualDisk) GetTemplateId() string { func (disk *SVirtualDisk) GetDiskType() string { backing := disk.getBackingInfo() if backing.Parent != nil { - // log.Infof("%s", backing.Parent.FileName) return models.DISK_TYPE_SYS } return models.DISK_TYPE_DATA @@ -176,10 +181,11 @@ func (disk *SVirtualDisk) GetMountpoint() string { func (disk *SVirtualDisk) Delete(ctx context.Context) error { istorage, err := disk.GetIStorage() if err != nil { + log.Errorf("disk.GetIStorage() fail %s", err) return err } ds := istorage.(*SDatastore) - return ds.DeleteVmdk(ctx, disk.getFilename()) + return ds.DeleteVmdk(ctx, disk.getBackingInfo().FileName) } func (disk *SVirtualDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { @@ -194,8 +200,33 @@ func (disk *SVirtualDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error return nil, cloudprovider.ErrNotImplemented } -func (disk *SVirtualDisk) Resize(ctx context.Context, newSize int64) error { - return cloudprovider.ErrNotImplemented +func (disk *SVirtualDisk) Resize(ctx context.Context, newSizeMb int64) error { + ndisk := disk.getVirtualDisk() + ndisk.CapacityInKB = newSizeMb * 1024 + + devSpec := types.VirtualDeviceConfigSpec{} + devSpec.Device = ndisk + devSpec.Operation = types.VirtualDeviceConfigSpecOperationEdit + + spec := types.VirtualMachineConfigSpec{} + spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&devSpec} + + vm := disk.vm.getVmObj() + + task, err := vm.Reconfigure(ctx, spec) + + if err != nil { + log.Errorf("vm.Reconfigure fail %s", err) + return err + } + + err = task.Wait(ctx) + if err != nil { + log.Errorf("task.Wait fail %s", err) + return err + } + + return err } func (disk *SVirtualDisk) Reset(ctx context.Context, snapshotId string) error { diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index 2000bc0890..e25b4547d3 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -3,6 +3,7 @@ package esxi import ( "context" "fmt" + "reflect" "time" "github.com/vmware/govmomi/object" @@ -12,12 +13,13 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" - "reflect" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/pkg/util/netutils" - "yunion.io/yunioncloud/pkg/util/regutils" + "yunion.io/x/pkg/util/regutils" + + "strings" ) var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "runtime", "summary", "config", "guest"} @@ -32,12 +34,10 @@ type SVirtualMachine struct { devs map[int32]SVirtualDevice guestIps map[string]string - - host *SHost } -func NewVirtualMachine(manager *SESXiClient, vm *mo.VirtualMachine, dc *SDatacenter, host *SHost) *SVirtualMachine { - svm := &SVirtualMachine{SManagedObject: newManagedObject(manager, vm, dc), host: host} +func NewVirtualMachine(manager *SESXiClient, vm *mo.VirtualMachine, dc *SDatacenter) *SVirtualMachine { + svm := &SVirtualMachine{SManagedObject: newManagedObject(manager, vm, dc)} svm.fetchHardwareInfo() return svm } @@ -77,6 +77,16 @@ func (self *SVirtualMachine) GetStatus() string { } func (self *SVirtualMachine) Refresh() error { + base := self.SManagedObject + var moObj mo.VirtualMachine + err := self.manager.reference2Object(self.object.Reference(), VIRTUAL_MACHINE_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SVirtualMachine{} + self.SManagedObject = base + self.fetchHardwareInfo() return nil } @@ -119,16 +129,16 @@ func (self *SVirtualMachine) GetCreateTime() time.Time { } func (self *SVirtualMachine) GetIHost() cloudprovider.ICloudHost { - // moVM := self.getVirtualMachine() - // log.Debugf("%#v", moVM.Parent) - me := self.findInParents("HostSystem") - if me == nil { - log.Errorf("fail to find vm host??? %s", self.GetName()) - return self.host - } - ihost, err := self.manager.FindHostByMoId(me.Self.Value) + vm := self.getVmObj() + + hostsys, err := vm.HostSystem(self.manager.context) if err != nil { - log.Errorf("fail to find host %s for vm %s???", me.Self.Value, self.GetName()) + log.Errorf("fail to find host system for vm %s", err) + return nil + } + ihost, err := self.manager.FindHostByMoId(moRefId(hostsys.Reference())) + if err != nil { + log.Errorf("fail to find host %s for vm %s???", hostsys.Name(), self.GetName()) return nil } return ihost @@ -142,6 +152,15 @@ func (self *SVirtualMachine) GetIDisks() ([]cloudprovider.ICloudDisk, error) { return idisks, nil } +func (self *SVirtualMachine) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + for i := 0; i < len(self.vdisks); i += 1 { + if self.vdisks[i].GetGlobalId() == idStr { + return &self.vdisks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + func (self *SVirtualMachine) GetINics() ([]cloudprovider.ICloudNic, error) { inics := make([]cloudprovider.ICloudNic, len(self.vnics)) for i := 0; i < len(self.vnics); i += 1 { @@ -199,16 +218,32 @@ func (self *SVirtualMachine) GetGuestToolsStatus() string { return string(moVM.Guest.ToolsStatus) } +func (self *SVirtualMachine) isToolsOk() bool { + switch self.getVirtualMachine().Guest.ToolsStatus { + case types.VirtualMachineToolsStatusToolsNotInstalled: + return false + case types.VirtualMachineToolsStatusToolsNotRunning: + return false + } + return true +} + func (self *SVirtualMachine) GetGuestToolsRunningStatus() string { moVM := self.getVirtualMachine() return string(moVM.Guest.ToolsRunningStatus) } func (self *SVirtualMachine) GetOSType() string { + if osInfo, ok := GuestOsInfo[self.GetGuestId()]; ok { + return string(osInfo.OsType) + } return "" } func (self *SVirtualMachine) GetOSName() string { + if osInfo, ok := GuestOsInfo[self.GetGuestId()]; ok { + return string(osInfo.OsDistribution) + } return "" } @@ -236,12 +271,23 @@ func (self *SVirtualMachine) getVmObj() *object.VirtualMachine { return object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) } +// ideopotent start func (self *SVirtualMachine) StartVM(ctx context.Context) error { + if self.GetStatus() == models.VM_RUNNING { + return nil + } + return self.startVM(ctx) +} + +func (self *SVirtualMachine) startVM(ctx context.Context) error { err := self.makeNicsStartConnected(ctx) if err != nil { return err } - task, err := self.getVmObj().PowerOn(ctx) + + vm := self.getVmObj() + + task, err := vm.PowerOn(ctx) if err != nil { return err } @@ -254,7 +300,10 @@ func (self *SVirtualMachine) makeNicsStartConnected(ctx context.Context) error { for i := 0; i < len(self.vnics); i += 1 { spec.DeviceChange[i] = makeNicStartConnected(&self.vnics[i]) } - task, err := self.getVmObj().Reconfigure(ctx, spec) + + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, spec) if err != nil { return err } @@ -271,18 +320,44 @@ func makeNicStartConnected(nic *SVirtualNIC) *types.VirtualDeviceConfigSpec { } func (self *SVirtualMachine) StopVM(ctx context.Context, isForce bool) error { - task, err := self.getVmObj().PowerOff(ctx) + if self.GetStatus() == models.VM_READY { + return nil + } + if !isForce && self.isToolsOk() { + return self.shutdownVM(ctx) + } else { + return self.poweroffVM(ctx) + } +} + +func (self *SVirtualMachine) poweroffVM(ctx context.Context) error { + vm := self.getVmObj() + + task, err := vm.PowerOff(ctx) if err != nil { return err } return task.Wait(ctx) } -func (self *SVirtualMachine) doDelete(ctx context.Context) error { - task, err := self.getVmObj().Destroy(ctx) +func (self *SVirtualMachine) shutdownVM(ctx context.Context) error { + vm := self.getVmObj() + + err := vm.ShutdownGuest(ctx) if err != nil { return err } + return err +} + +func (self *SVirtualMachine) doDelete(ctx context.Context) error { + vm := self.getVmObj() + + task, err := vm.Destroy(ctx) + if err != nil { + log.Errorf("vm.Destroy(ctx) fail %s", err) + return err + } return task.Wait(ctx) } @@ -290,6 +365,7 @@ func (self *SVirtualMachine) DeleteVM(ctx context.Context) error { for i := 0; i < len(self.vdisks); i += 1 { err := self.doDetachAndDeleteDisk(ctx, &self.vdisks[i]) if err != nil { + log.Errorf("self.doDetachAndDeleteDisk(ctx, &self.vdisks[i]) fail %s", err) return err } } @@ -308,13 +384,17 @@ func (self *SVirtualMachine) doDetachDisk(ctx context.Context, vdisk *SVirtualDi spec := types.VirtualMachineConfigSpec{} spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&removeSpec} - task, err := self.getVmObj().Reconfigure(ctx, spec) + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, spec) if err != nil { + log.Errorf("vm.Reconfigure fail %s", err) return err } err = task.Wait(ctx) if err != nil { + log.Errorf("task.Wait(ctx) fail %s", err) return err } @@ -382,8 +462,48 @@ func (self *SVirtualMachine) acquireVmrcUrl() (jsonutils.JSONObject, error) { return ret, nil } -func (dc *SVirtualMachine) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { - return cloudprovider.ErrNotImplemented +func (self *SVirtualMachine) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { + return self.doChangeConfig(ctx, int32(ncpu), int64(vmem), "", "") +} + +func (self *SVirtualMachine) GetVersion() string { + return self.getVirtualMachine().Config.Version +} + +func (self *SVirtualMachine) doChangeConfig(ctx context.Context, ncpu int32, vmemMB int64, guestId string, version string) error { + changed := false + configSpec := types.VirtualMachineConfigSpec{} + if int8(ncpu) != self.GetVcpuCount() { + configSpec.NumCPUs = ncpu + changed = true + } + if int(vmemMB) != self.GetVmemSizeMB() { + configSpec.MemoryMB = vmemMB + changed = true + } + if len(guestId) > 0 && guestId != self.GetGuestId() { + configSpec.GuestId = guestId + changed = true + } + if len(version) > 0 && version != self.GetVersion() { + configSpec.Version = version + changed = true + } + if !changed { + return nil + } + + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, configSpec) + if err != nil { + return err + } + err = task.Wait(ctx) + if err != nil { + return err + } + return self.Refresh() } func (self *SVirtualMachine) GetBillingType() string { @@ -466,3 +586,100 @@ func (self *SVirtualMachine) GetIps() []string { func (self *SVirtualMachine) GetVGADevice() string { return fmt.Sprintf("%s", self.vga.String()) } + +var ( + driverTable = map[string][]string{ + "sata": {"ahci"}, + "scsi": {"lsilogic", "lsilogicsas", "buslogic"}, + "pvscsi": {"parascsi"}, + "ide": {"ide"}, + } +) + +func (self *SVirtualMachine) getDevsByDriver(driver string) []SVirtualDevice { + devs := make([]SVirtualDevice, 0) + for _, drv := range self.devs { + if strings.HasSuffix(drv.GetDriver(), fmt.Sprintf("%scontroller", driver)) { + devs = append(devs, drv) + } + } + return devs +} + +func minDevKey(devs []SVirtualDevice) int32 { + var minKey int32 = -1 + for i := 0; i < len(devs); i += 1 { + if minKey < 0 || minKey > devs[i].getKey() { + minKey = devs[i].getKey() + } + } + return minKey +} + +func minDiskKey(devs []SVirtualDisk) int32 { + var minKey int32 = -1 + for i := 0; i < len(devs); i += 1 { + if minKey < 0 || minKey > devs[i].getKey() { + minKey = devs[i].getKey() + } + } + return minKey +} + +func (self *SVirtualMachine) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + aliasDrivers, ok := driverTable[driver] + if !ok { + return fmt.Errorf("Unsupported disk driver %s", driver) + } + var devs []SVirtualDevice + for _, alias := range aliasDrivers { + devs = self.getDevsByDriver(alias) + if len(devs) > 0 { + break + } + } + if len(devs) == 0 { + return fmt.Errorf("Driver %s not found", driver) + } + ctlKey := minDevKey(devs) + sameDisks := make([]SVirtualDisk, 0) + for i := 0; i < len(self.vdisks); i += 1 { + if self.vdisks[i].GetDriver() == driver { + sameDisks = append(sameDisks, self.vdisks[i]) + } + } + var diskKey int32 = 2000 + if len(sameDisks) == 0 { + diskKey = minDiskKey(sameDisks) + } + index := len(sameDisks) + if driver == "ide" { + ctlKey += int32(index / 2) + } + devSpec := NewDiskDev(int64(sizeMb), "", uuid, int32(index), diskKey, ctlKey) + spec := addDevSpec(devSpec) + spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate + configSpec := types.VirtualMachineConfigSpec{} + configSpec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{spec} + + vmObj := self.getVmObj() + + task, err := vmObj.Reconfigure(ctx, configSpec) + if err != nil { + return err + } + err = task.Wait(ctx) + if err != nil { + return err + } + oldDiskCnt := len(self.vdisks) + maxTries := 60 + for tried := 0; tried < maxTries; tried += 1 { + time.Sleep(time.Second) + self.Refresh() + if len(self.vdisks) > oldDiskCnt { + return nil + } + } + return cloudprovider.ErrTimeout +} diff --git a/pkg/util/qcloud/disk.go b/pkg/util/qcloud/disk.go index 8705edcdfe..1f3636074f 100644 --- a/pkg/util/qcloud/disk.go +++ b/pkg/util/qcloud/disk.go @@ -176,8 +176,8 @@ func (self *SRegion) ResizeDisk(ctx context.Context, diskId string, sizeGb int64 } } -func (self *SDisk) Resize(ctx context.Context, size int64) error { - return self.storage.zone.region.ResizeDisk(ctx, self.DiskId, size) +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.ResizeDisk(ctx, self.DiskId, sizeMb/1024) } func (self *SDisk) GetName() string { @@ -374,3 +374,7 @@ func (self *SRegion) CreateDisk(zoneId string, category string, name string, siz } return diskIDSet[0], nil } + +func (disk *SDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/qcloud/image.go b/pkg/util/qcloud/image.go index 2d481ab146..e368758ae9 100644 --- a/pkg/util/qcloud/image.go +++ b/pkg/util/qcloud/image.go @@ -5,6 +5,7 @@ import ( "strconv" "time" + "context" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -104,7 +105,7 @@ func (self *SImage) GetGlobalId() string { return fmt.Sprintf("%s-%s") } -func (self *SImage) Delete() error { +func (self *SImage) Delete(ctx context.Context) error { return self.storageCache.region.DeleteImage(self.ImageId) } diff --git a/pkg/util/qcloud/instance.go b/pkg/util/qcloud/instance.go index ba0103bffa..502dd52c35 100644 --- a/pkg/util/qcloud/instance.go +++ b/pkg/util/qcloud/instance.go @@ -400,7 +400,7 @@ func (self *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd s return instance.SystemDisk.DiskId, nil } -func (self *SInstance) ChangeConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { +func (self *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error { return self.host.zone.region.ChangeVMConfig(self.Placement.Zone, self.InstanceId, ncpu, vmem, nil) } @@ -735,3 +735,7 @@ func (self *SInstance) GetExpiredAt() time.Time { func (self *SInstance) UpdateUserData(userData string) error { return cloudprovider.ErrNotSupported } + +func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/util/qcloud/localdisk.go b/pkg/util/qcloud/localdisk.go index ab100b7a69..5d1e724d0d 100644 --- a/pkg/util/qcloud/localdisk.go +++ b/pkg/util/qcloud/localdisk.go @@ -127,3 +127,7 @@ func (self *SLocalDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { func (self *SLocalDisk) Resize(ctx context.Context, size int64) error { return cloudprovider.ErrNotSupported } + +func (disk *SLocalDisk) GetAccessPath() string { + return "" +} diff --git a/pkg/util/qcloud/localstorage.go b/pkg/util/qcloud/localstorage.go index 38d57186c1..5d12e21564 100644 --- a/pkg/util/qcloud/localstorage.go +++ b/pkg/util/qcloud/localstorage.go @@ -93,6 +93,10 @@ func (self *SLocalStorage) CreateIDisk(name string, sizeGb int, desc string) (cl return nil, cloudprovider.ErrNotSupported } -func (self *SLocalStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { +func (self *SLocalStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { return &SLocalDisk{storage: self, DiskId: idStr}, nil } + +func (self *SLocalStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/qcloud/provider/provider.go b/pkg/util/qcloud/provider/provider.go index 9f34d9123a..932b441855 100644 --- a/pkg/util/qcloud/provider/provider.go +++ b/pkg/util/qcloud/provider/provider.go @@ -67,26 +67,10 @@ func (self *SQcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegi return self.client.GetIRegionById(id) } -func (self *SQcloudProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return self.client.GetIHostById(id) -} - -func (self *SQcloudProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - return self.client.GetIVpcById(id) -} - -func (self *SQcloudProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.client.GetIStorageById(id) -} - -func (self *SQcloudProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - return self.client.GetIStoragecacheById(id) -} - func (self *SQcloudProvider) GetBalance() (float64, error) { return 0.0, nil } -func (self *SQcloudProvider) GetOnPremiseIHosts() ([]cloudprovider.ICloudHost, error) { +func (self *SQcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } diff --git a/pkg/util/qcloud/qcloud.go b/pkg/util/qcloud/qcloud.go index 02fb2fd061..492ab5ab6d 100644 --- a/pkg/util/qcloud/qcloud.go +++ b/pkg/util/qcloud/qcloud.go @@ -250,18 +250,6 @@ func (client *SQcloudClient) GetIStorageById(id string) (cloudprovider.ICloudSto return nil, cloudprovider.ErrNotFound } -func (client *SQcloudClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - for i := 0; i < len(client.iregions); i++ { - ihost, err := client.iregions[i].GetIStoragecacheById(id) - if err == nil { - return ihost, nil - } else if err != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - type SAccountBalance struct { AvailableAmount float64 AvailableCashAmount float64 diff --git a/pkg/util/qcloud/region.go b/pkg/util/qcloud/region.go index 2c74f880b5..aac721a209 100644 --- a/pkg/util/qcloud/region.go +++ b/pkg/util/qcloud/region.go @@ -156,6 +156,40 @@ func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, er return nil, cloudprovider.ErrNotFound } +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { storageCache := self.getStoragecache() if storageCache.GetGlobalId() == id { diff --git a/pkg/util/qcloud/storage.go b/pkg/util/qcloud/storage.go index a9ebca1bc4..065210f5df 100644 --- a/pkg/util/qcloud/storage.go +++ b/pkg/util/qcloud/storage.go @@ -121,7 +121,7 @@ func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudpr return nil, cloudprovider.ErrNotFound } -func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { disk, err := self.zone.region.GetDisk(idStr) if err != nil { return nil, err @@ -129,3 +129,7 @@ func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { disk.storage = self return disk, nil } + +func (self *SStorage) GetMountPoint() string { + return "" +} diff --git a/pkg/util/qcloud/storagecache.go b/pkg/util/qcloud/storagecache.go index f51281d605..c1d4e64571 100644 --- a/pkg/util/qcloud/storagecache.go +++ b/pkg/util/qcloud/storagecache.go @@ -109,6 +109,22 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { return self.iimages, nil } +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + parts, _, err := self.region.GetImages("", "PRIVATE_IMAGE", []string{extId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + parts[1].storageCache = self + return &parts[0], nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) { if len(extId) > 0 { log.Debugf("UploadImage: Image external ID exists %s", extId)