# Copyright (c) 2009-2016 Hewlett Packard Enterprise Development LP
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import sys
from requestbuilder import Arg
import six
from euca2ools.commands.iam import IAMRequest, AS_ACCOUNT, arg_user
from euca2ools.commands.iam.getuser import GetUser
import euca2ools.exceptions
import euca2ools.util
class CreateAccessKey(IAMRequest):
DESCRIPTION = 'Create a new access key for a user'
ARGS = [arg_user(help='''user the new key will belong to
(default: current user)'''),
Arg('-w', '--write-config', action='store_true', route_to=None,
help='''output access keys and region information in the
form of a euca2ools.ini(5) configuration file instead of
by themselves'''),
Arg('-d', '--domain', route_to=None, help='''the DNS domain
to use for region information in configuration file
output (default: based on IAM URL)'''),
Arg('-l', '--set-default-user', action='store_true', route_to=None,
help='''set this user as the default user for the region
in euca2ools.ini(5) configuration file output. This
option is only useful when used with -w.'''),
AS_ACCOUNT]
def postprocess(self, result):
if self.args.get('write_config'):
parsed = six.moves.urllib.parse.urlparse(self.service.endpoint)
if not self.args.get('domain'):
dnsname = parsed.netloc.split(':')[0]
if all(label.isdigit() for label in dnsname.split('.')):
msg = ('warning: IAM URL {0} refers to a specific IP; '
'for a complete configuration file supply '
'the region\'s DNS domain with -d/--domain'
.format(self.service.endpoint))
print >> sys.stderr, msg
else:
self.args['domain'] = parsed.netloc.split('.', 1)[1]
configfile = six.moves.configparser.SafeConfigParser()
if self.args.get('domain'):
if ':' not in self.args['domain'] and ':' in parsed.netloc:
# Add the port
self.args['domain'] += ':' + parsed.netloc.split(':')[1]
# This uses self.config.region instead of
# self.service.region_name because the latter is a global
# service in AWS and thus frequently deferred with "use"
# statements. That may eventually happen in eucalyptus
# cloud federations as well.
#
# At some point an option that lets one choose a region
# name at the command line may be useful, but until
# someone asks for it let's not clutter it up for now.
region_name = self.config.region or self.args['domain']
region_section = 'region {0}'.format(region_name.split(':')[0])
configfile.add_section(region_section)
for service in sorted(euca2ools.util.generate_service_names()):
url = '{scheme}://{service}.{domain}/'.format(
scheme=parsed.scheme, domain=self.args['domain'],
service=service)
configfile.set(region_section, '{0}-url'.format(service),
url)
if self.config.get_region_option('verify-tls') is not None:
configfile.set(region_section, 'verify-tls',
self.config.get_region_option('verify-tls'))
if self.config.get_region_option('verify-ssl') is not None:
configfile.set(region_section, 'verify-ssl',
self.config.get_region_option('verify-ssl'))
user_name = result['AccessKey'].get('UserName') or 'root'
account_id = self.get_user_account_id()
if account_id:
user_name = '{0}:{1}'.format(account_id, user_name)
user_section = 'user {0}'.format(user_name)
configfile.add_section(user_section)
configfile.set(user_section, 'key-id',
result['AccessKey']['AccessKeyId'])
configfile.set(user_section, 'secret-key',
result['AccessKey']['SecretAccessKey'])
if account_id:
configfile.set(user_section, 'account-id', account_id)
if self.args.get('set_default_user'):
configfile.set(region_section, 'user', user_name)
result['configfile'] = configfile
def print_result(self, result):
if self.args.get('write_config'):
result['configfile'].write(sys.stdout)
else:
print result['AccessKey']['AccessKeyId']
print result['AccessKey']['SecretAccessKey']
def get_user_account_id(self):
req = GetUser.from_other(
self, UserName=self.params['UserName'],
DelegateAccount=self.params.get('DelegateAccount'))
try:
response = req.main()
except euca2ools.exceptions.AWSError as err:
if err.status_code == 403:
msg = ('warning: unable to retrieve account ID ({0})'
.format(err.message))
print >> sys.stderr, msg
return None
raise
arn = response['User']['Arn']
return arn.split(':')[4]