diff --git a/pkg/apis/compute/snapshot.go b/pkg/apis/compute/snapshot.go index f766bc20eb..e85f7139c5 100644 --- a/pkg/apis/compute/snapshot.go +++ b/pkg/apis/compute/snapshot.go @@ -19,9 +19,8 @@ import "yunion.io/x/onecloud/pkg/apis" type SSnapshotCreateInput struct { apis.Meta - Name string `json:"name"` - ProjectId string `json:"project_id"` - DomainId string `json:"domain_id"` + Name string `json:"name"` + Description string `json:"description"` DiskId string `json:"disk_id"` StorageId string `json:"storage_id"` diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index d715dd2a39..6ee83a832a 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -978,6 +978,14 @@ func (self *SDisk) GetStorage() *SStorage { return nil } +func (self *SDisk) GetRegionDriver() (IRegionDriver, error) { + storage := self.GetStorage() + if storage == nil { + return nil, fmt.Errorf("failed to found storage for disk %s(%s)", self.Name, self.Id) + } + return storage.GetRegionDriver() +} + func (self *SDisk) GetBackupStorage() *SStorage { if len(self.BackupStorageId) == 0 { return nil diff --git a/pkg/compute/models/managedresource.go b/pkg/compute/models/managedresource.go index d12370f501..2f41a1b228 100644 --- a/pkg/compute/models/managedresource.go +++ b/pkg/compute/models/managedresource.go @@ -51,6 +51,19 @@ func (self *SManagedResourceBase) GetCloudaccount() *SCloudaccount { return cp.GetCloudaccount() } +func (self *SManagedResourceBase) GetRegionDriver() (IRegionDriver, error) { + cloudprovider := self.GetCloudprovider() + provider := api.CLOUD_PROVIDER_ONECLOUD + if cloudprovider != nil { + provider = cloudprovider.Provider + } + driver := GetRegionDriver(provider) + if driver == nil { + return nil, fmt.Errorf("failed to get %s region drivder", provider) + } + return driver, nil +} + func (self *SManagedResourceBase) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { provider := self.GetCloudprovider() if provider == nil { diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 5d9a2bce2b..5ff95de823 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -97,7 +97,7 @@ type IRegionDriver interface { // Region Driver Snapshot Apis ValidateSnapshotDelete(ctx context.Context, snapshot *SSnapshot) error - ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, data *jsonutils.JSONDict) error + ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, storage *SStorage, input *api.SSnapshotCreateInput) error RequestCreateSnapshot(ctx context.Context, snapshot *SSnapshot, task taskman.ITask) error RequestDeleteSnapshot(ctx context.Context, snapshot *SSnapshot, task taskman.ITask) error SnapshotIsOutOfChain(disk *SDisk) bool diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 22b95a1aaf..9b72261532 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -84,27 +84,6 @@ func init() { SnapshotManager.SetVirtualObject(SnapshotManager) } -func ValidateSnapshotName(name string, owner mcclient.IIdentityProvider) error { - q := SnapshotManager.Query() - q = SnapshotManager.FilterByName(q, name) - q = SnapshotManager.FilterByOwner(q, owner, SnapshotManager.NamespaceScope()) - q = SnapshotManager.FilterBySystemAttributes(q, nil, nil, SnapshotManager.ResourceScope()) - cnt, err := q.CountWithError() - if err != nil { - return err - } - if cnt != 0 { - return httperrors.NewConflictError("Name %s conflict", name) - } - if !('A' <= name[0] && name[0] <= 'Z' || 'a' <= name[0] && name[0] <= 'z') { - return httperrors.NewBadRequestError("Name must start with letter") - } - if len(name) < 2 || len(name) > 128 { - return httperrors.NewBadRequestError("Snapshot name length must within 2~128") - } - return nil -} - func (self *SSnapshotManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } @@ -236,21 +215,40 @@ func (self *SSnapshot) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { func (manager *SSnapshotManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { diskV := validators.NewModelIdOrNameValidator("disk", "disk", ownerId) - if err := diskV.Validate(data); err != nil { + err := diskV.Validate(data) + if err != nil { return nil, err } disk := diskV.Model.(*SDisk) - snapshotName, err := data.GetString("name") - if err != nil { - return nil, httperrors.NewMissingParameterError("name") + input := &api.SSnapshotCreateInput{ + DiskType: disk.DiskType, + Size: disk.DiskSize, } - err = ValidateSnapshotName(snapshotName, ownerId) + + err = data.Unmarshal(input) + if err != nil { + return nil, httperrors.NewInputParameterError("failed to unmarshal input params: %v", err) + } + + storage := disk.GetStorage() + if len(disk.ExternalId) == 0 { + input.StorageId = disk.StorageId + } + input.ManagerId = storage.ManagerId + region := storage.GetRegion() + if region == nil { + return nil, httperrors.NewInputParameterError("failed to found region for disk's storage %s(%s)", storage.Name, storage.Id) + } + input.CloudregionId = region.Id + + driver, err := storage.GetRegionDriver() if err != nil { return nil, err } + input.OutOfChain = driver.SnapshotIsOutOfChain(disk) - err = disk.GetStorage().GetRegion().GetDriver().ValidateSnapshotCreate(ctx, userCred, disk, data) + err = driver.ValidateCreateSnapshotData(ctx, userCred, disk, storage, input) if err != nil { return nil, err } @@ -262,26 +260,6 @@ func (manager *SSnapshotManager) ValidateCreateData(ctx context.Context, userCre return nil, httperrors.NewOutOfQuotaError("Check set pending quota error %s", err) } - input := &api.SSnapshotCreateInput{} - input.Name = snapshotName - input.ProjectId = ownerId.GetProjectId() - input.DomainId = ownerId.GetProjectDomainId() - input.DiskId = disk.Id - input.CreatedBy = api.SNAPSHOT_MANUAL - input.Size = disk.DiskSize - input.DiskType = disk.DiskType - input.OutOfChain = disk.GetStorage().GetRegion().GetDriver().SnapshotIsOutOfChain(disk) - storage := disk.GetStorage() - if len(disk.ExternalId) == 0 { - input.StorageId = disk.StorageId - } - if cloudregion := storage.GetRegion(); cloudregion != nil { - input.CloudregionId = cloudregion.GetId() - } - provider := disk.GetCloudprovider() - if provider != nil { - input.ManagerId = provider.Id - } return input.JSON(input), nil } diff --git a/pkg/compute/models/storagedrivers.go b/pkg/compute/models/storagedrivers.go index 9642cec190..c2bf0a2bfd 100644 --- a/pkg/compute/models/storagedrivers.go +++ b/pkg/compute/models/storagedrivers.go @@ -19,6 +19,7 @@ import ( "yunion.io/x/jsonutils" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -34,7 +35,7 @@ type IStorageDriver interface { PostCreate(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage, data jsonutils.JSONObject) ValidateSnapshotDelete(ctx context.Context, snapshot *SSnapshot) error - ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, data *jsonutils.JSONDict) error + ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, input *api.SSnapshotCreateInput) error RequestCreateSnapshot(ctx context.Context, snapshot *SSnapshot, task taskman.ITask) error RequestDeleteSnapshot(ctx context.Context, snapshot *SSnapshot, task taskman.ITask) error SnapshotIsOutOfChain(disk *SDisk) bool diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 14f233a6e9..84b05b22b1 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -845,9 +845,8 @@ func (self *SAliyunRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context return nil } -func (self *SAliyunRegionDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { - name, _ := data.GetString("name") - if strings.HasPrefix(name, "auto") || strings.HasPrefix(name, "http://") || strings.HasPrefix(name, "https://") { +func (self *SAliyunRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SSnapshotCreateInput) error { + if strings.HasPrefix(input.Name, "auto") || strings.HasPrefix(input.Name, "http://") || strings.HasPrefix(input.Name, "https://") { return httperrors.NewBadRequestError( "Snapshot for %s name can't start with auto, http:// or https://", self.GetProvider()) } diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index b0821f1b68..47c0b98e6b 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -149,8 +149,8 @@ func (self *SBaseRegionDriver) RequestDeleteSnapshot(ctx context.Context, snapsh return fmt.Errorf("Not Implement RequestDeleteSnapshot") } -func (self *SBaseRegionDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { - return fmt.Errorf("Not Implement ValidateSnapshotCreate") +func (self *SBaseRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SSnapshotCreateInput) error { + return fmt.Errorf("Not Implement ValidateCreateSnapshotData") } func (self *SBaseRegionDriver) RequestCreateSnapshot(ctx context.Context, snapshot *models.SSnapshot, task taskman.ITask) error { diff --git a/pkg/compute/regiondrivers/esxi.go b/pkg/compute/regiondrivers/esxi.go index 1b0716e915..e0092c9989 100644 --- a/pkg/compute/regiondrivers/esxi.go +++ b/pkg/compute/regiondrivers/esxi.go @@ -51,6 +51,6 @@ func (self *SEsxiRegionDriver) ValidateCreateLoadbalancerCertificateData(ctx con return nil, httperrors.NewNotImplementedError("%s does not support creating loadbalancer certificate", self.GetProvider()) } -func (self *SEsxiRegionDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { +func (self *SEsxiRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SSnapshotCreateInput) error { return fmt.Errorf("%s does not support creating snapshot", self.GetProvider()) } diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index fa1055cd47..1dc38eb4cf 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -732,9 +732,12 @@ func (self *SKVMRegionDriver) RequestDeleteSnapshot(ctx context.Context, snapsho return models.GetStorageDriver(storage.StorageType).RequestDeleteSnapshot(ctx, snapshot, task) } -func (self *SKVMRegionDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { - storage := disk.GetStorage() - return models.GetStorageDriver(storage.StorageType).ValidateSnapshotCreate(ctx, userCred, disk, data) +func (self *SKVMRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SSnapshotCreateInput) error { + host := storage.GetMasterHost() + if host == nil { + return fmt.Errorf("failed to get master host, maybe the host is offline") + } + return models.GetStorageDriver(storage.StorageType).ValidateCreateSnapshotData(ctx, userCred, disk, input) } func (self *SKVMRegionDriver) RequestCreateSnapshot(ctx context.Context, snapshot *models.SSnapshot, task taskman.ITask) error { diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 17f6f84d9e..d0258122d6 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -1193,7 +1193,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestDeleteSnapshot(ctx contex return nil } -func (self *SManagedVirtualizationRegionDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { +func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, storage *models.SStorage, input *api.SSnapshotCreateInput) error { return nil } diff --git a/pkg/compute/storagedrivers/base.go b/pkg/compute/storagedrivers/base.go index 21b71ab38b..f0c3966d31 100644 --- a/pkg/compute/storagedrivers/base.go +++ b/pkg/compute/storagedrivers/base.go @@ -66,7 +66,7 @@ func (self *SBaseStorageDriver) ValidateSnapshotDelete(ctx context.Context, snap return nil } -func (self *SBaseStorageDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { +func (self *SBaseStorageDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, input *api.SSnapshotCreateInput) error { guests := disk.GetGuests() if len(guests) != 1 { return httperrors.NewBadRequestError("Disk %s dosen't attach guest ?", disk.Id) diff --git a/pkg/compute/storagedrivers/rbd.go b/pkg/compute/storagedrivers/rbd.go index 3f1849a948..3a2b5ec2a3 100644 --- a/pkg/compute/storagedrivers/rbd.go +++ b/pkg/compute/storagedrivers/rbd.go @@ -179,7 +179,7 @@ func (self *SRbdStorageDriver) ValidateSnapshotDelete(ctx context.Context, snaps return nil } -func (self *SRbdStorageDriver) ValidateSnapshotCreate(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, data *jsonutils.JSONDict) error { +func (self *SRbdStorageDriver) ValidateCreateSnapshotData(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, input *api.SSnapshotCreateInput) error { return nil } diff --git a/pkg/compute/tasks/snapshot_create_task.go b/pkg/compute/tasks/snapshot_create_task.go index e312140295..b10aaf3d12 100644 --- a/pkg/compute/tasks/snapshot_create_task.go +++ b/pkg/compute/tasks/snapshot_create_task.go @@ -23,6 +23,7 @@ import ( "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 SnapshotCreateTask struct { @@ -41,12 +42,14 @@ func (self *SnapshotCreateTask) OnInit(ctx context.Context, obj db.IStandaloneMo func (self *SnapshotCreateTask) TaskFailed(ctx context.Context, snapshot *models.SSnapshot, reason string) { snapshot.SetStatus(self.UserCred, api.SNAPSHOT_FAILED, reason) db.OpsLog.LogEvent(snapshot, db.ACT_SNAPSHOT_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, snapshot, logclient.ACT_CREATE, reason, self.UserCred, false) self.SetStageFailed(ctx, reason) } func (self *SnapshotCreateTask) TaskComplete(ctx context.Context, snapshot *models.SSnapshot, data jsonutils.JSONObject) { snapshot.SetStatus(self.UserCred, api.SNAPSHOT_READY, "") db.OpsLog.LogEvent(snapshot, db.ACT_SNAPSHOT_DONE, "", self.UserCred) + logclient.AddActionLogWithStartable(self, snapshot, logclient.ACT_CREATE, "", self.UserCred, true) self.SetStageComplete(ctx, nil) }