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  }