Script File to Create Policies for Autoscaling Functions Post Provisioning

Use the script file to create policies for autoscaling functions after creating the Oracle WebLogic Server for OCI domain.

If the OCI Policies check box is not selected during domain creation (create_policies set to false), you can use the script file to create function's dynamic group and policies after creating the domain. The script verifies if the stack has create_policies set to false, in which case it returns an error that policies would be automatically created via stack. However, you can use the --force option to override and create dynamic group and policies when create_policies == true.

Copy the following scripts in Cloud Shell to create polices for autoscaling. For example, copy the scripts and save the file as create_autoscaling_policies.py

Note:

For instructions on how to use the script to create function's dynamic group and policies, see Dynamic Group Policies for Autoscaling.

After you run the script, you must enable alarms from the Oracle Cloud Infrastructure console. See To enable an alarm in Oracle Cloud Infrastructure documentation.

"""
#
# Copyright (c) 2022, Oracle Corporation and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
"""
import argparse
import logging
import oci
import os
import sys
import textwrap
from oci.identity import models as identity_models
 
logger = logging.getLogger()
logging.basicConfig()
REGION = ''
 
 
def get_config():
    if REGION != '':
        return {"region": REGION}
    return {}
 
 
def get_variable(variables, name, default=None):
    """
    First read from stack variables
    If not found and default provided, return default
    :param variables:
    :param name:
    :param default:
    :return:
    """
    ret = None
    found = True
 
    if name in variables:
        ret = variables.get(name)
    else:
        if default is not None:
            return default
        else:
            logger.info("ERROR: value for the variable [%s] could not be found!" % (name))
            found = False
 
    if found:
        logger.debug("Value of variable [%s] is [%s]" % (name, ret))
 
    return ret
 
 
def inspect_stack(signer, stack_ocid):
    client = oci.resource_manager.ResourceManagerClient(config=get_config(), signer=signer)
    try:
        stack = client.get_stack(stack_id=stack_ocid)
    except(Exception, ValueError) as ex:
        logger.exception("ERROR: accessing resource manager stack failed")
        raise
    resp = stack.data
 
    return resp
 
 
def create_functions_dynamic_group(signer, stack_compartment_id, tenancy_id, service_name):
    """
    Creates functions dynamic group in root compartment.
 
    :param signer:
    :param stack_compartment_id:
    :param tenancy_id:
    :param service_name:
    :return:
    """
    client = oci.identity.IdentityClient(config={}, signer=signer)
    client_composite_ops = oci.identity.IdentityClientCompositeOperations(client)
    dg_name = "{0}-functions-dynamic-group-manual".format(service_name)
    try:
        create_dynamicgrp_resp = client_composite_ops.create_dynamic_group_and_wait_for_state(
            create_dynamic_group_details=identity_models.CreateDynamicGroupDetails(
                compartment_id=tenancy_id,
                description="Autoscaling Functions Dynamic Group of stack: {0}".format(service_name),
                matching_rule="All {resource.type = 'fnfunc', "
                              "resource.compartment.id='%s'}" % (stack_compartment_id),
                name=dg_name
            ),
            wait_for_states=[identity_models.DynamicGroup.LIFECYCLE_STATE_ACTIVE]
        )
    except(Exception, ValueError) as ex:
        logger.exception("Failed to create functions dynamic group {0}".format(dg_name))
        raise
    return create_dynamicgrp_resp.data
 
 
