# coding: utf-8
# Copyright (c) 2016, 2026, Oracle and/or its affiliates.  All rights reserved.
# This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
# NOTE: This class is auto generated by OracleSDKGenerator. DO NOT EDIT. API Version: 20240815

from __future__ import print_function
import click
import oci  # noqa: F401
import six  # noqa: F401
import sys  # noqa: F401
from oci_cli.cli_root import cli
from oci_cli import cli_constants  # noqa: F401
from oci_cli import cli_util
from oci_cli import json_skeleton_utils
from oci_cli import custom_types  # noqa: F401
from oci_cli.aliasing import CommandGroupWithAlias


@cli.command(cli_util.override('security_attribute.security_attribute_root_group.command_name', 'security-attribute'), cls=CommandGroupWithAlias, help=cli_util.override('security_attribute.security_attribute_root_group.help', """Use the Security Attributes API to manage security attributes and security attribute namespaces. For more information, see the documentation for [Security Attributes] and [Security Attribute Namespaces]."""), short_help=cli_util.override('security_attribute.security_attribute_root_group.short_help', """Security Attribute API"""))
@cli_util.help_option_group
def security_attribute_root_group():
    pass


@click.command(cli_util.override('security_attribute.security_attribute_namespace_group.command_name', 'security-attribute-namespace'), cls=CommandGroupWithAlias, help="""A managed container for security attributes. A security attribute namespace is unique in a tenancy. For more information, see [Managing Security Attributes Namespaces].

**Warning:** Oracle recommends that you avoid using any confidential information when you supply string values using the API.""")
@cli_util.help_option_group
def security_attribute_namespace_group():
    pass


@click.command(cli_util.override('security_attribute.security_attribute_work_request_log_group.command_name', 'security-attribute-work-request-log'), cls=CommandGroupWithAlias, help="""The log entity.""")
@cli_util.help_option_group
def security_attribute_work_request_log_group():
    pass


@click.command(cli_util.override('security_attribute.security_attribute_group.command_name', 'security-attribute'), cls=CommandGroupWithAlias, help="""A security attribute that belongs to a specific security attribute namespace. Security attributes must be created in a tenancy before a user can apply them to resources. For more information, see [Managing Security Attributes].

**Warning:** Oracle recommends that you avoid using any confidential information when you supply string values using the API.""")
@cli_util.help_option_group
def security_attribute_group():
    pass


@click.command(cli_util.override('security_attribute.security_attribute_work_request_group.command_name', 'security-attribute-work-request'), cls=CommandGroupWithAlias, help="""The asynchronous API request does not take effect immediately. This request spawns an asynchronous workflow to fulfill the request. WorkRequest objects provide visibility for in-progress workflows.""")
@cli_util.help_option_group
def security_attribute_work_request_group():
    pass


@click.command(cli_util.override('security_attribute.security_attribute_work_request_error_group.command_name', 'security-attribute-work-request-error'), cls=CommandGroupWithAlias, help="""The error entity.""")
@cli_util.help_option_group
def security_attribute_work_request_error_group():
    pass


security_attribute_root_group.add_command(security_attribute_namespace_group)
security_attribute_root_group.add_command(security_attribute_work_request_log_group)
security_attribute_root_group.add_command(security_attribute_group)
security_attribute_root_group.add_command(security_attribute_work_request_group)
security_attribute_root_group.add_command(security_attribute_work_request_error_group)


