diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2cd74e42b..0f6c37447 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,17 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `__. +2.4.9 - 2017-09-13 +------------------ + +Fixed +~~~~~~~~~~ +* On Windows, fall back to old default config location (%USERPROFILE%\.oraclebmc\config) if new default location doesn't exist (%USERPROFILE%\.oci\config). + +Added +~~~~~~~~~~ +* Support for CustomerSecretKey operations (oci iam customer-secret-key create / delete / list / update). + 2.4.8 - 2017-09-11 ------------------ diff --git a/src/oci_cli/cli_root.py b/src/oci_cli/cli_root.py index 9ab1b1fa7..98c340d74 100644 --- a/src/oci_cli/cli_root.py +++ b/src/oci_cli/cli_root.py @@ -2,6 +2,7 @@ # Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. import sys +from oci.config import DEFAULT_LOCATION import click import logging @@ -35,7 +36,7 @@ For information on configuration, see https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/sdkconfig.htm.""") @click.version_option(__version__, '-v', '--version', message='%(version)s') @click.option('--config-file', - default='~/.oci/config', show_default=True, + default=DEFAULT_LOCATION, show_default=True, help='The path to the config file.') @click.option('--profile', default='DEFAULT', show_default=True, diff --git a/src/oci_cli/generated/identity_cli.py b/src/oci_cli/generated/identity_cli.py index 545582307..eb08aac8c 100644 --- a/src/oci_cli/generated/identity_cli.py +++ b/src/oci_cli/generated/identity_cli.py @@ -139,13 +139,6 @@ def compartment_group(): pass -@click.group(cli_util.override('customer_secret_key_summary_group.command_name', 'customer-secret-key-summary'), help="""As the name suggests, a `CustomerSecretKeySummary` object contains information about a `CustomerSecretKey`. -A `CustomerSecretKey` is an Oracle-provided key for using the Object Storage Service's Amazon S3 compatible API.""") -@cli_util.help_option_group -def customer_secret_key_summary_group(): - pass - - @click.group(cli_util.override('region_group.command_name', 'region'), help="""A localized geographic area, such as Phoenix, AZ. Oracle Bare Metal Cloud Services is hosted in regions and Availability Domains. A region is composed of several Availability Domains. An Availability Domain is one or more data centers located within a region. For more information, see [Regions and Availability Domains]. @@ -887,7 +880,7 @@ def list_compartments(ctx, compartment_id, page, limit): cli_util.render_response(result) -@customer_secret_key_summary_group.command(name=cli_util.override('list_customer_secret_keys.command_name', 'list-customer-secret-keys'), help="""Lists the secret keys for the specified user. The returned object contains the secret key's OCID, but not the secret key itself. The actual secret key is returned only upon creation.""") +@customer_secret_key_group.command(name=cli_util.override('list_customer_secret_keys.command_name', 'list'), help="""Lists the secret keys for the specified user. The returned object contains the secret key's OCID, but not the secret key itself. The actual secret key is returned only upon creation.""") @click.option('--user-id', required=True, help="""The OCID of the user.""") @cli_util.help_option @click.pass_context @@ -1132,7 +1125,7 @@ def update_compartment(ctx, compartment_id, description, name, if_match): cli_util.render_response(result) -@customer_secret_key_summary_group.command(name=cli_util.override('update_customer_secret_key.command_name', 'update-customer-secret-key'), help="""Updates the specified secret key's description.""") +@customer_secret_key_group.command(name=cli_util.override('update_customer_secret_key.command_name', 'update'), help="""Updates the specified secret key's description.""") @click.option('--user-id', required=True, help="""The OCID of the user.""") @click.option('--customer-secret-key-id', required=True, help="""The OCID of the secret key.""") @click.option('--display-name', help="""The description you assign to the secret key. Does not have to be unique, and it's changeable.""") diff --git a/src/oci_cli/identity_cli_extended.py b/src/oci_cli/identity_cli_extended.py index dfb68a6aa..f888b9cc0 100644 --- a/src/oci_cli/identity_cli_extended.py +++ b/src/oci_cli/identity_cli_extended.py @@ -9,6 +9,7 @@ identity_cli.identity_group.add_command(identity_cli.availability_domain_group) identity_cli.identity_group.add_command(identity_cli.compartment_group) +identity_cli.identity_group.add_command(identity_cli.customer_secret_key_group) identity_cli.identity_group.add_command(identity_cli.group_group) identity_cli.identity_group.add_command(identity_cli.policy_group) identity_cli.identity_group.add_command(identity_cli.region_group) @@ -18,7 +19,6 @@ identity_cli.user_group.add_command(identity_cli.swift_password_group) identity_cli.user_group.add_command(identity_cli.ui_password_group) - # help for oci iam policy create --statements identity_policy_create_statements_example = """'["statement 1","statement 2"]'""" identity_policy_create_statements_help = cli_util.GENERIC_JSON_FORMAT_HELP diff --git a/src/oci_cli/version.py b/src/oci_cli/version.py index 0c48c67fb..5cd61f029 100644 --- a/src/oci_cli/version.py +++ b/src/oci_cli/version.py @@ -1,4 +1,4 @@ # coding: utf-8 # Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. -__version__ = '2.4.8' +__version__ = '2.4.9' diff --git a/tests/output/inline_help_dump.txt b/tests/output/inline_help_dump.txt index a45a14357..8c760b7b8 100644 --- a/tests/output/inline_help_dump.txt +++ b/tests/output/inline_help_dump.txt @@ -1951,6 +1951,7 @@ Options: Commands: availability-domain One or more isolated, fault-tolerant Oracle... compartment A collection of related resources. + customer-secret-key A `CustomerSecretKey` is an Oracle-provided... group A collection of users who all need the same... policy A document that specifies the type of access... region A localized geographic area, such as Phoenix,... @@ -2115,6 +2116,106 @@ Options: etag value. -?, -h, --help Show this message and exit. +++++++++++++++++++++++++++++++++++++++++++++++ +$ oci iam customer-secret-key --help +Usage: oci iam customer-secret-key [OPTIONS] COMMAND [ARGS]... + + A `CustomerSecretKey` is an Oracle-provided key for using the Object Storage + Service's [Amazon S3 compatible API]. A user can have up to two secret keys + at a time. + + **Note:** The secret key is always an Oracle-generated string; you can't + change it to a string of your choice. + + For more information, see [Managing User Credentials]. + +Options: + -?, -h, --help Show this message and exit. + +Commands: + create Creates a new secret key for the specified... + delete Deletes the specified secret key for the... + list Lists the secret keys for the specified user. + update Updates the specified secret key's... + +++++++++++++++++++++++++++++++++++++++++++++++ +$ oci iam customer-secret-key create --help +Usage: oci iam customer-secret-key create [OPTIONS] + + Creates a new secret key for the specified user. Secret keys are used for + authentication with the Object Storage Service's Amazon S3 compatible API. + For information, see [Managing User Credentials]. + + You must specify a *description* for the secret key (although it can be an + empty string). It does not have to be unique, and you can change it anytime + with [UpdateCustomerSecretKey]. + + Every user has permission to create a secret key for *their own user ID*. An + administrator in your organization does not need to write a policy to give + users this ability. To compare, administrators who have permission to the + tenancy can use this operation to create a secret key for any user, + including themselves. + +Options: + --display-name TEXT The name you assign to the secret key during creation. + Does not have to be unique, and it's changeable. + [required] + --user-id TEXT The OCID of the user. [required] + -?, -h, --help Show this message and exit. + +++++++++++++++++++++++++++++++++++++++++++++++ +$ oci iam customer-secret-key delete --help +Usage: oci iam customer-secret-key delete [OPTIONS] + + Deletes the specified secret key for the specified user. + +Options: + --user-id TEXT The OCID of the user. [required] + --customer-secret-key-id TEXT The OCID of the secret key. [required] + --if-match TEXT For optimistic concurrency control. In the PUT + or DELETE call for a resource, set the `if- + match` parameter to the value of the etag from + a previous GET or POST response for that + resource. The resource will be updated or + deleted only if the etag you provide matches + the resource's current etag value. + --force Perform deletion without prompting for + confirmation. + -?, -h, --help Show this message and exit. + +++++++++++++++++++++++++++++++++++++++++++++++ +$ oci iam customer-secret-key list --help +Usage: oci iam customer-secret-key list [OPTIONS] + + Lists the secret keys for the specified user. The returned object contains + the secret key's OCID, but not the secret key itself. The actual secret key + is returned only upon creation. + +Options: + --user-id TEXT The OCID of the user. [required] + -?, -h, --help Show this message and exit. + +++++++++++++++++++++++++++++++++++++++++++++++ +$ oci iam customer-secret-key update --help +Usage: oci iam customer-secret-key update [OPTIONS] + + Updates the specified secret key's description. + +Options: + --user-id TEXT The OCID of the user. [required] + --customer-secret-key-id TEXT The OCID of the secret key. [required] + --display-name TEXT The description you assign to the secret key. + Does not have to be unique, and it's + changeable. + --if-match TEXT For optimistic concurrency control. In the PUT + or DELETE call for a resource, set the `if- + match` parameter to the value of the etag from + a previous GET or POST response for that + resource. The resource will be updated or + deleted only if the etag you provide matches + the resource's current etag value. + -?, -h, --help Show this message and exit. + ++++++++++++++++++++++++++++++++++++++++++++++ $ oci iam group --help Usage: oci iam group [OPTIONS] COMMAND [ARGS]... diff --git a/tests/test_identity.py b/tests/test_identity.py index 7c5e50fc4..063fc6dbf 100644 --- a/tests/test_identity.py +++ b/tests/test_identity.py @@ -14,6 +14,9 @@ class TestIdentity(unittest.TestCase): RENAME_COMPARTMENT_PREFIX = "PythonCliCompartmentRenameTest-" + VALID_ACTIVE_CUSTOMER_SECRET_KEY_STATES = ['ACTIVE', 'CREATING'] + VALID_DELETED_CUSTOMER_SECRET_KEY_STATES = ['DELETED', 'DELETING'] + def setUp(self): util.set_admin_pass_phrase() @@ -32,6 +35,7 @@ def test_all_operations(self, validator): self.subtest_ui_password_operations() self.subtest_swift_password_operations() self.subtest_policy_operations() + self.subtest_customer_secret_key_operations() self.subtest_cleanup() def subtest_availability_domain_operations(self): @@ -352,6 +356,60 @@ def subtest_policy_operations(self): result = self.invoke(['policy', 'delete', '--policy-id', policy_ocid, '--force']) self.validate_response(result) + def subtest_customer_secret_key_operations(self): + create_secret_key_one_parsed_result = self.create_and_assert_customer_secret_key('Secret Key One') + + result = self.invoke([ + 'customer-secret-key', 'update', + '--user-id', self.user_ocid, + '--customer-secret-key-id', + create_secret_key_one_parsed_result['data']['id'], + '--display-name', + 'Updated Secret Key One' + ]) + update_secret_key_one_parsed_result = json.loads(result.output) + + assert update_secret_key_one_parsed_result['data']['id'] == create_secret_key_one_parsed_result['data']['id'] + assert update_secret_key_one_parsed_result['data']['user-id'] == self.user_ocid + assert update_secret_key_one_parsed_result['data']['display-name'] == 'Updated Secret Key One' + assert update_secret_key_one_parsed_result['data']['time-created'] is not None + assert update_secret_key_one_parsed_result['data']['time-expires'] is None + assert update_secret_key_one_parsed_result['data']['lifecycle-state'] in self.VALID_ACTIVE_CUSTOMER_SECRET_KEY_STATES + + create_secret_key_two_parsed_result = self.create_and_assert_customer_secret_key('Secret Key Two') + + result = self.invoke(['customer-secret-key', 'list', '--user-id', self.user_ocid]) + parsed_list_result = json.loads(result.output) + + assert len(parsed_list_result['data']) == 2 + if parsed_list_result['data'][0]['id'] == create_secret_key_one_parsed_result['data']['id']: + self.compare_secret_key_dicts(parsed_list_result['data'][0], update_secret_key_one_parsed_result['data']) + self.compare_secret_key_dicts(parsed_list_result['data'][1], create_secret_key_two_parsed_result['data']) + else: + self.compare_secret_key_dicts(parsed_list_result['data'][0], create_secret_key_two_parsed_result['data']) + self.compare_secret_key_dicts(parsed_list_result['data'][1], update_secret_key_one_parsed_result['data']) + + self.invoke([ + 'customer-secret-key', 'delete', + '--user-id', self.user_ocid, + '--customer-secret-key-id', create_secret_key_one_parsed_result['data']['id'], + '--force' + ]) + self.invoke([ + 'customer-secret-key', 'delete', + '--user-id', self.user_ocid, + '--customer-secret-key-id', create_secret_key_two_parsed_result['data']['id'], + '--force' + ]) + + result = self.invoke(['customer-secret-key', 'list', '--user-id', self.user_ocid]) + if result.output: + parsed_list_result = json.loads(result.output) + + if len(parsed_list_result['data']) != 0: + for item in parsed_list_result['data']: + assert item['lifecycle-state'] in self.VALID_DELETED_CUSTOMER_SECRET_KEY_STATES + def subtest_cleanup(self): result = self.invoke(['user', 'delete', '--user-id', self.user_ocid], input='n') assert result.exit_code != 0 @@ -431,6 +489,29 @@ def get_compartment_to_rename(self): return parsed_result['data'] + def create_and_assert_customer_secret_key(self, display_name): + result = self.invoke(['customer-secret-key', 'create', '--user-id', self.user_ocid, '--display-name', display_name]) + create_secret_parsed_result = json.loads(result.output) + + assert create_secret_parsed_result['data']['key'] is not None + assert create_secret_parsed_result['data']['id'] is not None + assert create_secret_parsed_result['data']['user-id'] == self.user_ocid + assert create_secret_parsed_result['data']['display-name'] == display_name + assert create_secret_parsed_result['data']['time-created'] is not None + assert create_secret_parsed_result['data']['time-expires'] is None + assert create_secret_parsed_result['data']['lifecycle-state'] in self.VALID_ACTIVE_CUSTOMER_SECRET_KEY_STATES + + return create_secret_parsed_result + + def compare_secret_key_dicts(self, dict_one, dict_two): + assert dict_one['id'] == dict_two['id'] + assert dict_one['display-name'] == dict_two['display-name'] + assert dict_one['user-id'] == dict_two['user-id'] + assert dict_one['display-name'] == dict_two['display-name'] + assert dict_one['time-created'] == dict_two['time-created'] + assert dict_one['time-expires'] == dict_two['time-expires'] + assert dict_one['lifecycle-state'] == dict_two['lifecycle-state'] + if __name__ == '__main__': unittest.main()