diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 060c266c62..9590da6d0b 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -28,6 +28,11 @@ const ( STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency" STORAGE_CLOUD_SSD = "cloud_ssd" STORAGE_EPHEMERAL_SSD = "ephemeral_ssd" + STORAGE_GP2_SSD = "gp2" // aws general purpose ssd + STORAGE_IO1_SSD = "io1" // aws Provisioned IOPS SSD + STORAGE_ST1_HDD = "st1" // aws Throughput Optimized HDD + STORAGE_SC1_SSD = "sc1" // aws Cold HDD + STORAGE_STANDARD_SSD = "standard" // aws Magnetic volumes STORAGE_ENABLED = "enabled" STORAGE_DISABLED = "disabled" diff --git a/pkg/util/aws/disk.go b/pkg/util/aws/disk.go index ba4ac661b5..243d7c6a63 100644 --- a/pkg/util/aws/disk.go +++ b/pkg/util/aws/disk.go @@ -4,6 +4,9 @@ import ( "time" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" + "github.com/aws/aws-sdk-go/service/ec2" + "yunion.io/x/onecloud/pkg/compute/models" + "github.com/coredns/coredns/plugin/pkg/log" ) type SMountInstances struct { @@ -23,9 +26,10 @@ type SDisk struct { DiskName string // Tag Name Size int // Size - Category string // VolumeType? - Type string // VolumeType + Category string // VolumeType + Type string // system | data Status string // State + AttachmentStatus string // attachment.status Device string // Device InstanceId string // InstanceId Encrypted bool // Encrypted @@ -56,27 +60,44 @@ type SDisk struct { } func (self *SDisk) GetId() string { - panic("implement me") + return self.DiskId } func (self *SDisk) GetName() string { - panic("implement me") + if len(self.DiskName) > 0 { + return self.DiskName + } + return self.DiskId } func (self *SDisk) GetGlobalId() string { - panic("implement me") + return self.DiskId } func (self *SDisk) GetStatus() string { - panic("implement me") + // creating | available | in-use | deleting | deleted | error + switch self.Status { + case "creating": + return models.DISK_ALLOCATING + case "deleting": + return models.DISK_DEALLOC + case "error": + return models.DISK_ALLOC_FAILED + default: + return models.DISK_READY + } } func (self *SDisk) Refresh() error { - panic("implement me") + new, err := self.storage.zone.region.GetDisk(self.DiskId) + if err != nil { + return err + } + return jsonutils.Update(self, new) } func (self *SDisk) IsEmulated() bool { - panic("implement me") + return false } func (self *SDisk) GetMetadata() *jsonutils.JSONDict { @@ -92,79 +113,196 @@ func (self *SDisk) GetExpiredAt() time.Time { } func (self *SDisk) GetIStorge() cloudprovider.ICloudStorage { - panic("implement me") + return self.storage } func (self *SDisk) GetDiskFormat() string { - panic("implement me") + return "vhd" } func (self *SDisk) GetDiskSizeMB() int { - panic("implement me") + return self.Size * 1024 } func (self *SDisk) GetIsAutoDelete() bool { - panic("implement me") + return self.DeleteWithInstance } func (self *SDisk) GetTemplateId() string { - panic("implement me") + return self.ImageId } func (self *SDisk) GetDiskType() string { - panic("implement me") + return self.Type } func (self *SDisk) GetFsFormat() string { - panic("implement me") + return "" } func (self *SDisk) GetIsNonPersistent() bool { - panic("implement me") + return false } func (self *SDisk) GetDriver() string { - panic("implement me") + return "scsi" } func (self *SDisk) GetCacheMode() string { - panic("implement me") + return "none" } func (self *SDisk) GetMountpoint() string { - panic("implement me") + return "" } func (self *SDisk) Delete() error { - panic("implement me") + if _, err := self.storage.zone.region.GetDisk(self.DiskId); err == cloudprovider.ErrNotFound { + log.Errorf("Failed to find disk %s when delete", self.DiskId) + return nil + } + return self.storage.zone.region.DeleteDisk(self.DiskId) } func (self *SDisk) CreateISnapshot(name string, desc string) (cloudprovider.ICloudSnapshot, error) { - panic("implement me") + if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc); err != nil { + log.Errorf("createSnapshot fail %s", err) + return nil, err + } else if snapshot, err := self.getSnapshot(snapshotId); err != nil { + return nil, err + } else { + snapshot.region = self.storage.zone.region + if err := cloudprovider.WaitStatus(snapshot, models.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return snapshot, nil + } } -func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) { - panic("implement me") +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + if snapshot, err := self.getSnapshot(snapshotId); err != nil { + return nil, err + } else { + snapshot.region = self.storage.zone.region + return snapshot, nil + } } func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - panic("implement me") + snapshots := make([]SSnapshot, 0) + for { + if parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20); err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, err + } else { + snapshots = append(snapshots, parts...) + if len(snapshots) >= total { + break + } + } + } + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = self.storage.zone.region + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil } func (self *SDisk) Resize(newSize int64) error { - panic("implement me") + return self.storage.zone.region.resizeDisk(self.DiskId, newSize) } func (self *SDisk) Reset(snapshotId string) error { panic("implement me") } -func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { - return nil, 0, nil +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil { + return nil, err + } else if total != 1 { + return nil, cloudprovider.ErrNotFound + } else { + return &snapshots[0], nil + } +} + +func (self *SRegion) GetDisks(instanceId string, zoneId string, storageType string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { + params := &ec2.DescribeVolumesInput{} + filters := make([]*ec2.Filter, 0) + if len(instanceId) > 0 { + filters = AppendSingleValueFilter(filters, "attachment.instance-id", instanceId) + } + + if len(zoneId) > 0 { + filters = AppendSingleValueFilter(filters, "availability-zone", zoneId) + } + + if len(storageType) > 0 { + filters = AppendSingleValueFilter(filters, "volume-type", storageType) + } + + params.SetFilters(filters) + + if len(diskIds) > 0 { + params.SetVolumeIds(ConvertedList(diskIds)) + } + + ret, err := self.ec2Client.DescribeVolumes(params) + if err != nil { + return nil, 0 , err + } + + disks := make([]SDisk, len(ret.Volumes)) + for _, item := range ret.Volumes { + disk := SDisk{} + disk.ZoneId = *item.AvailabilityZone + disk.Status = *item.State + disk.Size = int(*item.Size) + disk.Category = *item.VolumeType + disk.RegionId = self.RegionId + disk.SourceSnapshotId = *item.SnapshotId + disk.Encrypted = *item.Encrypted + disk.DiskId = *item.VolumeId + disk.Iops = int(*item.Iops) + disk.CreationTime = *item.CreateTime + if len(item.Attachments) > 0 { + disk.DeleteWithInstance = *item.Attachments[0].DeleteOnTermination + disk.AttachedTime = *item.Attachments[0].AttachTime + disk.AttachmentStatus = *item.Attachments[0].State + disk.Device = *item.Attachments[0].Device + disk.InstanceId = *item.Attachments[0].InstanceId + // todo: 需要通过describe-instances 的root device 判断是否是系统盘 + if len(disk.InstanceId) > 0 { + instance, err := self.GetInstance(disk.InstanceId) + if err != nil { + log.Debug(err) + } + + if disk.Device == instance.RootDeviceName { + disk.Type = models.DISK_TYPE_SYS + } else { + disk.Type = models.DISK_TYPE_DATA + } + } else { + disk.Type = models.DISK_TYPE_DATA + } + } + + disks = append(disks, disk) + } + return disks, len(disks), nil } func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - return nil, nil + disks, total, err := self.GetDisks("", "", "", []string{diskId}, 0, 1) + if err != nil { + return nil, err + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + return &disks[0], nil } func (self *SRegion) DeleteDisk(diskId string) error { diff --git a/pkg/util/aws/instance.go b/pkg/util/aws/instance.go index 523236f298..185c66d6df 100644 --- a/pkg/util/aws/instance.go +++ b/pkg/util/aws/instance.go @@ -96,6 +96,7 @@ type SInstance struct { OperationLocks SOperationLocks PublicIpAddress SIpAddress Recyclable bool + RootDeviceName string SerialNumber string SpotPriceLimit string SpotStrategy string diff --git a/pkg/util/aws/utils.go b/pkg/util/aws/utils.go new file mode 100644 index 0000000000..c9bc33d712 --- /dev/null +++ b/pkg/util/aws/utils.go @@ -0,0 +1,31 @@ +package aws + +import "github.com/aws/aws-sdk-go/service/ec2" + +func AppendFilter(filters []*ec2.Filter, name string, values []string) ([]*ec2.Filter) { + f := &ec2.Filter{} + v := make([]*string, len(values)) + for _, value := range values { + v = append(v, &value) + } + + f.SetName(name) + f.SetValues(v) + return append(filters, f) +} + +func AppendSingleValueFilter(filters []*ec2.Filter, name string, value string) ([]*ec2.Filter) { + f := &ec2.Filter{} + f.SetName(name) + f.SetValues([]*string{&value}) + return append(filters, f) +} + +func ConvertedList(list []string) ([]*string) { + result := make([]*string, len(list)) + for _, item := range list { + result = append(result, &item) + } + + return result +} \ No newline at end of file