@security_attribute_group.command(name=cli_util.override('security_attribute.bulk_delete_security_attributes.command_name', 'bulk-delete'), help=u"""Deletes the specified security attribute definitions. This operation triggers a process that removes the security attributes from all resources in your tenancy. The security attributes must be within the same security attribute namespace.

The following actions happen immediately:

After you start this operation, the state of the tag changes to DELETING, and security attribute removal from resources begins. This process can take up to 48 hours depending on the number of resources that are tagged and the regions in which those resources reside.

When all security attributes have been removed, the state changes to DELETED. You cannot restore a deleted security attribute. After the security attribute state changes to DELETED, you can use the same security attribute name again.

After you start this operation, you cannot start either the [DeleteSecurityAttribute] or the [CascadeDeleteSecurityAttributeNamespace] operation until this process completes.

In order to delete security attribute, you must first retire the security attribute. Use [UpdateSecurityAttribute] to retire a security attribute. \n[Command Reference](bulkDeleteSecurityAttributes)""")
@cli_util.option('--security-attribute-ids', required=True, type=custom_types.CLI_COMPLEX_TYPE, help=u"""The OCIDs of the security attributes to delete.""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@json_skeleton_utils.get_cli_json_input_option({'security-attribute-ids': {'module': 'security_attribute', 'class': 'list[string]'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'security-attribute-ids': {'module': 'security_attribute', 'class': 'list[string]'}})
@cli_util.wrap_exceptions
def bulk_delete_security_attributes(ctx, from_json, security_attribute_ids):

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['securityAttributeIds'] = cli_util.parse_json_parameter("security_attribute_ids", security_attribute_ids)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.bulk_delete_security_attributes(
        bulk_delete_security_attributes_details=_details,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.bulk_edit_security_attributes.command_name', 'bulk-edit'), help=u"""Edits the specified list of security attributes for the selected resources. This operation triggers a process that edits the attributes on all selected resources. The possible actions are:

  * Add a security attribute when it does not already exist on the resource.   * Update the value for a security attribute when it is present on the resource.   * Add a security attribute when it does not already exist on the resource or update the value when it is present on the resource.   * Remove a security attribute from a resource. The security attribute is removed from the resource regardless of the value.

The edits can include a combination of operations and attributes. However, multiple operations cannot apply to the same attribute in the same request. \n[Command Reference](bulkEditSecurityAttributes)""")
@cli_util.option('--compartment-id', required=True, help=u"""The OCID of the compartment where the bulk edit request is submitted.""")
@cli_util.option('--resources', required=True, type=custom_types.CLI_COMPLEX_TYPE, help=u"""The resources to be updated.""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--bulk-edit-operations', required=True, type=custom_types.CLI_COMPLEX_TYPE, help=u"""The operations associated with the request to bulk edit tags.""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@json_skeleton_utils.get_cli_json_input_option({'resources': {'module': 'security_attribute', 'class': 'list[BulkEditResource]'}, 'bulk-edit-operations': {'module': 'security_attribute', 'class': 'list[BulkEditSecurityAttributeOperationDetails]'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'resources': {'module': 'security_attribute', 'class': 'list[BulkEditResource]'}, 'bulk-edit-operations': {'module': 'security_attribute', 'class': 'list[BulkEditSecurityAttributeOperationDetails]'}})
@cli_util.wrap_exceptions
def bulk_edit_security_attributes(ctx, from_json, compartment_id, resources, bulk_edit_operations):

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['compartmentId'] = compartment_id
    _details['resources'] = cli_util.parse_json_parameter("resources", resources)
    _details['bulkEditOperations'] = cli_util.parse_json_parameter("bulk_edit_operations", bulk_edit_operations)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.bulk_edit_security_attributes(
        bulk_edit_security_attribute_details=_details,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.cascading_delete_security_attribute_namespace.command_name', 'cascading-delete'), help=u"""Deletes the specified security attribute namespace. This operation triggers a process that removes all of the security attributes defined in the specified security attribute namespace from all resources in your tenancy and then deletes the security attribute namespace.

After you start the delete operation:

  * New security attribute key definitions cannot be created under the namespace.   * The state of the security attribute namespace changes to DELETING.   * Security attribute removal from the resources begins.

This process can take up to 48 hours depending on the number of security attributes in the namespace, the number of resources that are tagged, and the locations of the regions in which those resources reside.

After all security attributes are removed, the state changes to DELETED. You cannot restore a deleted security attribute namespace. After the deleted security attribute namespace changes its state to DELETED, you can use the name of the deleted security attribute namespace again.

After you start this operation, you cannot start either the [DeleteSecurityAttribute] or the [BulkDeleteSecurityAttributes] operation until this process completes.

To delete a security attribute namespace, you must first retire it. Use [UpdateSecurityAttributeNamespace] to retire a security attribute namespace. \n[Command Reference](cascadingDeleteSecurityAttributeNamespace)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--if-match', help=u"""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.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={})
@cli_util.wrap_exceptions
def cascading_delete_security_attribute_namespace(ctx, from_json, security_attribute_namespace_id, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.cascading_delete_security_attribute_namespace(
        security_attribute_namespace_id=security_attribute_namespace_id,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.change_security_attribute_namespace_compartment.command_name', 'change-compartment'), help=u"""Moves the specified security attribute namespace to the specified compartment within the same tenancy.

To move the security attribute namespace, you must have the manage security-attributes permission on both compartments. For more information about IAM policies, see [Details for IAM].

Moving a security attribute namespace moves all the security attributes contained in the security attribute namespace. \n[Command Reference](changeSecurityAttributeNamespaceCompartment)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--compartment-id', required=True, help=u"""The Oracle Cloud ID (OCID) of the destination compartment.""")
@cli_util.option('--if-match', help=u"""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.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={})
@cli_util.wrap_exceptions
def change_security_attribute_namespace_compartment(ctx, from_json, security_attribute_namespace_id, compartment_id, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['compartmentId'] = compartment_id

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.change_security_attribute_namespace_compartment(
        security_attribute_namespace_id=security_attribute_namespace_id,
        change_security_attribute_namespace_compartment_details=_details,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.create_security_attribute.command_name', 'create'), help=u"""Creates a new security attribute in the specified security attribute namespace.

The security attribute requires either the OCID or the name of the security attribute namespace that will contain this security attribute.

You must specify a *name* for the attribute, which must be unique across all attributes in the security attribute namespace and cannot be changed. The only valid characters for security attribute names are:\u00A00-9, A-Z, a-z, -, _ characters. Names are case insensitive. That means, for example, \"mySecurityAttribute\" and \"mysecurityattribute\" are not allowed in the same namespace. If you specify a name that's already in use in the security attribute namespace, a 409 error is returned.

The security attribute must have a *description*. It does not have to be unique, and you can change it with [UpdateSecurityAttribute].

The security attribute must have a value type, which is specified with a validator. Security attribute can use either a static value or a list of possible values. Static values are entered by a user applying the security attribute to a resource. Lists are created by the user and the user must apply a value from the list. Lists are validated. \n[Command Reference](createSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--name', required=True, help=u"""The name you assign to the security attribute during creation. This is the security attribute key. The name must be unique within the namespace and cannot be changed.""")
@cli_util.option('--description', required=True, help=u"""The description you assign to the security attribute during creation.""")
@cli_util.option('--validator', type=custom_types.CLI_COMPLEX_TYPE, help=u"""""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'validator': {'module': 'security_attribute', 'class': 'BaseSecurityAttributeValidator'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'validator': {'module': 'security_attribute', 'class': 'BaseSecurityAttributeValidator'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def create_security_attribute(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, name, description, validator):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['name'] = name
    _details['description'] = description

    if validator is not None:
        _details['validator'] = cli_util.parse_json_parameter("validator", validator)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.create_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        create_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.create_security_attribute_enum_security_attribute_validator.command_name', 'create-security-attribute-enum-security-attribute-validator'), help=u"""Creates a new security attribute in the specified security attribute namespace.

The security attribute requires either the OCID or the name of the security attribute namespace that will contain this security attribute.

You must specify a *name* for the attribute, which must be unique across all attributes in the security attribute namespace and cannot be changed. The only valid characters for security attribute names are:\u00A00-9, A-Z, a-z, -, _ characters. Names are case insensitive. That means, for example, \"mySecurityAttribute\" and \"mysecurityattribute\" are not allowed in the same namespace. If you specify a name that's already in use in the security attribute namespace, a 409 error is returned.

The security attribute must have a *description*. It does not have to be unique, and you can change it with [UpdateSecurityAttribute].

The security attribute must have a value type, which is specified with a validator. Security attribute can use either a static value or a list of possible values. Static values are entered by a user applying the security attribute to a resource. Lists are created by the user and the user must apply a value from the list. Lists are validated. \n[Command Reference](createSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--name', required=True, help=u"""The name you assign to the security attribute during creation. This is the security attribute key. The name must be unique within the namespace and cannot be changed.""")
@cli_util.option('--description', required=True, help=u"""The description you assign to the security attribute during creation.""")
@cli_util.option('--validator-values', type=custom_types.CLI_COMPLEX_TYPE, help=u"""The list of allowed values for a security attribute value.""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'validator-values': {'module': 'security_attribute', 'class': 'list[string]'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'validator-values': {'module': 'security_attribute', 'class': 'list[string]'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def create_security_attribute_enum_security_attribute_validator(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, name, description, validator_values):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['validator'] = {}
    _details['name'] = name
    _details['description'] = description

    if validator_values is not None:
        _details['validator']['values'] = cli_util.parse_json_parameter("validator_values", validator_values)

    _details['validator']['validatorType'] = 'ENUM'

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.create_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        create_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.create_security_attribute_default_security_attribute_validator.command_name', 'create-security-attribute-default-security-attribute-validator'), help=u"""Creates a new security attribute in the specified security attribute namespace.

The security attribute requires either the OCID or the name of the security attribute namespace that will contain this security attribute.

You must specify a *name* for the attribute, which must be unique across all attributes in the security attribute namespace and cannot be changed. The only valid characters for security attribute names are:\u00A00-9, A-Z, a-z, -, _ characters. Names are case insensitive. That means, for example, \"mySecurityAttribute\" and \"mysecurityattribute\" are not allowed in the same namespace. If you specify a name that's already in use in the security attribute namespace, a 409 error is returned.

The security attribute must have a *description*. It does not have to be unique, and you can change it with [UpdateSecurityAttribute].

The security attribute must have a value type, which is specified with a validator. Security attribute can use either a static value or a list of possible values. Static values are entered by a user applying the security attribute to a resource. Lists are created by the user and the user must apply a value from the list. Lists are validated. \n[Command Reference](createSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--name', required=True, help=u"""The name you assign to the security attribute during creation. This is the security attribute key. The name must be unique within the namespace and cannot be changed.""")
@cli_util.option('--description', required=True, help=u"""The description you assign to the security attribute during creation.""")
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def create_security_attribute_default_security_attribute_validator(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, name, description):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['validator'] = {}
    _details['name'] = name
    _details['description'] = description

    _details['validator']['validatorType'] = 'DEFAULT'

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.create_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        create_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.create_security_attribute_namespace.command_name', 'create'), help=u"""Creates a new security attribute namespace in the specified compartment.

You must specify the compartment ID in the request object (remember that the tenancy is simply the root compartment).

You must also specify a *name* for the namespace, which must be unique across all namespaces in your tenancy and cannot be changed. The only valid characters for security attribute names are: \u00A00-9, A-Z, a-z, -, _ characters. Names are case insensitive. That means, for example, \"myNamespace\" and \"mynamespace\" are not allowed in the same tenancy. Once you created a namespace, you cannot change the name. If you specify a name that's already in use in the tenancy, a 409 error is returned.

You must also specify a *description* for the namespace. It does not have to be unique, and you can change it with [UpdateSecurityAttributeNamespace]. \n[Command Reference](createSecurityAttributeNamespace)""")
@cli_util.option('--compartment-id', required=True, help=u"""The OCID of the tenancy containing the security attribute namespace.""")
@cli_util.option('--name', required=True, help=u"""The name you assign to the security attribute namespace during creation. The name must be unique across all namespaces in the tenancy and cannot be changed.""")
@cli_util.option('--description', required=True, help=u"""The description you assign to the security attribute namespace during creation.""")
@cli_util.option('--freeform-tags', type=custom_types.CLI_COMPLEX_TYPE, help=u"""Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. For more information, see [Resource Tags].

Example: `{\"Department\": \"Finance\"}`""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--defined-tags', type=custom_types.CLI_COMPLEX_TYPE, help=u"""Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see [Resource Tags].

Example: `{\"Operations\": {\"CostCenter\": \"42\"}}`""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'freeform-tags': {'module': 'security_attribute', 'class': 'dict(str, string)'}, 'defined-tags': {'module': 'security_attribute', 'class': 'dict(str, dict(str, object))'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'freeform-tags': {'module': 'security_attribute', 'class': 'dict(str, string)'}, 'defined-tags': {'module': 'security_attribute', 'class': 'dict(str, dict(str, object))'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttributeNamespace'})
@cli_util.wrap_exceptions
def create_security_attribute_namespace(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, compartment_id, name, description, freeform_tags, defined_tags):

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['compartmentId'] = compartment_id
    _details['name'] = name
    _details['description'] = description

    if freeform_tags is not None:
        _details['freeformTags'] = cli_util.parse_json_parameter("freeform_tags", freeform_tags)

    if defined_tags is not None:
        _details['definedTags'] = cli_util.parse_json_parameter("defined_tags", defined_tags)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.create_security_attribute_namespace(
        create_security_attribute_namespace_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute_namespace') and callable(getattr(client, 'get_security_attribute_namespace')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute_namespace(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.delete_security_attribute.command_name', 'delete'), help=u"""Deletes the specified security attribute. This operation triggers a process that removes the security attribute from all resources in your tenancy.

When you start the delete operation, the state of the security attribute changes to DELETING and security attribute removal from resources begins. This can take up to 48 hours depending on the number of resources that were tagged as well as the regions in which those resources reside.

When all attributes have been removed, the state changes to DELETED. You cannot restore a deleted attribute. Once the deleted attribute changes its state to DELETED, you can use the same security attribute name again.

After you start this operation, you cannot start either the [BulkDeleteSecurityAttributes] or the [CascadeDeleteSecurityAttributeNamespace] operation until this process completes.

To delete a security attribute, you must first retire it. Use [UpdateSecurityAttribute] to retire a security attribute. \n[Command Reference](deleteSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--security-attribute-name', required=True, help=u"""The name of the security attribute.""")
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.confirm_delete_option
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={})
@cli_util.wrap_exceptions
def delete_security_attribute(ctx, from_json, security_attribute_namespace_id, security_attribute_name, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    if isinstance(security_attribute_name, six.string_types) and len(security_attribute_name.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-name cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.delete_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        security_attribute_name=security_attribute_name,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.delete_security_attribute_namespace.command_name', 'delete'), help=u"""Deletes the specified security attribute namespace. Only an empty security attribute namespace can be deleted with this operation. To use this operation to delete a security attribute namespace that contains security attributes, first delete all of its security attributes. Use [DeleteSecurityAttribute] to delete a security attribute. \n[Command Reference](deleteSecurityAttributeNamespace)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.confirm_delete_option
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={})
@cli_util.wrap_exceptions
def delete_security_attribute_namespace(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.delete_security_attribute_namespace(
        security_attribute_namespace_id=security_attribute_namespace_id,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute_namespace') and callable(getattr(client, 'get_security_attribute_namespace')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                oci.wait_until(client, client.get_security_attribute_namespace(security_attribute_namespace_id), 'lifecycle_state', wait_for_state, succeed_on_not_found=True, **wait_period_kwargs)
            except oci.exceptions.ServiceError as e:
                # We make an initial service call so we can pass the result to oci.wait_until(), however if we are waiting on the
                # outcome of a delete operation it is possible that the resource is already gone and so the initial service call
                # will result in an exception that reflects a HTTP 404. In this case, we can exit with success (rather than raising
                # the exception) since this would have been the behaviour in the waiter anyway (as for delete we provide the argument
                # succeed_on_not_found=True to the waiter).
                #
                # Any non-404 should still result in the exception being thrown.
                if e.status == 404:
                    pass
                else:
                    raise
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Please retrieve the resource to find its current state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.get_security_attribute.command_name', 'get'), help=u"""Gets the specified security attribute's information. \n[Command Reference](getSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--security-attribute-name', required=True, help=u"""The name of the security attribute.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def get_security_attribute(ctx, from_json, security_attribute_namespace_id, security_attribute_name):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    if isinstance(security_attribute_name, six.string_types) and len(security_attribute_name.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-name cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.get_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        security_attribute_name=security_attribute_name,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.get_security_attribute_namespace.command_name', 'get'), help=u"""Gets the specified security attribute namespace's information. \n[Command Reference](getSecurityAttributeNamespace)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'SecurityAttributeNamespace'})
@cli_util.wrap_exceptions
def get_security_attribute_namespace(ctx, from_json, security_attribute_namespace_id):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.get_security_attribute_namespace(
        security_attribute_namespace_id=security_attribute_namespace_id,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_work_request_group.command(name=cli_util.override('security_attribute.get_security_attribute_work_request.command_name', 'get'), help=u"""Gets details on a specified work request. The workRequestID is returned in the opc-work-request-id header for any asynchronous operation in security attributes service. \n[Command Reference](getSecurityAttributeWorkRequest)""")
@cli_util.option('--work-request-id', required=True, help=u"""The OCID of the work request.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'SecurityAttributeWorkRequest'})
@cli_util.wrap_exceptions
def get_security_attribute_work_request(ctx, from_json, work_request_id):

    if isinstance(work_request_id, six.string_types) and len(work_request_id.strip()) == 0:
        raise click.UsageError('Parameter --work-request-id cannot be whitespace or empty string')

    kwargs = {}
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.get_security_attribute_work_request(
        work_request_id=work_request_id,
        **kwargs
    )
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.list_security_attribute_namespaces.command_name', 'list'), help=u"""Lists the security attribute namespaces in the specified compartment. \n[Command Reference](listSecurityAttributeNamespaces)""")
@cli_util.option('--compartment-id', help=u"""The [OCID] of the compartment in which to list resources.""")
@cli_util.option('--page', help=u"""The value of the `opc-next-page` response header from the previous \"List\" call.""")
@cli_util.option('--limit', type=click.INT, help=u"""The maximum number of items to return in a paginated \"List\" call.""")
@cli_util.option('--sort-order', type=custom_types.CliCaseInsensitiveChoice(["ASC", "DESC"]), help=u"""The sort order to use, either ascending (`ASC`) or descending (`DESC`).""")
@cli_util.option('--sort-by', type=custom_types.CliCaseInsensitiveChoice(["TIMECREATED", "NAME"]), help=u"""The field to sort by. You can provide one sort order (`sortOrder`). Default order for TIMECREATED is descending. Default order for NAME is ascending. The NAME sort order is case sensitive.

**Note:** In general, some \"List\" operations (for example, `ListInstances`) let you optionally filter by Availability Domain if the scope of the resource type is within a single Availability Domain. If you call one of these \"List\" operations without specifying an Availability Domain, the resources are grouped by Availability Domain, then sorted.""")
@cli_util.option('--name', help=u"""A filter to return only resources that match the entire display name given.""")
@cli_util.option('--compartment-id-in-subtree', type=click.BOOL, help=u"""An optional boolean parameter indicating whether to retrieve all security attribute namespaces in subcompartments. If this parameter is not specified, only the namespaces defined in the specified compartment are retrieved.""")
@cli_util.option('--lifecycle-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), help=u"""A filter to only return resources that match the given lifecycle state.  The state value is case-insensitive.""")
@cli_util.option('--all', 'all_pages', is_flag=True, help="""Fetches all pages of results. If you provide this option, then you cannot provide the --limit option.""")
@cli_util.option('--page-size', type=click.INT, help="""When fetching results, the number of results to fetch per call. Only valid when used with --all or --limit, and ignored otherwise.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'list[SecurityAttributeNamespaceSummary]'})
@cli_util.wrap_exceptions
def list_security_attribute_namespaces(ctx, from_json, all_pages, page_size, compartment_id, page, limit, sort_order, sort_by, name, compartment_id_in_subtree, lifecycle_state):

    if all_pages and limit:
        raise click.UsageError('If you provide the --all option you cannot provide the --limit option')

    kwargs = {}
    if compartment_id is not None:
        kwargs['compartment_id'] = compartment_id
    if page is not None:
        kwargs['page'] = page
    if limit is not None:
        kwargs['limit'] = limit
    if sort_order is not None:
        kwargs['sort_order'] = sort_order
    if sort_by is not None:
        kwargs['sort_by'] = sort_by
    if name is not None:
        kwargs['name'] = name
    if compartment_id_in_subtree is not None:
        kwargs['compartment_id_in_subtree'] = compartment_id_in_subtree
    if lifecycle_state is not None:
        kwargs['lifecycle_state'] = lifecycle_state
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    if all_pages:
        if page_size:
            kwargs['limit'] = page_size

        result = cli_util.list_call_get_all_results(
            client.list_security_attribute_namespaces,
            **kwargs
        )
    elif limit is not None:
        result = cli_util.list_call_get_up_to_limit(
            client.list_security_attribute_namespaces,
            limit,
            page_size,
            **kwargs
        )
    else:
        result = client.list_security_attribute_namespaces(
            **kwargs
        )
    cli_util.render_response(result, ctx)


@security_attribute_work_request_error_group.command(name=cli_util.override('security_attribute.list_security_attribute_work_request_errors.command_name', 'list'), help=u"""Gets the errors for a work request. \n[Command Reference](listSecurityAttributeWorkRequestErrors)""")
@cli_util.option('--work-request-id', required=True, help=u"""The OCID of the work request.""")
@cli_util.option('--page', help=u"""The value of the `opc-next-page` response header from the previous \"List\" call.""")
@cli_util.option('--limit', type=click.INT, help=u"""The maximum number of items to return in a paginated \"List\" call.""")
@cli_util.option('--all', 'all_pages', is_flag=True, help="""Fetches all pages of results. If you provide this option, then you cannot provide the --limit option.""")
@cli_util.option('--page-size', type=click.INT, help="""When fetching results, the number of results to fetch per call. Only valid when used with --all or --limit, and ignored otherwise.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'list[SecurityAttributeWorkRequestErrorSummary]'})
@cli_util.wrap_exceptions
def list_security_attribute_work_request_errors(ctx, from_json, all_pages, page_size, work_request_id, page, limit):

    if all_pages and limit:
        raise click.UsageError('If you provide the --all option you cannot provide the --limit option')

    if isinstance(work_request_id, six.string_types) and len(work_request_id.strip()) == 0:
        raise click.UsageError('Parameter --work-request-id cannot be whitespace or empty string')

    kwargs = {}
    if page is not None:
        kwargs['page'] = page
    if limit is not None:
        kwargs['limit'] = limit
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    if all_pages:
        if page_size:
            kwargs['limit'] = page_size

        result = cli_util.list_call_get_all_results(
            client.list_security_attribute_work_request_errors,
            work_request_id=work_request_id,
            **kwargs
        )
    elif limit is not None:
        result = cli_util.list_call_get_up_to_limit(
            client.list_security_attribute_work_request_errors,
            limit,
            page_size,
            work_request_id=work_request_id,
            **kwargs
        )
    else:
        result = client.list_security_attribute_work_request_errors(
            work_request_id=work_request_id,
            **kwargs
        )
    cli_util.render_response(result, ctx)


@security_attribute_work_request_log_group.command(name=cli_util.override('security_attribute.list_security_attribute_work_request_logs.command_name', 'list'), help=u"""Gets the logs for a work request. \n[Command Reference](listSecurityAttributeWorkRequestLogs)""")
@cli_util.option('--work-request-id', required=True, help=u"""The OCID of the work request.""")
@cli_util.option('--page', help=u"""The value of the `opc-next-page` response header from the previous \"List\" call.""")
@cli_util.option('--limit', type=click.INT, help=u"""The maximum number of items to return in a paginated \"List\" call.""")
@cli_util.option('--all', 'all_pages', is_flag=True, help="""Fetches all pages of results. If you provide this option, then you cannot provide the --limit option.""")
@cli_util.option('--page-size', type=click.INT, help="""When fetching results, the number of results to fetch per call. Only valid when used with --all or --limit, and ignored otherwise.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'list[SecurityAttributeWorkRequestLogSummary]'})
@cli_util.wrap_exceptions
def list_security_attribute_work_request_logs(ctx, from_json, all_pages, page_size, work_request_id, page, limit):

    if all_pages and limit:
        raise click.UsageError('If you provide the --all option you cannot provide the --limit option')

    if isinstance(work_request_id, six.string_types) and len(work_request_id.strip()) == 0:
        raise click.UsageError('Parameter --work-request-id cannot be whitespace or empty string')

    kwargs = {}
    if page is not None:
        kwargs['page'] = page
    if limit is not None:
        kwargs['limit'] = limit
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    if all_pages:
        if page_size:
            kwargs['limit'] = page_size

        result = cli_util.list_call_get_all_results(
            client.list_security_attribute_work_request_logs,
            work_request_id=work_request_id,
            **kwargs
        )
    elif limit is not None:
        result = cli_util.list_call_get_up_to_limit(
            client.list_security_attribute_work_request_logs,
            limit,
            page_size,
            work_request_id=work_request_id,
            **kwargs
        )
    else:
        result = client.list_security_attribute_work_request_logs(
            work_request_id=work_request_id,
            **kwargs
        )
    cli_util.render_response(result, ctx)


@security_attribute_work_request_group.command(name=cli_util.override('security_attribute.list_security_attribute_work_requests.command_name', 'list'), help=u"""Lists the security attribute work requests in compartment. \n[Command Reference](listSecurityAttributeWorkRequests)""")
@cli_util.option('--compartment-id', help=u"""The [OCID] of the compartment in which to list resources.""")
@cli_util.option('--page', help=u"""The value of the `opc-next-page` response header from the previous \"List\" call.""")
@cli_util.option('--limit', type=click.INT, help=u"""The maximum number of items to return in a paginated \"List\" call.""")
@cli_util.option('--resource-identifier', help=u"""The identifier of the resource the work request affects.""")
@cli_util.option('--all', 'all_pages', is_flag=True, help="""Fetches all pages of results. If you provide this option, then you cannot provide the --limit option.""")
@cli_util.option('--page-size', type=click.INT, help="""When fetching results, the number of results to fetch per call. Only valid when used with --all or --limit, and ignored otherwise.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'list[SecurityAttributeWorkRequestSummary]'})
@cli_util.wrap_exceptions
def list_security_attribute_work_requests(ctx, from_json, all_pages, page_size, compartment_id, page, limit, resource_identifier):

    if all_pages and limit:
        raise click.UsageError('If you provide the --all option you cannot provide the --limit option')

    kwargs = {}
    if compartment_id is not None:
        kwargs['compartment_id'] = compartment_id
    if page is not None:
        kwargs['page'] = page
    if limit is not None:
        kwargs['limit'] = limit
    if resource_identifier is not None:
        kwargs['resource_identifier'] = resource_identifier
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    if all_pages:
        if page_size:
            kwargs['limit'] = page_size

        result = cli_util.list_call_get_all_results(
            client.list_security_attribute_work_requests,
            **kwargs
        )
    elif limit is not None:
        result = cli_util.list_call_get_up_to_limit(
            client.list_security_attribute_work_requests,
            limit,
            page_size,
            **kwargs
        )
    else:
        result = client.list_security_attribute_work_requests(
            **kwargs
        )
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.list_security_attributes.command_name', 'list'), help=u"""Lists the security attributes in the specified namespace. \n[Command Reference](listSecurityAttributes)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--page', help=u"""The value of the `opc-next-page` response header from the previous \"List\" call.""")
@cli_util.option('--limit', type=click.INT, help=u"""The maximum number of items to return in a paginated \"List\" call.""")
@cli_util.option('--lifecycle-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), help=u"""A filter to only return resources that match the given lifecycle state.  The state value is case-insensitive.""")
@cli_util.option('--all', 'all_pages', is_flag=True, help="""Fetches all pages of results. If you provide this option, then you cannot provide the --limit option.""")
@cli_util.option('--page-size', type=click.INT, help="""When fetching results, the number of results to fetch per call. Only valid when used with --all or --limit, and ignored otherwise.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'list[SecurityAttributeSummary]'})
@cli_util.wrap_exceptions
def list_security_attributes(ctx, from_json, all_pages, page_size, security_attribute_namespace_id, page, limit, lifecycle_state):

    if all_pages and limit:
        raise click.UsageError('If you provide the --all option you cannot provide the --limit option')

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    kwargs = {}
    if page is not None:
        kwargs['page'] = page
    if limit is not None:
        kwargs['limit'] = limit
    if lifecycle_state is not None:
        kwargs['lifecycle_state'] = lifecycle_state
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])
    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    if all_pages:
        if page_size:
            kwargs['limit'] = page_size

        result = cli_util.list_call_get_all_results(
            client.list_security_attributes,
            security_attribute_namespace_id=security_attribute_namespace_id,
            **kwargs
        )
    elif limit is not None:
        result = cli_util.list_call_get_up_to_limit(
            client.list_security_attributes,
            limit,
            page_size,
            security_attribute_namespace_id=security_attribute_namespace_id,
            **kwargs
        )
    else:
        result = client.list_security_attributes(
            security_attribute_namespace_id=security_attribute_namespace_id,
            **kwargs
        )
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.update_security_attribute.command_name', 'update'), help=u"""Updates the specified security attribute. You can only update `description`, and `isRetired`. \n[Command Reference](updateSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--security-attribute-name', required=True, help=u"""The name of the security attribute.""")
@cli_util.option('--description', help=u"""The description of the security attribute during creation.""")
@cli_util.option('--is-retired', type=click.BOOL, help=u"""Whether the security attribute is retired. See [Managing Security Attributes].""")
@cli_util.option('--validator', type=custom_types.CLI_COMPLEX_TYPE, help=u"""""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.option('--force', help="""Perform update without prompting for confirmation.""", is_flag=True)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'validator': {'module': 'security_attribute', 'class': 'BaseSecurityAttributeValidator'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'validator': {'module': 'security_attribute', 'class': 'BaseSecurityAttributeValidator'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def update_security_attribute(ctx, from_json, force, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, security_attribute_name, description, is_retired, validator, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    if isinstance(security_attribute_name, six.string_types) and len(security_attribute_name.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-name cannot be whitespace or empty string')
    if not force:
        if validator:
            if not click.confirm("WARNING: Updates to validator will replace any existing values. Are you sure you want to continue?"):
                ctx.abort()

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}

    if description is not None:
        _details['description'] = description

    if is_retired is not None:
        _details['isRetired'] = is_retired

    if validator is not None:
        _details['validator'] = cli_util.parse_json_parameter("validator", validator)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.update_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        security_attribute_name=security_attribute_name,
        update_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.update_security_attribute_enum_security_attribute_validator.command_name', 'update-security-attribute-enum-security-attribute-validator'), help=u"""Updates the specified security attribute. You can only update `description`, and `isRetired`. \n[Command Reference](updateSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--security-attribute-name', required=True, help=u"""The name of the security attribute.""")
@cli_util.option('--description', help=u"""The description of the security attribute during creation.""")
@cli_util.option('--is-retired', type=click.BOOL, help=u"""Whether the security attribute is retired. See [Managing Security Attributes].""")
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.option('--validator-values', type=custom_types.CLI_COMPLEX_TYPE, help=u"""The list of allowed values for a security attribute value.""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'validator-values': {'module': 'security_attribute', 'class': 'list[string]'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'validator-values': {'module': 'security_attribute', 'class': 'list[string]'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def update_security_attribute_enum_security_attribute_validator(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, security_attribute_name, description, is_retired, if_match, validator_values):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    if isinstance(security_attribute_name, six.string_types) and len(security_attribute_name.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-name cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['validator'] = {}

    if description is not None:
        _details['description'] = description

    if is_retired is not None:
        _details['isRetired'] = is_retired

    if validator_values is not None:
        _details['validator']['values'] = cli_util.parse_json_parameter("validator_values", validator_values)

    _details['validator']['validatorType'] = 'ENUM'

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.update_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        security_attribute_name=security_attribute_name,
        update_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_group.command(name=cli_util.override('security_attribute.update_security_attribute_default_security_attribute_validator.command_name', 'update-security-attribute-default-security-attribute-validator'), help=u"""Updates the specified security attribute. You can only update `description`, and `isRetired`. \n[Command Reference](updateSecurityAttribute)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--security-attribute-name', required=True, help=u"""The name of the security attribute.""")
@cli_util.option('--description', help=u"""The description of the security attribute during creation.""")
@cli_util.option('--is-retired', type=click.BOOL, help=u"""Whether the security attribute is retired. See [Managing Security Attributes].""")
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={}, output_type={'module': 'security_attribute', 'class': 'SecurityAttribute'})
@cli_util.wrap_exceptions
def update_security_attribute_default_security_attribute_validator(ctx, from_json, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, security_attribute_name, description, is_retired, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')

    if isinstance(security_attribute_name, six.string_types) and len(security_attribute_name.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-name cannot be whitespace or empty string')

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}
    _details['validator'] = {}

    if description is not None:
        _details['description'] = description

    if is_retired is not None:
        _details['isRetired'] = is_retired

    _details['validator']['validatorType'] = 'DEFAULT'

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.update_security_attribute(
        security_attribute_namespace_id=security_attribute_namespace_id,
        security_attribute_name=security_attribute_name,
        update_security_attribute_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute') and callable(getattr(client, 'get_security_attribute')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)


@security_attribute_namespace_group.command(name=cli_util.override('security_attribute.update_security_attribute_namespace.command_name', 'update'), help=u"""Updates the specified security attribute namespace. You can't update the namespace name.

Updating `isRetired` to 'true' retires the namespace and all the security attributes in the namespace. Reactivating a namespace (changing `isRetired` from 'true' to 'false') does not reactivate security attributes. To reactivate the security attributes, you must reactivate each one individually *after* you reactivate the namespace, using [UpdateSecurityAttribute]. For more information about retiring security attribute namespaces, see [Managing Security Attribute Namespaces].

You can't add a namespace with the same name as a retired namespace in the same tenancy. \n[Command Reference](updateSecurityAttributeNamespace)""")
@cli_util.option('--security-attribute-namespace-id', required=True, help=u"""The OCID of the security attribute namespace.""")
@cli_util.option('--description', help=u"""The description you assign to the security attribute namespace to help you identify it.""")
@cli_util.option('--is-retired', type=click.BOOL, help=u"""Indicates whether the security attribute namespace is retired. See [Managing Security Attribute Namespaces].""")
@cli_util.option('--freeform-tags', type=custom_types.CLI_COMPLEX_TYPE, help=u"""Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. For more information, see [Resource Tags].

Example: `{\"Department\": \"Finance\"}`""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--defined-tags', type=custom_types.CLI_COMPLEX_TYPE, help=u"""Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see [Resource Tags].

Example: `{\"Operations\": {\"CostCenter\": \"42\"}}`""" + custom_types.cli_complex_type.COMPLEX_TYPE_HELP)
@cli_util.option('--if-match', help=u"""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.""")
@cli_util.option('--force', help="""Perform update without prompting for confirmation.""", is_flag=True)
@cli_util.option('--wait-for-state', type=custom_types.CliCaseInsensitiveChoice(["ACTIVE", "INACTIVE", "DELETING", "DELETED"]), multiple=True, help="""This operation creates, modifies or deletes a resource that has a defined lifecycle state. Specify this option to perform the action and then wait until the resource reaches a given lifecycle state. Multiple states can be specified, returning on the first state. For example, --wait-for-state ACTIVE --wait-for-state DELETED would return on whichever lifecycle state is reached first. If timeout is reached, a return code of 2 is returned. For any other error, a return code of 1 is returned.""")
@cli_util.option('--max-wait-seconds', type=click.INT, help="""The maximum time to wait for the resource to reach the lifecycle state defined by --wait-for-state. Defaults to 1200 seconds.""")
@cli_util.option('--wait-interval-seconds', type=click.INT, help="""Check every --wait-interval-seconds to see whether the resource has reached the lifecycle state defined by --wait-for-state. Defaults to 30 seconds.""")
@json_skeleton_utils.get_cli_json_input_option({'freeform-tags': {'module': 'security_attribute', 'class': 'dict(str, string)'}, 'defined-tags': {'module': 'security_attribute', 'class': 'dict(str, dict(str, object))'}})
@cli_util.help_option
@click.pass_context
@json_skeleton_utils.json_skeleton_generation_handler(input_params_to_complex_types={'freeform-tags': {'module': 'security_attribute', 'class': 'dict(str, string)'}, 'defined-tags': {'module': 'security_attribute', 'class': 'dict(str, dict(str, object))'}}, output_type={'module': 'security_attribute', 'class': 'SecurityAttributeNamespace'})
@cli_util.wrap_exceptions
def update_security_attribute_namespace(ctx, from_json, force, wait_for_state, max_wait_seconds, wait_interval_seconds, security_attribute_namespace_id, description, is_retired, freeform_tags, defined_tags, if_match):

    if isinstance(security_attribute_namespace_id, six.string_types) and len(security_attribute_namespace_id.strip()) == 0:
        raise click.UsageError('Parameter --security-attribute-namespace-id cannot be whitespace or empty string')
    if not force:
        if freeform_tags or defined_tags:
            if not click.confirm("WARNING: Updates to freeform-tags and defined-tags will replace any existing values. Are you sure you want to continue?"):
                ctx.abort()

    kwargs = {}
    if if_match is not None:
        kwargs['if_match'] = if_match
    kwargs['opc_request_id'] = cli_util.use_or_generate_request_id(ctx.obj['request_id'])

    _details = {}

    if description is not None:
        _details['description'] = description

    if is_retired is not None:
        _details['isRetired'] = is_retired

    if freeform_tags is not None:
        _details['freeformTags'] = cli_util.parse_json_parameter("freeform_tags", freeform_tags)

    if defined_tags is not None:
        _details['definedTags'] = cli_util.parse_json_parameter("defined_tags", defined_tags)

    client = cli_util.build_client('security_attribute', 'security_attribute', ctx)
    result = client.update_security_attribute_namespace(
        security_attribute_namespace_id=security_attribute_namespace_id,
        update_security_attribute_namespace_details=_details,
        **kwargs
    )
    if wait_for_state:

        if hasattr(client, 'get_security_attribute_namespace') and callable(getattr(client, 'get_security_attribute_namespace')):
            try:
                wait_period_kwargs = {}
                if max_wait_seconds is not None:
                    wait_period_kwargs['max_wait_seconds'] = max_wait_seconds
                if wait_interval_seconds is not None:
                    wait_period_kwargs['max_interval_seconds'] = wait_interval_seconds

                click.echo('Action completed. Waiting until the resource has entered state: {}'.format(wait_for_state), file=sys.stderr)
                result = oci.wait_until(client, client.get_security_attribute_namespace(result.data.id), 'lifecycle_state', wait_for_state, **wait_period_kwargs)
            except oci.exceptions.MaximumWaitTimeExceeded as e:
                # If we fail, we should show an error, but we should still provide the information to the customer
                click.echo('Failed to wait until the resource entered the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                sys.exit(2)
            except Exception:
                click.echo('Encountered error while waiting for resource to enter the specified state. Outputting last known resource state', file=sys.stderr)
                cli_util.render_response(result, ctx)
                raise
        else:
            click.echo('Unable to wait for the resource to enter the specified state', file=sys.stderr)
    cli_util.render_response(result, ctx)
