

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 删除存储卷的快照
<a name="DeletingASnapshot"></a>

可以删除存储卷的快照。例如，当您在一段时间内拍摄了存储卷的许多快照而不再需要较旧的快照时，您可能想要删除快照。由于快照是增量备份，因此删除某个快照的操作仅会删除其他快照不需要的数据。

**Topics**
+ [使用适用于 Java 的 AWS SDK 删除快照](#DeletingSnapshotsUsingJava)
+ [使用适用于.NET 的 AWS SDK 删除快照](#DeletingSnapshotsUsingDotNet)
+ [使用删除快照 AWS Tools for Windows PowerShell](#DeletingSnapshotsUsingPowerShell)

在 Amazon EBS 控制台中，您可以一次删除一个快照。有关如何使用 Amazon EBS 控制台删除快照的信息，请参阅《Amazon EC2 用户指南》**中的[删除 Amazon EBS 快照](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-deleting-snapshot.html)。

 要一次删除多个快照，您可以使用其中一个支持 Storage Gateway 操作的快照。 AWS SDKs 有关示例，请参阅 [使用适用于 Java 的 AWS SDK 删除快照](#DeletingSnapshotsUsingJava)、[使用适用于.NET 的 AWS SDK 删除快照](#DeletingSnapshotsUsingDotNet) 和 [使用删除快照 AWS Tools for Windows PowerShell](#DeletingSnapshotsUsingPowerShell)。

## 使用适用于 Java 的 AWS SDK 删除快照
<a name="DeletingSnapshotsUsingJava"></a>

如需删除与卷关联的多个快照，您可以使用编程方法。以下示例演示如何使用适用于 Java 的 AWS 软件开发工具包删除快照。如需使用示例代码，您应该熟悉 Java 控制台应用程序的运行方式。有关更多信息，请参阅《适用于 Java 的AWS 软件开发工具包开发人员指南》**中的[入门](https://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/java-dg-setup.html)。如果您只需删除少量快照，请按 [删除存储卷的快照](#DeletingASnapshot) 中所述使用控制台。

**Example : 使用适用于 Java 的 AWS SDK 删除快照**  
以下 Java 代码示例列出了网关各个卷的快照以及快照起始日期是在指定日期前还是之后。它使用适用于 Storage Gateway 和 Amazon EC2 的 Java AWS 开发工具包 API。Amazon EC2 API 包括数种处理快照的操作。  
更新代码以提供服务终端节点、您的网关的 Amazon 资源名称 (ARN) 和您想要保存快照的回溯天数。此截止日期之前拍摄的快照都将被删除。您还需要指定布尔值 `viewOnly`，该值表明是要查看要删除的快照还是实际执行快照删除。先只带 view 选项 (即将 `viewOnly` 设置为 `true`) 运行代码，看看代码会删除什么。有关可以与 Storage Gateway 配合使用的 AWS 服务终端节点列表，请参阅中的[AWS Storage Gateway 终端节点和配额*AWS 一般参考*](https://docs.aws.amazon.com/general/latest/gr/sg.html)。  

```
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DeleteSnapshotRequest;
import com.amazonaws.services.ec2.model.DescribeSnapshotsRequest;
import com.amazonaws.services.ec2.model.DescribeSnapshotsResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.storagegateway.AWSStorageGatewayClient;
import com.amazonaws.services.storagegateway.model.ListVolumesRequest;
import com.amazonaws.services.storagegateway.model.ListVolumesResult;
import com.amazonaws.services.storagegateway.model.VolumeInfo;

public class ListDeleteVolumeSnapshotsExample {

    public static AWSStorageGatewayClient sgClient;
    public static AmazonEC2Client ec2Client;    
    static String serviceURLSG = "https://storagegateway.us-east-1.amazonaws.com";
    static String serviceURLEC2 = "https://ec2.us-east-1.amazonaws.com"; 
    
    // The gatewayARN
    public static String gatewayARN = "*** provide gateway ARN ***";
    
    // The number of days back you want to save snapshots. Snapshots before this cutoff are deleted
    // if viewOnly = false.
    public static int daysBack = 10;
    
    // true = show what will be deleted; false = actually delete snapshots that meet the daysBack criteria
    public static boolean viewOnly = true;

    public static void main(String[] args) throws IOException {

        // Create a Storage Gateway and amazon ec2 client
        sgClient = new AWSStorageGatewayClient(new PropertiesCredentials(
                ListDeleteVolumeSnapshotsExample.class.getResourceAsStream("AwsCredentials.properties")));    
        sgClient.setEndpoint(serviceURLSG);
        
        ec2Client = new AmazonEC2Client(new PropertiesCredentials(
                ListDeleteVolumeSnapshotsExample.class.getResourceAsStream("AwsCredentials.properties")));
        ec2Client.setEndpoint(serviceURLEC2);        
        
        List<VolumeInfo> volumes = ListVolumesForGateway();
        DeleteSnapshotsForVolumes(volumes, daysBack);        
        
    }
    public static List<VolumeInfo> ListVolumesForGateway()
    {
        List<VolumeInfo> volumes = new ArrayList<VolumeInfo>();

        String marker = null;
        do {
            ListVolumesRequest request = new ListVolumesRequest().withGatewayARN(gatewayARN);
            ListVolumesResult result = sgClient.listVolumes(request);
            marker = result.getMarker();
            
            for (VolumeInfo vi : result.getVolumeInfos())
            {
                volumes.add(vi);
                System.out.println(OutputVolumeInfo(vi));
            }           
        } while (marker != null);

        return volumes;
    }
    private static void DeleteSnapshotsForVolumes(List<VolumeInfo> volumes,
            int daysBack2) {
        
        // Find snapshots and delete for each volume 
        for (VolumeInfo vi : volumes) {
            
            String volumeARN = vi.getVolumeARN();
            String volumeId = volumeARN.substring(volumeARN.lastIndexOf("/")+1).toLowerCase();
            Collection<Filter> filters = new ArrayList<Filter>();
            Filter filter = new Filter().withName("volume-id").withValues(volumeId);
            filters.add(filter);
            
            DescribeSnapshotsRequest describeSnapshotsRequest =
                new DescribeSnapshotsRequest().withFilters(filters);
            DescribeSnapshotsResult describeSnapshotsResult =
                ec2Client.describeSnapshots(describeSnapshotsRequest);
            
            List<Snapshot> snapshots = describeSnapshotsResult.getSnapshots();
            System.out.println("volume-id = " + volumeId);
            for (Snapshot s : snapshots){
                StringBuilder sb = new StringBuilder();
                boolean meetsCriteria = !CompareDates(daysBack, s.getStartTime());
                sb.append(s.getSnapshotId() + ", " + s.getStartTime().toString());                
                sb.append(", meets criteria for delete? " + meetsCriteria);
                sb.append(", deleted? ");
                if (!viewOnly & meetsCriteria) {
                    sb.append("yes");
                    DeleteSnapshotRequest deleteSnapshotRequest = 
                        new DeleteSnapshotRequest().withSnapshotId(s.getSnapshotId());
                    ec2Client.deleteSnapshot(deleteSnapshotRequest);
                }
                else {
                    sb.append("no");
                }
                System.out.println(sb.toString());                    
            }        
        }
    }

    private static String OutputVolumeInfo(VolumeInfo vi) {
        
        String volumeInfo = String.format(
                 "Volume Info:\n" + 
                 "  ARN: %s\n" +
                 "  Type: %s\n",
                 vi.getVolumeARN(),
                 vi.getVolumeType());
        return volumeInfo; 
     }
    
    // Returns the date in two formats as a list
    public static boolean CompareDates(int daysBack, Date snapshotDate) {
        Date today = new Date();
        Calendar cal = new GregorianCalendar();
        cal.setTime(today);
        cal.add(Calendar.DAY_OF_MONTH, -daysBack);
        Date cutoffDate = cal.getTime();        
        return (snapshotDate.compareTo(cutoffDate) > 0) ? true : false;
    }

}
```

## 使用适用于.NET 的 AWS SDK 删除快照
<a name="DeletingSnapshotsUsingDotNet"></a>

如需删除与卷关联的多个快照，您可以使用编程方法。以下示例演示如何使用适用于 .NET 的 AWS 软件开发工具包版本 2 和 3 删除快照。如需使用示例代码，您应该熟悉 .NET 控制台应用程序的运行方式。有关更多信息，请参阅《适用于 .NET 的AWS 软件开发工具包开发人员指南》**中的[入门](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-config.html)。如果您只需删除少量快照，请按 [删除存储卷的快照](#DeletingASnapshot) 中所述使用控制台。

**Example : 使用适用于.NET 的 AWS SDK 删除快照**  
在以下 C\$1 代码示例中， AWS Identity and Access Management 用户可以列出网关每个卷的快照。然后，该用户可以判断快照的起始时间是在指定日期 (保留期) 之前还是之后，并删除过了保留期的快照。该示例使用适用于 Storage Gateway 和 Amazon EC2 的.NET AWS 开发工具包 API。Amazon EC2 API 包括数种处理快照的操作。  
以下代码示例使用适用于.NET 的 AWS SDK 版本 2 和 3。您可以将旧版本的 .NET 迁移到新版本。有关更多信息，请参阅[迁移适用于.NET 的 AWS SDK 的项目](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-migrating.html)。  
更新代码以提供服务终端节点、您的网关的 Amazon 资源名称 (ARN) 和您想要保存快照的回溯天数。此截止日期之前拍摄的快照都将被删除。您还需要指定布尔值 `viewOnly`，该值表明是要查看要删除的快照还是实际执行快照删除。先只带 view 选项 (即将 `viewOnly` 设置为 `true`) 运行代码，看看代码会删除什么。有关可以与 Storage Gateway 配合使用的 AWS 服务终端节点列表，请参阅中的[AWS Storage Gateway 终端节点和配额*AWS 一般参考*](https://docs.aws.amazon.com/general/latest/gr/sg.html)。  
 首先，创建一个用户并将最小 IAM 策略附加到该用户。然后为您的网关制定自动快照计划。  
以下代码创建允许用户删除快照的最小权限策略。在本示例中，策略的名称为 **sgw-delete-snapshot**。    
****  

```
{
      "Version":"2012-10-17",		 	 	 
      "Statement": [
          {
              "Sid": "StmtEC2Snapshots",
              "Effect": "Allow",
              "Action": [
                  "ec2:DeleteSnapshot",
                  "ec2:DescribeSnapshots"
              ],
              "Resource": [
                  "*"
              ]
          },
          {
              "Sid": "StmtSgwListVolumes",
              "Effect": "Allow",
              "Action": [
                  "storagegateway:ListVolumes"
              ],
              "Resource": [
                  "*"
              ]
          }
      ]
  }
```
以下 C\$1 代码在指定网关中查找与卷和指定截止期匹配的所有快照并将其删除。  

```
using System;
using System.Collections.Generic;
using System.Text;
using Amazon.EC2;
using Amazon.EC2.Model;
using Amazon.StorageGateway.Model;
using Amazon.StorageGateway;

namespace DeleteStorageGatewaySnapshotNS
{
    class Program
    {
        /*
         * Replace the variables below to match your environment.
         */
         
         /* IAM AccessKey */
        static String AwsAccessKey = "AKIA................";
        
        /* IAM SecretKey */
        static String AwsSecretKey = "*******************************";
        
        /* Account number, 12 digits, no hyphen */
        static String OwnerID = "123456789012";
        
        /* Your Gateway ARN. Use a Storage Gateway ID, sgw-XXXXXXXX* */ 
        static String GatewayARN = "arn:aws:storagegateway:ap-southeast-2:123456789012:gateway/sgw-XXXXXXXX";
        
        /* Snapshot status: "completed", "pending", "error" */                                                                                                      
        static String SnapshotStatus = "completed";
        
        /* Region where your gateway is activated */ 
        static String AwsRegion = "ap-southeast-2";
        
        /* Minimum age of snapshots before they are deleted (retention policy) */
        static int daysBack = 30; 

        /*
         * Do not modify the four lines below.
         */
        static AmazonEC2Config ec2Config;
        static AmazonEC2Client ec2Client;
        static AmazonStorageGatewayClient sgClient;
        static AmazonStorageGatewayConfig sgConfig;

        static void Main(string[] args)
        {
            // Create an EC2 client.
            ec2Config = new AmazonEC2Config();
            ec2Config.ServiceURL = "https://ec2." + AwsRegion + ".amazonaws.com";
            ec2Client = new AmazonEC2Client(AwsAccessKey, AwsSecretKey, ec2Config);

            // Create a Storage Gateway client.
            sgConfig = new AmazonStorageGatewayConfig();
            sgConfig.ServiceURL = "https://storagegateway." + AwsRegion + ".amazonaws.com";
            sgClient = new AmazonStorageGatewayClient(AwsAccessKey, AwsSecretKey, sgConfig);

            List<VolumeInfo> StorageGatewayVolumes = ListVolumesForGateway();
            List<Snapshot> StorageGatewaySnapshots = ListSnapshotsForVolumes(StorageGatewayVolumes, 
                                                     daysBack);
            DeleteSnapshots(StorageGatewaySnapshots);
        }

        /*
         * List all volumes for your gateway
         * returns: A list of VolumeInfos, or null.
         */
        private static List<VolumeInfo> ListVolumesForGateway()
        {
            ListVolumesResponse response = new ListVolumesResponse();
            try
            {
                ListVolumesRequest request = new ListVolumesRequest();
                request.GatewayARN = GatewayARN;
                response = sgClient.ListVolumes(request);

                foreach (VolumeInfo vi in response.VolumeInfos)
                {
                    Console.WriteLine(OutputVolumeInfo(vi));
                }
            }
            catch (AmazonStorageGatewayException ex)
            {
                Console.WriteLine(ex.Message);
            }
            return response.VolumeInfos;
        }

        /*
         * Gets the list of snapshots that match the requested volumes
         * and cutoff period.
         */
        private static List<Snapshot> ListSnapshotsForVolumes(List<VolumeInfo> volumes, int snapshotAge)
        {
            List<Snapshot> SelectedSnapshots = new List<Snapshot>();
            try
            {
                foreach (VolumeInfo vi in volumes)
                {
                    String volumeARN = vi.VolumeARN;
                    String volumeID = volumeARN.Substring(volumeARN.LastIndexOf("/") + 1).ToLower();

                    DescribeSnapshotsRequest describeSnapshotsRequest = new DescribeSnapshotsRequest();

                    Filter ownerFilter = new Filter();
                    List<String> ownerValues = new List<String>();
                    ownerValues.Add(OwnerID);
                    ownerFilter.Name = "owner-id";
                    ownerFilter.Values = ownerValues;
                    describeSnapshotsRequest.Filters.Add(ownerFilter);

                    Filter statusFilter = new Filter();
                    List<String> statusValues = new List<String>();
                    statusValues.Add(SnapshotStatus);
                    statusFilter.Name = "status";
                    statusFilter.Values = statusValues;
                    describeSnapshotsRequest.Filters.Add(statusFilter);

                    Filter volumeFilter = new Filter();
                    List<String> volumeValues = new List<String>();
                    volumeValues.Add(volumeID);
                    volumeFilter.Name = "volume-id";
                    volumeFilter.Values = volumeValues;
                    describeSnapshotsRequest.Filters.Add(volumeFilter);

                    DescribeSnapshotsResponse describeSnapshotsResponse = 
                      ec2Client.DescribeSnapshots(describeSnapshotsRequest);

                    List<Snapshot> snapshots = describeSnapshotsResponse.Snapshots;
                    Console.WriteLine("volume-id = " + volumeID);
                    foreach (Snapshot s in snapshots)
                    {
                        if (IsSnapshotPastRetentionPeriod(snapshotAge, s.StartTime))
                        {
                            Console.WriteLine(s.SnapshotId + ", " + s.VolumeId + ", 
                               " + s.StartTime + ", " + s.Description);
                            SelectedSnapshots.Add(s);
                        }
                    }
                }
            }
            catch (AmazonEC2Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return SelectedSnapshots;
        }

        /*
         * Deletes a list of snapshots.
         */
        private static void DeleteSnapshots(List<Snapshot> snapshots)
        {
            try
            {
                foreach (Snapshot s in snapshots)
                {

                    DeleteSnapshotRequest deleteSnapshotRequest = new DeleteSnapshotRequest(s.SnapshotId);
                    DeleteSnapshotResponse response = ec2Client.DeleteSnapshot(deleteSnapshotRequest);
                    Console.WriteLine("Volume: " +
                              s.VolumeId +
                              " => Snapshot: " +
                              s.SnapshotId +
                              " Response: "
                              + response.HttpStatusCode.ToString());
                }
            }
            catch (AmazonEC2Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /*
         * Checks if the snapshot creation date is past the retention period.
         */
        private static Boolean IsSnapshotPastRetentionPeriod(int daysBack, DateTime snapshotDate)
        {
            DateTime cutoffDate = DateTime.Now.Add(new TimeSpan(-daysBack, 0, 0, 0));
            return (DateTime.Compare(snapshotDate, cutoffDate) < 0) ? true : false;
        }

        /*
         * Displays information related to a volume.
         */
        private static String OutputVolumeInfo(VolumeInfo vi)
        {
            String volumeInfo = String.Format(
                "Volume Info:\n" +
                "  ARN: {0}\n" +
                "  Type: {1}\n",
                vi.VolumeARN,
                vi.VolumeType);
            return volumeInfo;
        }
    }
}
```

## 使用删除快照 AWS Tools for Windows PowerShell
<a name="DeletingSnapshotsUsingPowerShell"></a>

如需删除与卷关联的多个快照，您可以使用编程方法。以下示例演示如何使用 AWS Tools for Windows PowerShell删除快照。要使用示例脚本，您应该熟悉如何运行 PowerShell 脚本。有关更多信息，请参阅 [https://docs.aws.amazon.com/powershell/latest/userguide/pstools-getting-started.html](https://docs.aws.amazon.com/powershell/latest/userguide/pstools-getting-started.html)* 中的AWS Tools for Windows PowerShell入门*。如果您只需要删除少量快照，请按 [删除存储卷的快照](#DeletingASnapshot) 中所述使用控制台。

**Example : 使用删除快照 AWS Tools for Windows PowerShell**  
以下 PowerShell 脚本示例列出了网关每个卷的快照以及快照开始时间是在指定日期之前还是之后。它使用 Storage Gateway 和 Amazon EC2 的 AWS Tools for Windows PowerShell cmdlet。Amazon EC2 API 包括数种处理快照的操作。  
您需要更新脚本并提供您的网关的 Amazon 资源名称 (ARN) 和想要保存快照的回溯天数。此截止日期之前拍摄的快照都将被删除。您还需要指定布尔值 `viewOnly`，该值表明是要查看要删除的快照还是实际执行快照删除。先只带 view 选项 (即将 `viewOnly` 设置为 `true`) 运行代码，看看代码会删除什么。  

```
<#
.DESCRIPTION
    Delete snapshots of a specified volume that match given criteria.
    
.NOTES
    PREREQUISITES:
    1) AWS Tools for Windows PowerShell from https://aws.amazon.com/powershell/
    2) Credentials and AWS Region stored in session using Initialize-AWSDefault.
    For more info see, https://docs.aws.amazon.com/powershell/latest/userguide/specifying-your-aws-credentials.html 

.EXAMPLE
    powershell.exe .\SG_DeleteSnapshots.ps1  
#>

# Criteria to use to filter the results returned.
$daysBack = 18
$gatewayARN = "*** provide gateway ARN ***"
$viewOnly = $true;

#ListVolumes
$volumesResult = Get-SGVolume -GatewayARN $gatewayARN
$volumes = $volumesResult.VolumeInfos
Write-Output("`nVolume List")
foreach ($volumes in $volumesResult)
  { Write-Output("`nVolume Info:")
    Write-Output("ARN:  " + $volumes.VolumeARN)
    write-Output("Type: " + $volumes.VolumeType)
  }

Write-Output("`nWhich snapshots meet the criteria?")
foreach ($volume in $volumesResult)
  { 
    $volumeARN = $volume.VolumeARN
    
    $volumeId = ($volumeARN-split"/")[3].ToLower()
  
    $filter = New-Object Amazon.EC2.Model.Filter
    $filter.Name = "volume-id"
    $filter.Value.Add($volumeId)
    
    $snapshots = get-EC2Snapshot -Filter $filter    
    Write-Output("`nFor volume-id = " + $volumeId)
    foreach ($s in $snapshots)
    {
       $d = ([DateTime]::Now).AddDays(-$daysBack)
       $meetsCriteria = $false
       if ([DateTime]::Compare($d, $s.StartTime) -gt 0)
       {
            $meetsCriteria = $true
       }
       
       $sb = $s.SnapshotId + ", " + $s.StartTime + ", meets criteria for delete? " + $meetsCriteria
       if (!$viewOnly -AND $meetsCriteria) 
       {
           $resp = Remove-EC2Snapshot -SnapshotId $s.SnapshotId
           #Can get RequestId from response for troubleshooting.
           $sb = $sb + ", deleted? yes"
       }
       else {
           $sb = $sb + ", deleted? no"
       }
       Write-Output($sb) 
    }
  }
```