yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/snapshot.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 apsara 16 17 import ( 18 "context" 19 "fmt" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 25 api "yunion.io/x/cloudmux/pkg/apis/compute" 26 "yunion.io/x/cloudmux/pkg/cloudprovider" 27 "yunion.io/x/cloudmux/pkg/multicloud" 28 ) 29 30 type SnapshotStatusType string 31 32 const ( 33 SnapshotStatusAccomplished SnapshotStatusType = "accomplished" 34 SnapshotStatusProgress SnapshotStatusType = "progressing" 35 SnapshotStatusFailed SnapshotStatusType = "failed" 36 37 SnapshotTypeSystem string = "System" 38 SnapshotTypeData string = "Data" 39 ) 40 41 type SSnapshot struct { 42 multicloud.SResourceBase 43 ApsaraTags 44 region *SRegion 45 46 Progress string 47 SnapshotId string 48 SnapshotName string 49 SourceDiskId string 50 SourceDiskSize int32 51 SourceDiskType string 52 Status SnapshotStatusType 53 Usage string 54 DepartmentInfo 55 } 56 57 func (self *SSnapshot) GetId() string { 58 return self.SnapshotId 59 } 60 61 func (self *SSnapshot) GetName() string { 62 return self.SnapshotName 63 } 64 65 func (self *SSnapshot) GetStatus() string { 66 if self.Status == SnapshotStatusAccomplished { 67 return api.SNAPSHOT_READY 68 } else if self.Status == SnapshotStatusProgress { 69 return api.SNAPSHOT_CREATING 70 } else { // if self.Status == SnapshotStatusFailed 71 return api.SNAPSHOT_FAILED 72 } 73 } 74 75 func (self *SSnapshot) GetSizeMb() int32 { 76 return self.SourceDiskSize * 1024 77 } 78 79 func (self *SSnapshot) GetDiskId() string { 80 return self.SourceDiskId 81 } 82 83 func (self *SSnapshot) GetDiskType() string { 84 if self.SourceDiskType == SnapshotTypeSystem { 85 return api.DISK_TYPE_SYS 86 } else if self.SourceDiskType == SnapshotTypeData { 87 return api.DISK_TYPE_DATA 88 } else { 89 return "" 90 } 91 } 92 93 func (self *SSnapshot) Refresh() error { 94 if snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1); err != nil { 95 return err 96 } else if total != 1 { 97 return cloudprovider.ErrNotFound 98 } else if err := jsonutils.Update(self, snapshots[0]); err != nil { 99 return err 100 } 101 return nil 102 } 103 104 func (self *SSnapshot) GetGlobalId() string { 105 return fmt.Sprintf("%s", self.SnapshotId) 106 } 107 108 func (self *SSnapshot) IsEmulated() bool { 109 return false 110 } 111 112 func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { 113 snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) 114 if err != nil { 115 return nil, err 116 } 117 for len(snapshots) < total { 118 var parts []SSnapshot 119 parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) 120 if err != nil { 121 return nil, err 122 } 123 snapshots = append(snapshots, parts...) 124 } 125 ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) 126 for i := 0; i < len(snapshots); i += 1 { 127 ret[i] = &snapshots[i] 128 } 129 return ret, nil 130 } 131 132 func (self *SSnapshot) Delete() error { 133 if self.region == nil { 134 return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) 135 } 136 if err := self.region.SnapshotPreDelete(self.SnapshotId); err != nil { 137 return err 138 } 139 return self.region.DeleteSnapshot(self.SnapshotId) 140 } 141 142 func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { 143 if limit > 50 || limit <= 0 { 144 limit = 50 145 } 146 params := make(map[string]string) 147 params["RegionId"] = self.RegionId 148 params["PageSize"] = fmt.Sprintf("%d", limit) 149 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 150 151 if len(instanceId) > 0 { 152 params["InstanceId"] = instanceId 153 } 154 if len(diskId) > 0 { 155 params["diskId"] = diskId 156 } 157 if len(snapshotName) > 0 { 158 params["SnapshotName"] = snapshotName 159 } 160 if snapshotIds != nil && len(snapshotIds) > 0 { 161 params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() 162 } 163 164 body, err := self.ecsRequest("DescribeSnapshots", params) 165 if err != nil { 166 log.Errorf("GetSnapshots fail %s", err) 167 return nil, 0, err 168 } 169 170 snapshots := make([]SSnapshot, 0) 171 if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { 172 log.Errorf("Unmarshal snapshot details fail %s", err) 173 return nil, 0, err 174 } 175 total, _ := body.Int("TotalCount") 176 for i := 0; i < len(snapshots); i += 1 { 177 snapshots[i].region = self 178 } 179 return snapshots, int(total), nil 180 } 181 182 func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { 183 snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) 184 if err != nil { 185 return nil, err 186 } 187 if total == 0 { 188 return nil, cloudprovider.ErrNotFound 189 } else if total > 1 { 190 return nil, cloudprovider.ErrDuplicateId 191 } 192 return &snapshots[0], nil 193 } 194 195 func (self *SRegion) DeleteSnapshot(snapshotId string) error { 196 params := make(map[string]string) 197 params["SnapshotId"] = snapshotId 198 _, err := self.ecsRequest("DeleteSnapshot", params) 199 return err 200 } 201 202 // If snapshot linked images can't be delete 203 // delete images first -- Apsara 204 func (self *SRegion) SnapshotPreDelete(snapshotId string) error { 205 images, _, err := self.GetImagesBySnapshot(snapshotId, 0, 0) 206 if err != nil { 207 return fmt.Errorf("PreDelete get images by snapshot %s error: %s", snapshotId, err) 208 } 209 for _, image := range images { 210 image.storageCache = &SStoragecache{region: self} 211 if err := image.Delete(context.Background()); err != nil { 212 return fmt.Errorf("PreDelete image %s error: %s", image.GetId(), err) 213 } 214 if err := cloudprovider.WaitDeleted(&image, 3*time.Second, 300*time.Second); err != nil { 215 return fmt.Errorf("PreDelete waite image %s deleted error: %s", image.GetId(), err) 216 } 217 } 218 return nil 219 }