yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ucloud/disk.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ucloud
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/pkg/errors"
    24  
    25  	"yunion.io/x/jsonutils"
    26  	"yunion.io/x/log"
    27  	"yunion.io/x/pkg/utils"
    28  
    29  	billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
    30  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    31  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    32  	"yunion.io/x/cloudmux/pkg/multicloud"
    33  )
    34  
    35  // https://docs.ucloud.cn/api/udisk-api/describe_udisk
    36  type SDisk struct {
    37  	storage *SStorage
    38  	multicloud.SDisk
    39  	UcloudTags
    40  
    41  	Status        string `json:"Status"`
    42  	DeviceName    string `json:"DeviceName"`
    43  	UHostID       string `json:"UHostId"`
    44  	Tag           string `json:"Tag"`
    45  	Version       string `json:"Version"`
    46  	Name          string `json:"Name"`
    47  	Zone          string `json:"Zone"`
    48  	UHostIP       string `json:"UHostIP"`
    49  	DiskType      string `json:"DiskType"`
    50  	UDataArkMode  string `json:"UDataArkMode"`
    51  	SnapshotLimit int    `json:"SnapshotLimit"`
    52  	ExpiredTime   int64  `json:"ExpiredTime"`
    53  	SnapshotCount int    `json:"SnapshotCount"`
    54  	IsExpire      string `json:"IsExpire"`
    55  	UDiskID       string `json:"UDiskId"`
    56  	ChargeType    string `json:"ChargeType"`
    57  	UHostName     string `json:"UHostName"`
    58  	CreateTime    int64  `json:"CreateTime"`
    59  	SizeGB        int    `json:"Size"`
    60  }
    61  
    62  func (self *SDisk) GetProjectId() string {
    63  	return self.storage.zone.region.client.projectId
    64  }
    65  
    66  func (self *SDisk) GetId() string {
    67  	return self.UDiskID
    68  }
    69  
    70  func (self *SDisk) GetName() string {
    71  	if len(self.Name) == 0 {
    72  		return self.GetId()
    73  	}
    74  
    75  	return self.Name
    76  }
    77  
    78  func (self *SDisk) GetGlobalId() string {
    79  	return self.GetId()
    80  }
    81  
    82  func (self *SDisk) GetStatus() string {
    83  	switch self.Status {
    84  	case "Available":
    85  		return api.DISK_READY
    86  	case "Attaching":
    87  		return api.DISK_ATTACHING
    88  	case "InUse":
    89  		return api.DISK_READY
    90  	case "Detaching":
    91  		return api.DISK_DETACHING
    92  	case "Initializating":
    93  		return api.DISK_ALLOCATING
    94  	case "Failed":
    95  		return api.DISK_ALLOC_FAILED
    96  	case "Cloning":
    97  		return api.DISK_CLONING
    98  	case "Restoring":
    99  		return api.DISK_RESET
   100  	case "RestoreFailed":
   101  		return api.DISK_RESET_FAILED
   102  	default:
   103  		return api.DISK_UNKNOWN
   104  	}
   105  }
   106  
   107  func (self *SDisk) Refresh() error {
   108  	new, err := self.storage.zone.region.GetDisk(self.GetId())
   109  	if err != nil {
   110  		return err
   111  	}
   112  	return jsonutils.Update(self, new)
   113  }
   114  
   115  func (self *SDisk) IsEmulated() bool {
   116  	return false
   117  }
   118  
   119  func (self *SDisk) GetSysTags() map[string]string {
   120  	data := map[string]string{}
   121  	data["hypervisor"] = api.HYPERVISOR_UCLOUD
   122  
   123  	return data
   124  }
   125  
   126  // Year,Month,Dynamic,Trial
   127  func (self *SDisk) GetBillingType() string {
   128  	switch self.ChargeType {
   129  	case "Year", "Month":
   130  		return billing_api.BILLING_TYPE_PREPAID
   131  	default:
   132  		return billing_api.BILLING_TYPE_POSTPAID
   133  	}
   134  }
   135  
   136  func (self *SDisk) GetCreatedAt() time.Time {
   137  	return time.Unix(self.CreateTime, 0)
   138  }
   139  
   140  func (self *SDisk) GetExpiredAt() time.Time {
   141  	return time.Unix(self.ExpiredTime, 0)
   142  }
   143  
   144  func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
   145  	return self.storage, nil
   146  }
   147  
   148  func (self *SDisk) GetDiskFormat() string {
   149  	return "vhd"
   150  }
   151  
   152  func (self *SDisk) GetDiskSizeMB() int {
   153  	return self.SizeGB * 1024
   154  }
   155  
   156  func (self *SDisk) GetIsAutoDelete() bool {
   157  	if self.DiskType == "SystemDisk" {
   158  		return true
   159  	}
   160  
   161  	return false
   162  }
   163  
   164  func (self *SDisk) GetTemplateId() string {
   165  	if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 {
   166  		ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID)
   167  		if err != nil {
   168  			log.Errorln(err)
   169  		}
   170  
   171  		return ins.ImageID
   172  	}
   173  
   174  	return ""
   175  }
   176  
   177  func (self *SDisk) GetDiskType() string {
   178  	if strings.Contains(self.DiskType, "SystemDisk") {
   179  		return api.DISK_TYPE_SYS
   180  	}
   181  
   182  	return api.DISK_TYPE_DATA
   183  }
   184  
   185  func (self *SDisk) GetStorageType() string {
   186  	if self.storage == nil {
   187  		if strings.Contains(self.DiskType, "SSD") {
   188  			return api.STORAGE_UCLOUD_CLOUD_SSD
   189  		} else {
   190  			return api.STORAGE_UCLOUD_CLOUD_NORMAL
   191  		}
   192  	}
   193  
   194  	return self.storage.storageType
   195  }
   196  
   197  func (self *SDisk) GetFsFormat() string {
   198  	return ""
   199  }
   200  
   201  func (self *SDisk) GetIsNonPersistent() bool {
   202  	return false
   203  }
   204  
   205  func (self *SDisk) GetDriver() string {
   206  	return "scsi"
   207  }
   208  
   209  func (self *SDisk) GetCacheMode() string {
   210  	return "none"
   211  }
   212  
   213  func (self *SDisk) GetMountpoint() string {
   214  	return ""
   215  }
   216  
   217  func (self *SDisk) GetAccessPath() string {
   218  	return ""
   219  }
   220  
   221  func (self *SDisk) Delete(ctx context.Context) error {
   222  	return self.storage.zone.region.DeleteDisk(self.Zone, self.GetId())
   223  }
   224  
   225  func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) {
   226  	snapshot, err := self.storage.zone.region.CreateSnapshot(self.Zone, self.GetId(), name, desc)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	isnapshot, err := self.GetISnapshot(snapshot)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  
   236  	err = cloudprovider.WaitStatus(isnapshot, api.SNAPSHOT_READY, time.Second*10, time.Second*300)
   237  	if err != nil {
   238  		return nil, errors.Wrap(err, "CreateISnapshot")
   239  	}
   240  
   241  	return isnapshot, nil
   242  }
   243  
   244  func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) {
   245  	snapshot, err := self.storage.zone.region.GetSnapshotById(self.Zone, snapshotId)
   246  	return &snapshot, err
   247  }
   248  
   249  func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) {
   250  	snapshot, err := self.getSnapshot(idStr)
   251  	return snapshot, err
   252  }
   253  
   254  func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
   255  	snapshots, err := self.storage.zone.region.GetSnapshots("", self.GetId(), "")
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots))
   261  	for i := 0; i < len(snapshots); i++ {
   262  		isnapshots[i] = &snapshots[i]
   263  	}
   264  	return isnapshots, nil
   265  }
   266  
   267  func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error {
   268  	var sizeGB int64
   269  	// 向上取整
   270  	if (newSizeMB % 1024) > 0 {
   271  		sizeGB = newSizeMB/1024 + 1
   272  	} else {
   273  		sizeGB = newSizeMB / 1024
   274  	}
   275  
   276  	if self.Status == "InUse" {
   277  		err := self.storage.zone.region.DetachDisk(self.Zone, self.UHostID, self.UDiskID)
   278  		if err != nil {
   279  			return err
   280  		}
   281  
   282  		defer self.storage.zone.region.AttachDisk(self.Zone, self.UHostID, self.UDiskID)
   283  		err = cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second)
   284  		if err != nil {
   285  			return errors.Wrap(err, "DiskResize")
   286  		}
   287  
   288  	}
   289  	return self.storage.zone.region.resizeDisk(self.Zone, self.GetId(), sizeGB)
   290  }
   291  
   292  func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
   293  	err := self.storage.zone.region.resetDisk(self.Zone, self.GetId(), snapshotId)
   294  	if err != nil {
   295  		return "", err
   296  	}
   297  
   298  	return self.GetId(), nil
   299  }
   300  
   301  func (self *SDisk) Rebuild(ctx context.Context) error {
   302  	return self.storage.zone.region.resetDisk(self.Zone, self.GetId(), "")
   303  }
   304  
   305  func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
   306  	if len(diskId) == 0 {
   307  		return nil, fmt.Errorf("GetDisk id should not empty")
   308  	}
   309  
   310  	disks, err := self.GetDisks("", "", []string{diskId})
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	if len(disks) == 1 {
   316  		return &disks[0], nil
   317  	} else if len(disks) == 0 {
   318  		return nil, cloudprovider.ErrNotFound
   319  	} else {
   320  		return nil, fmt.Errorf("GetDisk %s %d found", diskId, len(disks))
   321  	}
   322  }
   323  
   324  // https://docs.ucloud.cn/api/udisk-api/describe_udisk
   325  // diskType DataDisk|SystemDisk (DataDisk表示数据盘,SystemDisk表示系统盘)
   326  func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string) ([]SDisk, error) {
   327  	disks := make([]SDisk, 0)
   328  	params := NewUcloudParams()
   329  	if len(zoneId) > 0 {
   330  		params.Set("Zone", zoneId)
   331  	}
   332  
   333  	if len(diskType) > 0 {
   334  		params.Set("DiskType", diskType)
   335  	}
   336  
   337  	err := self.DoListAll("DescribeUDisk", params, &disks)
   338  	if err != nil {
   339  		return nil, err
   340  	}
   341  
   342  	if len(diskIds) > 0 {
   343  		filtedDisks := make([]SDisk, 0)
   344  		for i := range disks {
   345  			if utils.IsInStringArray(disks[i].UDiskID, diskIds) {
   346  				filtedDisks = append(filtedDisks, disks[i])
   347  			}
   348  		}
   349  
   350  		return filtedDisks, nil
   351  	}
   352  
   353  	return disks, nil
   354  }
   355  
   356  // https://docs.ucloud.cn/api/udisk-api/delete_udisk
   357  func (self *SRegion) DeleteDisk(zoneId string, diskId string) error {
   358  	params := NewUcloudParams()
   359  	params.Set("Zone", zoneId)
   360  	params.Set("UDiskId", diskId)
   361  
   362  	return self.DoAction("DeleteUDisk", params, nil)
   363  }
   364  
   365  // https://docs.ucloud.cn/api/udisk-api/create_udisk
   366  func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int) (string, error) {
   367  	params := NewUcloudParams()
   368  	params.Set("Zone", zoneId)
   369  	params.Set("Size", sizeGb)
   370  	params.Set("Name", name)
   371  	params.Set("DiskType", category)
   372  
   373  	diskIds := make([]string, 0)
   374  	err := self.DoAction("CreateUDisk", params, &diskIds)
   375  	if err != nil {
   376  		return "", err
   377  	}
   378  
   379  	if len(diskIds) == 0 {
   380  		return "", fmt.Errorf("CreateDisk with empty response")
   381  	}
   382  
   383  	return diskIds[0], nil
   384  }
   385  
   386  // https://docs.ucloud.cn/api/udisk-api/create_udisk_snapshot
   387  func (self *SRegion) CreateSnapshot(zoneId, diskId, name, desc string) (string, error) {
   388  	params := NewUcloudParams()
   389  	params.Set("Zone", zoneId)
   390  	params.Set("UDiskId", diskId)
   391  	params.Set("Name", name)
   392  	params.Set("Comment", desc)
   393  
   394  	snapshotIds := make([]string, 0)
   395  	err := self.DoAction("CreateUDiskSnapshot", params, &snapshotIds)
   396  	if err != nil {
   397  		return "", err
   398  	}
   399  
   400  	if len(snapshotIds) == 0 {
   401  		return "", fmt.Errorf("CreateSnapshot with empty response")
   402  	}
   403  
   404  	return snapshotIds[0], nil
   405  }
   406  
   407  // https://docs.ucloud.cn/api/udisk-api/resize_udisk
   408  func (self *SRegion) resizeDisk(zoneId string, diskId string, sizeGB int64) error {
   409  	params := NewUcloudParams()
   410  	params.Set("Zone", zoneId)
   411  	params.Set("Size", sizeGB)
   412  	params.Set("UDiskId", diskId)
   413  
   414  	return self.DoAction("ResizeUDisk", params, nil)
   415  }
   416  
   417  // https://docs.ucloud.cn/api/udisk-api/restore_u_disk
   418  func (self *SRegion) resetDisk(zoneId, diskId, snapshotId string) error {
   419  	params := NewUcloudParams()
   420  	params.Set("Zone", zoneId)
   421  	params.Set("UDiskId", diskId)
   422  	if len(snapshotId) > 0 {
   423  		params.Set("SnapshotId", snapshotId)
   424  	}
   425  
   426  	return self.DoAction("RestoreUDisk", params, nil)
   427  }
   428  
   429  // https://docs.ucloud.cn/api/udisk-api/attach_udisk
   430  func (self *SRegion) AttachDisk(zoneId string, instanceId string, diskId string) error {
   431  	params := NewUcloudParams()
   432  	params.Set("Zone", zoneId)
   433  	params.Set("UHostId", instanceId)
   434  	params.Set("UDiskId", diskId)
   435  
   436  	return self.DoAction("AttachUDisk", params, nil)
   437  }
   438  
   439  // https://docs.ucloud.cn/api/udisk-api/detach_udisk
   440  func (self *SRegion) DetachDisk(zoneId string, instanceId string, diskId string) error {
   441  	idisks, err := self.GetDisk(diskId)
   442  	if err != nil {
   443  		return err
   444  	}
   445  
   446  	if idisks.Status == "Available" {
   447  		return nil
   448  	}
   449  
   450  	params := NewUcloudParams()
   451  	params.Set("Zone", zoneId)
   452  	params.Set("UHostId", instanceId)
   453  	params.Set("UDiskId", diskId)
   454  
   455  	return self.DoAction("DetachUDisk", params, nil)
   456  }