Path: blob/develop/awscli/customizations/ec2/bundleinstance.py
1567 views
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.1#2# Licensed under the Apache License, Version 2.0 (the "License"). You3# may not use this file except in compliance with the License. A copy of4# the License is located at5#6# http://aws.amazon.com/apache2.0/7#8# or in the "license" file accompanying this file. This file is9# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF10# ANY KIND, either express or implied. See the License for the specific11# language governing permissions and limitations under the License.1213import logging14from hashlib import sha115import hmac16import base6417import datetime1819from awscli.arguments import CustomArgument20from awscli.compat import get_current_datetime2122logger = logging.getLogger('ec2bundleinstance')2324# This customization adds the following scalar parameters to the25# bundle-instance operation:2627# --bucket:28BUCKET_DOCS = ('The bucket in which to store the AMI. '29'You can specify a bucket that you already own or '30'a new bucket that Amazon EC2 creates on your behalf. '31'If you specify a bucket that belongs to someone else, '32'Amazon EC2 returns an error.')3334# --prefix:35PREFIX_DOCS = ('The prefix for the image component names being stored '36'in Amazon S3.')3738# --owner-akid39OWNER_AKID_DOCS = 'The access key ID of the owner of the Amazon S3 bucket.'4041# --policy42POLICY_DOCS = (43"An Amazon S3 upload policy that gives "44"Amazon EC2 permission to upload items into Amazon S3 "45"on the user's behalf. If you provide this parameter, "46"you must also provide "47"your secret access key, so we can create a policy "48"signature for you (the secret access key is not passed "49"to Amazon EC2). If you do not provide this parameter, "50"we generate an upload policy for you automatically. "51"For more information about upload policies see the "52"sections about policy construction and signatures in the "53'<a href="http://docs.aws.amazon.com/AmazonS3/latest/dev'54'/HTTPPOSTForms.html">'55'Amazon Simple Storage Service Developer Guide</a>.')5657# --owner-sak58OWNER_SAK_DOCS = ('The AWS secret access key for the owner of the '59'Amazon S3 bucket specified in the --bucket '60'parameter. This parameter is required so that a '61'signature can be computed for the policy.')626364def _add_params(argument_table, **kwargs):65# Add the scalar parameters and also change the complex storage66# param to not be required so the user doesn't get an error from67# argparse if they only supply scalar params.68storage_arg = argument_table['storage']69storage_arg.required = False70arg = BundleArgument(storage_param='Bucket',71name='bucket',72help_text=BUCKET_DOCS)73argument_table['bucket'] = arg74arg = BundleArgument(storage_param='Prefix',75name='prefix',76help_text=PREFIX_DOCS)77argument_table['prefix'] = arg78arg = BundleArgument(storage_param='AWSAccessKeyId',79name='owner-akid',80help_text=OWNER_AKID_DOCS)81argument_table['owner-akid'] = arg82arg = BundleArgument(storage_param='_SAK',83name='owner-sak',84help_text=OWNER_SAK_DOCS)85argument_table['owner-sak'] = arg86arg = BundleArgument(storage_param='UploadPolicy',87name='policy',88help_text=POLICY_DOCS)89argument_table['policy'] = arg909192def _check_args(parsed_args, **kwargs):93# This function checks the parsed args. If the user specified94# the --ip-permissions option with any of the scalar options we95# raise an error.96logger.debug(parsed_args)97arg_dict = vars(parsed_args)98if arg_dict['storage']:99for key in ('bucket', 'prefix', 'owner_akid',100'owner_sak', 'policy'):101if arg_dict[key]:102msg = ('Mixing the --storage option '103'with the simple, scalar options is '104'not recommended.')105raise ValueError(msg)106107POLICY = ('{{"expiration": "{expires}",'108'"conditions": ['109'{{"bucket": "{bucket}"}},'110'{{"acl": "ec2-bundle-read"}},'111'["starts-with", "$key", "{prefix}"]'112']}}'113)114115116def _generate_policy(params):117# Called if there is no policy supplied by the user.118# Creates a policy that provides access for 24 hours.119delta = datetime.timedelta(hours=24)120expires = get_current_datetime() + delta121expires_iso = expires.strftime("%Y-%m-%dT%H:%M:%S.%fZ")122policy = POLICY.format(expires=expires_iso,123bucket=params['Bucket'],124prefix=params['Prefix'])125params['UploadPolicy'] = policy126127128def _generate_signature(params):129# If we have a policy and a sak, create the signature.130policy = params.get('UploadPolicy')131sak = params.get('_SAK')132if policy and sak:133policy = base64.b64encode(policy.encode('latin-1')).decode('utf-8')134new_hmac = hmac.new(sak.encode('utf-8'), digestmod=sha1)135new_hmac.update(policy.encode('latin-1'))136ps = base64.encodebytes(new_hmac.digest()).strip().decode('utf-8')137params['UploadPolicySignature'] = ps138del params['_SAK']139140141def _check_params(params, **kwargs):142# Called just before call but prior to building the params.143# Adds information not supplied by the user.144storage = params['Storage']['S3']145if 'UploadPolicy' not in storage:146_generate_policy(storage)147if 'UploadPolicySignature' not in storage:148_generate_signature(storage)149150151EVENTS = [152('building-argument-table.ec2.bundle-instance', _add_params),153('operation-args-parsed.ec2.bundle-instance', _check_args),154('before-parameter-build.ec2.BundleInstance', _check_params),155]156157158def register_bundleinstance(event_handler):159# Register all of the events for customizing BundleInstance160for event, handler in EVENTS:161event_handler.register(event, handler)162163164class BundleArgument(CustomArgument):165166def __init__(self, storage_param, *args, **kwargs):167super(BundleArgument, self).__init__(*args, **kwargs)168self._storage_param = storage_param169170def _build_storage(self, params, value):171# Build up the Storage data structure172if 'Storage' not in params:173params['Storage'] = {'S3': {}}174params['Storage']['S3'][self._storage_param] = value175176def add_to_params(self, parameters, value):177if value:178self._build_storage(parameters, value)179180181