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 }