-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for "config get/set" command #603
Changes from 3 commits
c57043b
dfad2b7
919b241
eb08db9
ab0f2c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,6 @@ | |
import sys | ||
import logging | ||
|
||
import six | ||
from botocore.exceptions import ProfileNotFound | ||
|
||
from awscli.customizations.commands import BasicCommand | ||
|
@@ -103,7 +102,7 @@ def _create_file(self, config_filename): | |
if not os.path.isdir(dirname): | ||
os.makedirs(dirname) | ||
with os.fdopen(os.open(config_filename, | ||
os.O_WRONLY|os.O_CREAT, 0o600), 'w') as f: | ||
os.O_WRONLY|os.O_CREAT, 0o600), 'w'): | ||
pass | ||
|
||
def _write_new_section(self, section_name, new_values, config_filename): | ||
|
@@ -115,9 +114,11 @@ def _write_new_section(self, section_name, new_values, config_filename): | |
def _update_section_contents(self, contents, section_name, new_values): | ||
new_values = new_values.copy() | ||
# contents is a list of file line contents. | ||
start_index = 0 | ||
for i in range(len(contents)): | ||
line = contents[i] | ||
if line.strip().startswith(('#', ';')): | ||
# This is a comment, so we can safely ignore this line. | ||
continue | ||
match = self.SECTION_REGEX.search(line) | ||
if match is not None and self._matches_section(match, | ||
section_name): | ||
|
@@ -259,21 +260,113 @@ def _lookup_credentials(self): | |
|
||
def _lookup_config(self, name): | ||
# First try to look up the variable in the env. | ||
value = self._session.get_variable(name, methods=('env',)) | ||
value = self._session.get_config_variable(name, methods=('env',)) | ||
if value is not None: | ||
return ConfigValue(value, 'env', self._session.env_vars[name][1]) | ||
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_variable(name, methods=('config',)) | ||
value = self._session.get_config_variable(name, methods=('config',)) | ||
if value is not None: | ||
return ConfigValue(value, 'config_file', | ||
self._session.get_variable('config_file')) | ||
self._session.get_config_variable('config_file')) | ||
else: | ||
return ConfigValue(NOT_SET, None, None) | ||
|
||
class ConfigureSetCommand(BasicCommand): | ||
NAME = 'set' | ||
DESCRIPTION = BasicCommand.FROM_FILE('configure', 'set', | ||
'_description.rst') | ||
SYNOPSIS = ('aws configure set varname value [--profile profile-name]') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the parens here? It's not a tuple (no trailing comma)... |
||
EXAMPLES = BasicCommand.FROM_FILE('configure', 'set', '_examples.rst') | ||
ARG_TABLE = [ | ||
{'name': 'varname', | ||
'help_text': 'The name of the config value to set.', | ||
'action': 'store', | ||
'cli_type_name': 'string', 'positional_arg': True}, | ||
{'name': 'value', | ||
'help_text': 'The value to set.', | ||
'action': 'store', | ||
'cli_type_name': 'string', 'positional_arg': True}, | ||
] | ||
|
||
def __init__(self, session, config_writer=None): | ||
super(ConfigureSetCommand, self).__init__(session) | ||
if config_writer is None: | ||
config_writer = ConfigFileWriter() | ||
self._config_writer = config_writer | ||
|
||
def _run_main(self, args, parsed_globals): | ||
varname = args.varname | ||
value = args.value | ||
section = 'default' | ||
if '.' not in varname: | ||
if self._session.profile is not None: | ||
section = 'profile %s' % self._session.profile | ||
else: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this block for per-service config options? Or something else? A comment explaining what's going on would be nice. |
||
num_dots = varname.count('.') | ||
if num_dots == 1: | ||
section, varname = varname.split('.') | ||
elif num_dots == 2 and varname.startswith('profile'): | ||
dotted_section, varname = varname.rsplit('.', 1) | ||
profile = dotted_section.split('.')[1] | ||
section = 'profile %s' % profile | ||
config_filename = os.path.expanduser( | ||
self._session.get_config_variable('config_file')) | ||
updated_config = {'__section__': section, varname: value} | ||
self._config_writer.update_config(updated_config, config_filename) | ||
|
||
|
||
class ConfigureGetCommand(BasicCommand): | ||
NAME = 'get' | ||
DESCRIPTION = BasicCommand.FROM_FILE('configure', 'get', | ||
'_description.rst') | ||
SYNOPSIS = ('aws configure get varname [--profile profile-name]') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, parens but not a tuple? |
||
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_config() returns the config variables in the config | ||
# file (not the logical_var names), which is what we want. | ||
config = self._session.get_config() | ||
value = config.get(varname) | ||
else: | ||
num_dots = varname.count('.') | ||
if num_dots == 1: | ||
full_config = self._session.full_config | ||
section, config_name = varname.split('.') | ||
value = full_config.get(section, {}).get(config_name) | ||
elif num_dots == 2 and varname.startswith('profile'): | ||
# We're hard coding logic for profiles here. Really | ||
# we could support any generic format of [section subsection], | ||
# but we'd need some botocore.session changes for that, | ||
# and nothing would immediately use that feature. | ||
dot_section, config_name = varname.rsplit('.', 1) | ||
start, profile_name = dot_section.split('.') | ||
self._session.profile = profile_name | ||
config = self._session.get_config() | ||
value = config.get(config_name) | ||
if value is not None: | ||
self._stream.write(value) | ||
self._stream.write('\n') | ||
return 0 | ||
else: | ||
return 1 | ||
|
||
|
||
class ConfigureCommand(BasicCommand): | ||
NAME = 'configure' | ||
DESCRIPTION = BasicCommand.FROM_FILE | ||
DESCRIPTION = BasicCommand.FROM_FILE() | ||
SYNOPSIS = ('aws configure [--profile profile-name]') | ||
EXAMPLES = ( | ||
'To create a new configuration::\n' | ||
|
@@ -293,7 +386,9 @@ class ConfigureCommand(BasicCommand): | |
' Default output format [None]:\n' | ||
) | ||
SUBCOMMANDS = [ | ||
{'name': 'list', 'command_class': ConfigureListCommand} | ||
{'name': 'list', 'command_class': ConfigureListCommand}, | ||
{'name': 'get', 'command_class': ConfigureGetCommand}, | ||
{'name': 'set', 'command_class': ConfigureSetCommand}, | ||
] | ||
|
||
# If you want to add new values to prompt, update this list here. | ||
|
@@ -318,7 +413,6 @@ def _run_main(self, parsed_args, parsed_globals): | |
# Called when invoked with no args "aws configure" | ||
new_values = {} | ||
if parsed_globals.profile is not None: | ||
profile = parsed_globals.profile | ||
self._session.profile = parsed_globals.profile | ||
# This is the config from the config file scoped to a specific | ||
# profile. | ||
|
@@ -333,7 +427,7 @@ def _run_main(self, parsed_args, parsed_globals): | |
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_variable('config_file')) | ||
self._session.get_config_variable('config_file')) | ||
if new_values: | ||
if parsed_globals.profile is not None: | ||
new_values['__section__'] = ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
Get a configuration value from the config file. | ||
|
||
The ``aws configure get`` command can be used to print a configuration value in | ||
the AWS config file. The ``get`` command supports two types of configuration | ||
values, *unqualified* and *qualified* config values. | ||
|
||
|
||
Note that ``aws configure get`` only looks at values in the AWS configuration | ||
file. It does **not** resolve configuration variables specified anywhere else, | ||
including environment variables, command line arguments, etc. | ||
|
||
|
||
Unqualified Names | ||
----------------- | ||
|
||
Every value in the AWS configuration file must be placed in a section (denoted | ||
by ``[section-name]`` in the config file). To retrieve a value from the | ||
config file, the section name and the config name must be known. | ||
|
||
An unqualified configuration name refers to a name that is not scoped to a | ||
specific section in the configuration file. Sections are specified by | ||
separating parts with the ``"."`` character (``section.config-name``). An | ||
unqualified name will be scoped to the current profile. For example, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth providing a dotted example here as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nevermind, I just saw them in the examples below. |
||
``aws configure get aws_access_key_id`` will retrieve the ``aws_access_key_id`` | ||
from the current profile, or the ``default`` profile if no profile is | ||
specified. You can still provide a ``--profile`` argument to the ``aws | ||
configure get`` command. For example, ``aws configure get region --profile | ||
testing`` will print the region value for the ``testing`` profile. | ||
|
||
|
||
Qualified Names | ||
--------------- | ||
|
||
A qualified name is a name that has at least one ``"."`` character in the name. | ||
This name provides a way to specify the config section from which to retrieve | ||
the config variable. When a qualified name is provided to ``aws configure | ||
get``, the currently specified profile is ignored. Section names that have | ||
the format ``[profile profile-name]`` can be specified by using the | ||
``profile.profile-name.config-value`` syntax. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
Suppose you had the following config file:: | ||
|
||
[default] | ||
aws_access_key_id=default_access_key | ||
aws_secret_access_key=default_secret_key | ||
|
||
[preview] | ||
cloudsearch=true | ||
|
||
[profile testing] | ||
aws_access_key_id=testing_access_key | ||
aws_secret_access_key=testing_secret_key | ||
region=us-west-2 | ||
|
||
The following commands would have the corresponding output:: | ||
|
||
$ aws configure get aws_access_key_id | ||
default_access_key | ||
|
||
$ aws configure get default.aws_access_key_id | ||
default_access_key | ||
|
||
$ aws configure get aws_access_key_id --profile testing | ||
testing_access_key | ||
|
||
$ aws configure get profile.testing.aws_access_key_id | ||
default_access_key | ||
|
||
$ aws configure get preview.cloudsearch | ||
true | ||
|
||
$ aws configure get preview.does-not-exist | ||
$ | ||
$ echo $? | ||
1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Set a configuration value from the config file. | ||
|
||
The ``aws configure set`` command can be used to set a single configuration | ||
value in the AWS config file. The ``set`` command supports both the | ||
*qualified* and *unqualified* config values documented in the ``get`` command | ||
(see ``aws configure get help`` for more information). | ||
|
||
To set a single value, provide the configuration name followed by the | ||
configuration value. | ||
|
||
If the config file does not exist, one will automatically be created. If the | ||
configuration value already exists in the config file, it will updated with the | ||
new configuration value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL: You can provide a tuple to
.startswith(...)
.