def create_policies_for_functions_dynamic_group(signer, stack_compartment_id, tenancy_id, service_name,
                                                network_compartment_id,
                                                apm_domain_compartment_id=None,
                                                atp_db_compartment_id=None,
                                                ocidb_compartment_id=None,
                                                app_atp_db_compartment_id=None,
                                                app_ocidb_compartment_id=None,
                                                fss_compartment_id=None):
    """
    Creates policies for functions dynamic group.
 
    :param signer:
    :param stack_compartment_id:
    :param tenancy_id:
    :param service_name:
    :param network_compartment_id:
    :param apm_domain_compartment_id:
    :param atp_db_compartment_id:
    :param ocidb_compartment_id:
    :param app_atp_db_compartment_id:
    :param app_ocidb_compartment_id:
    :param fss_compartment_id:
    :return:
    """
    client = oci.identity.IdentityClient(config={}, signer=signer)
    client_composite_ops = oci.identity.IdentityClientCompositeOperations(client)
    dg_name = "{0}-functions-dynamic-group-manual".format(service_name)
    try:
        policies = [
            "Allow dynamic-group {0} to inspect tenancies in tenancy".format(dg_name),
            "Allow dynamic-group {0} to inspect limits in tenancy".format(dg_name),
            "Allow dynamic-group {0} to manage volume-family in compartment id {1}".format(dg_name,
                                                                                           stack_compartment_id),
            "Allow dynamic-group {0} to manage instance-family in compartment id {1}".format(dg_name,
                                                                                             stack_compartment_id),
            "Allow dynamic-group {0} to use app-catalog-listing in compartment id {1}".format(dg_name,
                                                                                              stack_compartment_id),
            "Allow dynamic-group {0} to manage virtual-network-family in compartment id {1}".format(dg_name,
                                                                                                    network_compartment_id),
            "Allow dynamic-group {0} to manage load-balancers in compartment id {1}".format(dg_name,
                                                                                            network_compartment_id),
            "Allow dynamic-group {0} to manage orm-family in compartment id {1}".format(dg_name, stack_compartment_id),
            "Allow dynamic-group {0} to read metrics in compartment id {1}".format(dg_name, stack_compartment_id),
            "Allow dynamic-group {0} to manage repos in tenancy".format(dg_name),
            "Allow dynamic-group {0} to manage functions-family in compartment id {1}".format(dg_name,
                                                                                              stack_compartment_id),
            "Allow dynamic-group {0} to manage ons-topics in compartment id {1}".format(dg_name, stack_compartment_id),
            "Allow dynamic-group {0} to manage instance-agent-command-family in compartment id {1}".format(dg_name,
                                                                                                           stack_compartment_id),
            "Allow dynamic-group {0} to manage alarms in compartment id {1}".format(dg_name, stack_compartment_id),
            "Allow dynamic-group {0} to manage log-groups in compartment id {1}".format(dg_name, stack_compartment_id),
            "Allow dynamic-group {0} to manage unified-configuration in compartment id {1}".format(dg_name,
                                                                                                stack_compartment_id),
            "Allow dynamic-group {0} to inspect dynamic-groups in tenancy".format(dg_name),
            "Allow dynamic-group {0} to manage policies in tenancy".format(dg_name),
            "Allow dynamic-group {0} to use tag-namespaces in tenancy".format(dg_name)
        ]
        if apm_domain_compartment_id is not None:
            policies.append("Allow dynamic-group {0} to use apm-domains in compartment id {1}".format(dg_name,
                                                                                                      apm_domain_compartment_id))
        if atp_db_compartment_id is not None:
            policies.append(
                "Allow dynamic-group {0} to inspect autonomous-transaction-processing-family in compartment id {1}".format(
                    dg_name,
                    atp_db_compartment_id))
        if ocidb_compartment_id is not None:
            policies.append("Allow dynamic-group {0} to inspect database-family in compartment id {1}".format(dg_name,
                                                                                                              ocidb_compartment_id))
        if app_ocidb_compartment_id is not None:
            policies.append("Allow dynamic-group {0} to inspect database-family in compartment id {1}".format(dg_name,
                                                                                                              app_ocidb_compartment_id))
        if app_atp_db_compartment_id is not None:
            policies.append(
                "Allow dynamic-group {0} to use autonomous-transaction-processing-family in compartment id {1}".format(
                    dg_name,
                    app_atp_db_compartment_id))
        if fss_compartment_id is not None:
            policies.append("Allow dynamic-group {0} to manage mount-targets in compartment id {1}".format(dg_name,
                                                                                                           fss_compartment_id))
            policies.append("Allow dynamic-group {0} to manage file-systems in compartment id {1}".format(dg_name,
                                                                                                          fss_compartment_id))
            policies.append("Allow dynamic-group {0} to manage export-sets in compartment id {1}".format(dg_name,
                                                                                                         fss_compartment_id))
        create_policy_resp = client_composite_ops.create_policy_and_wait_for_state(
            create_policy_details=identity_models.CreatePolicyDetails(
                compartment_id=tenancy_id,
                description="Policy for Autoscaling Functions Dynamic Group of stack: {0}".format(service_name),
                statements=policies,
                name="{0}-wlsc-policy-manual".format(service_name)
            ),
            wait_for_states=[identity_models.Policy.LIFECYCLE_STATE_ACTIVE]
        )
    except(Exception, ValueError) as ex:
        logger.exception("Failed to create policies for functions dynamic group {0}".format(dg_name))
        raise
    return create_policy_resp.data
 
 
