Skip to content

Commit

Permalink
Merge branch 'release-1.10.7'
Browse files Browse the repository at this point in the history
* release-1.10.7:
  Bumping version to 1.10.7
  Add route53 to changelog
  Update changelog with latest changes
  Handle empty sections when using configure set command
  Break the configure model into several distinct files.
  add .python-version to gitignore
  • Loading branch information
AWS committed Feb 23, 2016
2 parents 67cb452 + f4caa0b commit f04e5d4
Show file tree
Hide file tree
Showing 22 changed files with 1,481 additions and 1,283 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ doc/source/aws_man_pages.json
doc/source/reference
doc/source/topic
doc/source/tutorial/services.rst

# Pyenv
.python-version

9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
CHANGELOG
=========

1.10.7
======

* bug:``aws configure set``: Fix issue when adding entries to
an empty profile section
(`issue 1806 <https://github.com/aws/aws-cli/pull/1806>`__)
* feature:``aws route53``: Add suport for SNI health checks


1.10.6
======
* feature:``aws storagegateway``: Added support for user-supplied barcodes.
Expand Down
2 changes: 1 addition & 1 deletion awscli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"""
import os

__version__ = '1.10.6'
__version__ = '1.10.7'

#
# Get our data path to be added to botocore's search path
Expand Down
571 changes: 3 additions & 568 deletions awscli/customizations/configure/__init__.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion awscli/customizations/configure/addmodel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
Expand Down
141 changes: 141 additions & 0 deletions awscli/customizations/configure/configure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import os
import logging

from botocore.exceptions import ProfileNotFound

from awscli.compat import raw_input
from awscli.customizations.commands import BasicCommand
from awscli.customizations.configure.addmodel import AddModelCommand
from awscli.customizations.configure.set import ConfigureSetCommand
from awscli.customizations.configure.get import ConfigureGetCommand
from awscli.customizations.configure.list import ConfigureListCommand
from awscli.customizations.configure.writer import ConfigFileWriter

from . import mask_value


logger = logging.getLogger(__name__)


def register_configure_cmd(cli):
cli.register('building-command-table.main',
ConfigureCommand.add_command)


class InteractivePrompter(object):

def get_value(self, current_value, config_name, prompt_text=''):
if config_name in ('aws_access_key_id', 'aws_secret_access_key'):
current_value = mask_value(current_value)
response = raw_input("%s [%s]: " % (prompt_text, current_value))
if not response:
# If the user hits enter, we return a value of None
# instead of an empty string. That way we can determine
# whether or not a value has changed.
response = None
return response


class ConfigureCommand(BasicCommand):
NAME = 'configure'
DESCRIPTION = BasicCommand.FROM_FILE()
SYNOPSIS = ('aws configure [--profile profile-name]')
EXAMPLES = (
'To create a new configuration::\n'
'\n'
' $ aws configure\n'
' AWS Access Key ID [None]: accesskey\n'
' AWS Secret Access Key [None]: secretkey\n'
' Default region name [None]: us-west-2\n'
' Default output format [None]:\n'
'\n'
'To update just the region name::\n'
'\n'
' $ aws configure\n'
' AWS Access Key ID [****]:\n'
' AWS Secret Access Key [****]:\n'
' Default region name [us-west-1]: us-west-2\n'
' Default output format [None]:\n'
)
SUBCOMMANDS = [
{'name': 'list', 'command_class': ConfigureListCommand},
{'name': 'get', 'command_class': ConfigureGetCommand},
{'name': 'set', 'command_class': ConfigureSetCommand},
{'name': 'add-model', 'command_class': AddModelCommand}
]

# If you want to add new values to prompt, update this list here.
VALUES_TO_PROMPT = [
# (logical_name, config_name, prompt_text)
('aws_access_key_id', "AWS Access Key ID"),
('aws_secret_access_key', "AWS Secret Access Key"),
('region', "Default region name"),
('output', "Default output format"),
]

def __init__(self, session, prompter=None, config_writer=None):
super(ConfigureCommand, self).__init__(session)
if prompter is None:
prompter = InteractivePrompter()
self._prompter = prompter
if config_writer is None:
config_writer = ConfigFileWriter()
self._config_writer = config_writer

def _run_main(self, parsed_args, parsed_globals):
# Called when invoked with no args "aws configure"
new_values = {}
# This is the config from the config file scoped to a specific
# profile.
try:
config = self._session.get_scoped_config()
except ProfileNotFound:
config = {}
for config_name, prompt_text in self.VALUES_TO_PROMPT:
current_value = config.get(config_name)
new_value = self._prompter.get_value(current_value, config_name,
prompt_text)
if new_value is not None and new_value != current_value:
new_values[config_name] = new_value
config_filename = os.path.expanduser(
self._session.get_config_variable('config_file'))
if new_values:
self._write_out_creds_file_values(new_values,
parsed_globals.profile)
if parsed_globals.profile is not None:
new_values['__section__'] = (
'profile %s' % parsed_globals.profile)
self._config_writer.update_config(new_values, config_filename)

def _write_out_creds_file_values(self, new_values, profile_name):
# The access_key/secret_key are now *always* written to the shared
# credentials file (~/.aws/credentials), see aws/aws-cli#847.
# post-conditions: ~/.aws/credentials will have the updated credential
# file values and new_values will have the cred vars removed.
credential_file_values = {}
if 'aws_access_key_id' in new_values:
credential_file_values['aws_access_key_id'] = new_values.pop(
'aws_access_key_id')
if 'aws_secret_access_key' in new_values:
credential_file_values['aws_secret_access_key'] = new_values.pop(
'aws_secret_access_key')
if credential_file_values:
if profile_name is not None:
credential_file_values['__section__'] = profile_name
shared_credentials_filename = os.path.expanduser(
self._session.get_config_variable('credentials_file'))
self._config_writer.update_config(
credential_file_values,
shared_credentials_filename)
89 changes: 89 additions & 0 deletions awscli/customizations/configure/get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import sys

from awscli.customizations.commands import BasicCommand

from . import PREDEFINED_SECTION_NAMES


class ConfigureGetCommand(BasicCommand):
NAME = 'get'
DESCRIPTION = BasicCommand.FROM_FILE('configure', 'get',
'_description.rst')
SYNOPSIS = ('aws configure get varname [--profile profile-name]')
EXAMPLES = BasicCommand.FROM_FILE('configure', 'get', '_examples.rst')
ARG_TABLE = [
{'name': 'varname',
'help_text': 'The name of the config value to retrieve.',
'action': 'store',
'cli_type_name': 'string', 'positional_arg': True},
]

def __init__(self, session, stream=sys.stdout):
super(ConfigureGetCommand, self).__init__(session)
self._stream = stream

def _run_main(self, args, parsed_globals):
varname = args.varname
value = None
if '.' not in varname:
# get_scoped_config() returns the config variables in the config
# file (not the logical_var names), which is what we want.
config = self._session.get_scoped_config()
value = config.get(varname)
else:
value = self._get_dotted_config_value(varname)
if value is not None:
self._stream.write(value)
self._stream.write('\n')
return 0
else:
return 1

def _get_dotted_config_value(self, varname):
parts = varname.split('.')
num_dots = varname.count('.')
# Logic to deal with predefined sections like [preview], [plugin] and etc.
if num_dots == 1 and parts[0] in PREDEFINED_SECTION_NAMES:
full_config = self._session.full_config
section, config_name = varname.split('.')
value = full_config.get(section, {}).get(config_name)
if value is None:
# Try to retrieve it from the profile config.
value = full_config['profiles'].get(
section, {}).get(config_name)
return value
if parts[0] == 'profile':
profile_name = parts[1]
config_name = parts[2]
remaining = parts[3:]
# Check if varname starts with 'default' profile (e.g. default.emr-dev.emr.instance_profile)
# If not, go further to check if varname starts with a known profile name
elif parts[0] == 'default' or (parts[0] in self._session.full_config['profiles']):
profile_name = parts[0]
config_name = parts[1]
remaining = parts[2:]
else:
profile_name = self._session.get_config_variable('profile')
config_name = parts[0]
remaining = parts[1:]

value = self._session.full_config['profiles'].get(
profile_name, {}).get(config_name)
if len(remaining) == 1:
try:
value = value.get(remaining[-1])
except AttributeError:
value = None
return value
119 changes: 119 additions & 0 deletions awscli/customizations/configure/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import sys

from awscli.customizations.commands import BasicCommand

from . import ConfigValue, NOT_SET


class ConfigureListCommand(BasicCommand):
NAME = 'list'
DESCRIPTION = (
'List the AWS CLI configuration data. This command will '
'show you the current configuration data. For each configuration '
'item, it will show you the value, where the configuration value '
'was retrieved, and the configuration variable name. For example, '
'if you provide the AWS region in an environment variable, this '
'command will show you the name of the region you\'ve configured, '
'it will tell you that this value came from an environment '
'variable, and it will tell you the name of the environment '
'variable.\n'
)
SYNOPSIS = 'aws configure list [--profile profile-name]'
EXAMPLES = (
'To show your current configuration values::\n'
'\n'
' $ aws configure list\n'
' Name Value Type Location\n'
' ---- ----- ---- --------\n'
' profile <not set> None None\n'
' access_key ****************ABCD config_file ~/.aws/config\n'
' secret_key ****************ABCD config_file ~/.aws/config\n'
' region us-west-2 env AWS_DEFAULT_REGION\n'
'\n'
)

def __init__(self, session, stream=sys.stdout):
super(ConfigureListCommand, self).__init__(session)
self._stream = stream

def _run_main(self, args, parsed_globals):
self._display_config_value(ConfigValue('Value', 'Type', 'Location'),
'Name')
self._display_config_value(ConfigValue('-----', '----', '--------'),
'----')

if self._session.profile is not None:
profile = ConfigValue(self._session.profile, 'manual',
'--profile')
else:
profile = self._lookup_config('profile')
self._display_config_value(profile, 'profile')

access_key, secret_key = self._lookup_credentials()
self._display_config_value(access_key, 'access_key')
self._display_config_value(secret_key, 'secret_key')

region = self._lookup_config('region')
self._display_config_value(region, 'region')

def _display_config_value(self, config_value, config_name):
self._stream.write('%10s %24s %16s %s\n' % (
config_name, config_value.value, config_value.config_type,
config_value.config_variable))

def _lookup_credentials(self):
# First try it with _lookup_config. It's possible
# that we don't find credentials this way (for example,
# if we're using an IAM role).
access_key = self._lookup_config('access_key')
if access_key.value is not NOT_SET:
secret_key = self._lookup_config('secret_key')
access_key.mask_value()
secret_key.mask_value()
return access_key, secret_key
else:
# Otherwise we can try to use get_credentials().
# This includes a few more lookup locations
# (IAM roles, some of the legacy configs, etc.)
credentials = self._session.get_credentials()
if credentials is None:
no_config = ConfigValue(NOT_SET, None, None)
return no_config, no_config
else:
# For the ConfigValue, we don't track down the
# config_variable because that info is not
# visible from botocore.credentials. I think
# the credentials.method is sufficient to show
# where the credentials are coming from.
access_key = ConfigValue(credentials.access_key,
credentials.method, '')
secret_key = ConfigValue(credentials.secret_key,
credentials.method, '')
access_key.mask_value()
secret_key.mask_value()
return access_key, secret_key

def _lookup_config(self, name):
# First try to look up the variable in the env.
value = self._session.get_config_variable(name, methods=('env',))
if value is not None:
return ConfigValue(value, 'env', self._session.session_var_map[name][1])
# Then try to look up the variable in the config file.
value = self._session.get_config_variable(name, methods=('config',))
if value is not None:
return ConfigValue(value, 'config-file',
self._session.get_config_variable('config_file'))
else:
return ConfigValue(NOT_SET, None, None)
Loading

0 comments on commit f04e5d4

Please sign in to comment.