yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/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 aws
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/aws/aws-sdk-go/service/ec2"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  
    27  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/cloudmux/pkg/multicloud"
    30  )
    31  
    32  type SnapshotStatusType string
    33  
    34  const (
    35  	SnapshotStatusAccomplished SnapshotStatusType = "completed"
    36  	SnapshotStatusProgress     SnapshotStatusType = "pending"
    37  	SnapshotStatusFailed       SnapshotStatusType = "error"
    38  )
    39  
    40  type SSnapshot struct {
    41  	multicloud.SResourceBase
    42  	AwsTags
    43  	region *SRegion
    44  
    45  	Progress       string
    46  	SnapshotId     string
    47  	SnapshotName   string
    48  	SourceDiskId   string
    49  	SourceDiskSize int32
    50  	SourceDiskType string
    51  	Status         SnapshotStatusType
    52  	Usage          string
    53  	//TagSpec        TagSpec
    54  }
    55  
    56  func (self *SSnapshot) GetDiskType() string {
    57  	// todo: self.SourceDiskType
    58  	return ""
    59  }
    60  
    61  func (self *SSnapshot) GetId() string {
    62  	return self.SnapshotId
    63  }
    64  
    65  func (self *SSnapshot) GetName() string {
    66  	if len(self.SnapshotName) == 0 {
    67  		return self.SnapshotId
    68  	}
    69  
    70  	return self.SnapshotName
    71  }
    72  
    73  func (self *SSnapshot) GetGlobalId() string {
    74  	return fmt.Sprintf("%s", self.SnapshotId)
    75  }
    76  
    77  func (self *SSnapshot) GetStatus() string {
    78  	// todo: implement me
    79  	if self.Status == SnapshotStatusAccomplished {
    80  		return api.SNAPSHOT_READY
    81  	} else if self.Status == SnapshotStatusProgress {
    82  		return api.SNAPSHOT_CREATING
    83  	} else { // if self.Status == SnapshotStatusFailed
    84  		return api.SNAPSHOT_FAILED
    85  	}
    86  }
    87  
    88  func (self *SSnapshot) Refresh() error {
    89  	if snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1); err != nil {
    90  		return err
    91  	} else if total != 1 {
    92  		return errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots")
    93  	} else if err := jsonutils.Update(self, snapshots[0]); err != nil {
    94  		return err
    95  	}
    96  	return nil
    97  }
    98  
    99  func (self *SSnapshot) IsEmulated() bool {
   100  	return false
   101  }
   102  
   103  func (self *SSnapshot) GetSizeMb() int32 {
   104  	return self.SourceDiskSize * 1024
   105  }
   106  
   107  func (self *SSnapshot) GetDiskId() string {
   108  	return self.SourceDiskId
   109  }
   110  
   111  func (self *SSnapshot) Delete() error {
   112  	return self.region.DeleteSnapshot(self.SnapshotId)
   113  }
   114  
   115  func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) {
   116  	params := &ec2.DescribeSnapshotsInput{}
   117  	filters := make([]*ec2.Filter, 0)
   118  	// todo: not support search by instancesId. use Tag?
   119  	// if len(instanceId) > o {
   120  	// 	filters = AppendSingleValueFilter(filters, )
   121  	// }
   122  	// owner by self
   123  	owner := "self"
   124  	params.SetOwnerIds([]*string{&owner})
   125  	if len(diskId) > 0 {
   126  		filters = AppendSingleValueFilter(filters, "volume-id", diskId)
   127  	}
   128  
   129  	if len(snapshotName) > 0 {
   130  		filters = AppendSingleValueFilter(filters, "tag:Name", snapshotName)
   131  	}
   132  
   133  	if len(filters) > 0 {
   134  		params.SetFilters(filters)
   135  	}
   136  
   137  	if len(snapshotIds) > 0 {
   138  		params.SetSnapshotIds(ConvertedList(snapshotIds))
   139  	}
   140  
   141  	ec2Client, err := self.getEc2Client()
   142  	if err != nil {
   143  		return nil, 0, errors.Wrap(err, "getEc2Client")
   144  	}
   145  	ret, err := ec2Client.DescribeSnapshots(params)
   146  	err = parseNotFoundError(err)
   147  	if err != nil {
   148  		if strings.Contains(err.Error(), "InvalidSnapshot.NotFound") {
   149  			return nil, 0, errors.Wrap(cloudprovider.ErrNotFound, "parseNotFoundError")
   150  		}
   151  
   152  		return nil, 0, err
   153  	}
   154  
   155  	snapshots := []SSnapshot{}
   156  	for _, item := range ret.Snapshots {
   157  		if err := FillZero(item); err != nil {
   158  			return nil, 0, err
   159  		}
   160  
   161  		tagspec := TagSpec{ResourceType: "snapshot"}
   162  		tagspec.LoadingEc2Tags(item.Tags)
   163  
   164  		snapshot := SSnapshot{}
   165  		snapshot.SnapshotId = *item.SnapshotId
   166  		snapshot.Status = SnapshotStatusType(*item.State)
   167  		snapshot.region = self
   168  		snapshot.Progress = *item.Progress
   169  		snapshot.SnapshotName = *item.SnapshotId
   170  		snapshot.SourceDiskId = *item.VolumeId
   171  		snapshot.SourceDiskSize = int32(*item.VolumeSize)
   172  		// snapshot.SourceDiskType
   173  		snapshot.SnapshotName = tagspec.GetNameTag()
   174  		jsonutils.Update(&snapshot.AwsTags.TagSet, item.Tags)
   175  		snapshots = append(snapshots, snapshot)
   176  	}
   177  
   178  	return snapshots, len(snapshots), nil
   179  }
   180  
   181  func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
   182  	if snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
   183  		return nil, errors.Wrap(err, "GetSnapshots")
   184  	} else if total != 1 {
   185  		return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots")
   186  	} else {
   187  		return &snapshots[0], nil
   188  	}
   189  }
   190  
   191  func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) {
   192  	params := &ec2.CreateSnapshotInput{}
   193  	if len(diskId) <= 0 {
   194  		return "", fmt.Errorf("disk id should not be empty")
   195  	} else {
   196  		params.SetVolumeId(diskId)
   197  	}
   198  
   199  	if len(name) <= 0 {
   200  		return "", fmt.Errorf("name length should great than 0")
   201  	} else {
   202  		tagspec := TagSpec{ResourceType: "snapshot"}
   203  		tagspec.SetNameTag(name)
   204  		ec2Tag, _ := tagspec.GetTagSpecifications()
   205  		params.SetTagSpecifications([]*ec2.TagSpecification{ec2Tag})
   206  	}
   207  
   208  	params.SetDescription(desc)
   209  	log.Debugf("CreateSnapshots with params %s", params)
   210  	ec2Client, err := self.getEc2Client()
   211  	if err != nil {
   212  		return "", errors.Wrap(err, "getEc2Client")
   213  	}
   214  
   215  	ret, err := ec2Client.CreateSnapshot(params)
   216  	if err != nil {
   217  		return "", errors.Wrap(err, "CreateSnapshot")
   218  	}
   219  	return StrVal(ret.SnapshotId), nil
   220  }
   221  
   222  func (self *SRegion) DeleteSnapshot(snapshotId string) error {
   223  	ec2Client, err := self.getEc2Client()
   224  	if err != nil {
   225  		return errors.Wrap(err, "getEc2Client")
   226  	}
   227  	params := &ec2.DeleteSnapshotInput{}
   228  	params.SetSnapshotId(snapshotId)
   229  	_, err = ec2Client.DeleteSnapshot(params)
   230  	return errors.Wrap(err, "DeleteSnapshot")
   231  }
   232  
   233  func (self *SSnapshot) GetProjectId() string {
   234  	return ""
   235  }