def get_apm_compartment_id(signer, apm_domain_id):
    client = oci.apm_control_plane.ApmDomainClient(config=get_config(), signer=signer)
    try:
        resp = client.get_apm_domain(apm_domain_id)
    except(Exception, ValueError) as ex:
        logger.exception("Failed to get compartment for APM domain ID [{0}]".format(apm_domain_id))
        raise
    apm_domain = resp.data
    return apm_domain.compartment_id
 
 
def main():
    signer = None
    # delegate token should be present at /etc/oci/delegation_token in cloud shell
    if os.path.exists('/etc/oci/delegation_token'):
        with open('/etc/oci/delegation_token', 'r') as file:
            delegation_token = file.read()
        signer = oci.auth.signers.InstancePrincipalsDelegationTokenSigner(delegation_token=delegation_token)
    else:
        logger.error("In the Cloud shell the delegation token does not exist at location /etc/oci/delegation_token. "
                     "Run the script from the Cloud shell, where you need to delete the resources.")
        sys.exit(1)
 
    if signer is None:
        logger.error('Instance principal signer is not initialized')
        sys.exit(1)
 
    parser = argparse.ArgumentParser(description=textwrap.dedent('''
        This script creates Functions Dynamic Group and Policies for Autoscaling.
    '''), formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('stack_ocid', help='Stack OCID')
    parser.add_argument('-r', '--region', default='', help='Region other than home region must be specified.')
    parser.add_argument('-d', '--debug', action='store_const', const=True, help='Enable Debug')
    parser.add_argument('-f', '--force', action='store_const', const=True, help='Force creation of dynamic group and '
                                                                                'policies')
 
    args = parser.parse_args()
 
    stack_ocid = args.stack_ocid
    global REGION
 
    REGION = args.region
    debug = args.debug
    if debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)
    force = args.force
 
    # Get stack variables
    resp = inspect_stack(signer, stack_ocid)
    logger.debug(resp)
    variables = resp.variables
    create_policies = get_variable(variables, 'create_policies', "true")
 
    if create_policies == 'true':
        if not force:
            logger.error('Stack has create_policies enabled so manual creation of autoscaling functions dynamic group '
                         'and policies is not required. Bailing out!')
            return
        else:
            logger.warning('Stack has create_policies enabled so manual creation of autoscaling functions dynamic '
                           'group and policies is not required.')
 
    stack_compartment_id = get_variable(variables, 'compartment_ocid')
    tenancy_id = get_variable(variables, 'tenancy_ocid')
    service_name = get_variable(variables, 'service_name')
 
    # create functions dynamic group
    create_functions_dynamic_group(signer, stack_compartment_id, tenancy_id, service_name)
 
    # create policies for the functions dynamic group
    apm_domain_id = get_variable(variables, 'apm_domain_id', "")
    atp_db_id = get_variable(variables, "atp_db_id", "")
    ocidb_dbsystem_id = get_variable(variables, "ocidb_dbsystem_id", "")
    app_atp_db_id = get_variable(variables, "app_atp_db_id", "")
    appdb_dbsystem_id = get_variable(variables, "appdb_dbsystem_id", "")
    add_fss = get_variable(variables, "add_fss", "false")
 
    network_compartment_id = get_variable(variables, 'network_compartment_id', stack_compartment_id)
    apm_domain_compartment_id = get_apm_compartment_id(signer, apm_domain_id) if apm_domain_id != '' else None
    atp_db_compartment_id = get_variable(variables, 'atp_db_compartment_id',
                                         stack_compartment_id) if atp_db_id != '' else None
    ocidb_compartment_id = get_variable(variables, 'ocidb_compartment_id',
                                        stack_compartment_id) if ocidb_dbsystem_id != '' else None
    app_atp_db_compartment_id = get_variable(variables, 'app_atp_db_compartment_id',
                                             stack_compartment_id) if app_atp_db_id != '' else None
    app_ocidb_compartment_id = get_variable(variables, 'app_ocidb_compartment_id',
                                            stack_compartment_id) if appdb_dbsystem_id != '' else None
    fss_compartment_id = get_variable(variables, 'fss_compartment_id',
                                      stack_compartment_id) if add_fss == 'true' else None
 
    create_policies_for_functions_dynamic_group(signer, stack_compartment_id, tenancy_id, service_name,
                                                network_compartment_id, apm_domain_compartment_id,
                                                atp_db_compartment_id,
                                                ocidb_compartment_id,
                                                app_atp_db_compartment_id,
                                                app_ocidb_compartment_id,
                                                fss_compartment_id)
 
 
if __name__ == '__main__':
    main()