예제 #1
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Get a list of apps
        apps = body_via_v3_post(pc_external_ip, "apps", pc_password, None).json

        # Loop through our apps
        for app in apps["entities"]:

            # Print out status
            INFO(f'{app["status"]["name"]} App State: {app["status"]["state"]}')

            # Fail out if app is not in running state
            if app["status"]["state"].lower() != "running":
                raise Exception(f"{app['status']['name']} app in a non-running state.")

    except Exception as ex:
        ERROR(traceback.format_exc())
        # NX-on-GCP does not support erroring out based on return codes,
        # so sleeping to time the deployment out
        time.sleep(18000)
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Create the API call body
        body = {"enable_nutanix_apps": True}

        # Make API call to enable marketplace
        resp = create_via_v3_post(pc_external_ip, "marketplace_items/config",
                                  pc_password, body)

        # Log appropriately based on response
        if resp.code == 200 or resp.code == 202:
            INFO("Marketplace enabled successfully.")
        else:
            raise Exception(f"Marketplace enable failed with:\n" +
                            f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                            f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #3
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in our spec file
        autodc_spec = file_to_dict("specs/pc_autodc.json")
        INFO(f"autodc_spec: {autodc_spec}")

        # Make API call to configure the authconfig
        resp = create_via_v1_post(pc_external_ip, "authconfig/directories",
                                  pc_password, autodc_spec)

        # Log appropriately based on response
        if resp.code == 200 or resp.code == 202:
            INFO("Authconfig configured successfully.")
        else:
            raise Exception(f"Authconfig failed with:\n" + f"Resp: {resp}\n" +
                            f"Error Code: {resp.code}\n" +
                            f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #4
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Get marketplace items
        mp_items = body_via_v3_post(pc_external_ip, "calm_marketplace_items",
                                    pc_password, None).json

        # Loop through our items
        for item in mp_items["entities"]:

            # We only care about those PENDING
            if item["status"]["app_state"] == "PENDING":

                # Get and modify the body
                body = body_via_v3_get(
                    pc_external_ip,
                    "calm_marketplace_items",
                    pc_password,
                    item["metadata"]["uuid"],
                ).json
                del body["status"]
                body["spec"]["resources"]["app_state"] = "ACCEPTED"

                # Update the item
                resp = update_via_v3_put(
                    pc_external_ip,
                    "calm_marketplace_items",
                    pc_password,
                    item["metadata"]["uuid"],
                    body,
                )

                # Log appropriately based on response
                if resp.code == 200 or resp.code == 202:
                    INFO(f"{item['status']['name']} bp approved successfully.")
                else:
                    raise Exception(
                        f"{item['status']['name']} bp approved failed with:\n"
                        + f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                        f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #5
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        subnet_spec = file_to_dict("specs/calm_subnet.spec")
        INFO(f"subnet_spec: {subnet_spec}")
        bp_spec = file_to_dict("specs/calm_bp_upload.spec")
        INFO(f"bp_spec: {bp_spec}")

        # Get our subnet info from the infra
        subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                      subnet_spec["vlan"])

        # Loop through the blueprints to upload
        for bp in bp_spec["entities"]:

            # Get our project uuid and create our payload
            project_uuid = uuid_via_v3_post(pc_external_ip, "projects",
                                            pc_password, bp["bp_project"])
            payload = {"name": bp["bp_name"], "project_uuid": project_uuid}

            # Upload our blueprint
            resp = upload_bp_via_v3_post(pc_external_ip, pc_password, payload,
                                         bp["bp_file"])

            # Log appropriately based on response
            if (resp.code == 200 or resp.code == 202):
                INFO(f"{bp['bp_name']} blueprint created successfully.")
            else:
                raise Exception(f"{bp['bp_name']} blueprint create" +
                                f" failed with:\n" +
                                f"Error Code: {resp.code}\n" +
                                f"Error Message: {resp.message}")

    except Exception as ex:
        INFO(ex)
예제 #6
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the delete spec file
        delete_spec = file_to_dict("specs/calm_app_delete.json")

        # Loop through the apps to delete
        for app in delete_spec["entities"]:

            # Get the app uuid
            app_uuid = uuid_via_v3_post(pc_external_ip, "apps", pc_password,
                                        app["app_name"])

            # Handle soft_delete
            if app["soft_delete"]:
                app_uuid = app_uuid + "?type=soft"

            # Delete the app
            resp = del_via_v3_delete(pc_external_ip, "apps", pc_password,
                                     app_uuid)

            # Log appropriately based on response
            if resp.code == 200 or resp.code == 202:
                INFO(f'{app["app_name"]} app deleted successfully.')
            else:
                raise Exception(
                    'f{app["app_name"]} app delete failed with:\n' +
                    f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                    f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #7
0
def main():

    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    cvm_info = config.get("tdaas_cluster")
    cvm_external_ip = cvm_info.get("ips")[0][0]
    cluster = NOSCluster(cluster=cvm_external_ip, configured=False)

    autodc_spec = file_to_dict("specs/pc_autodc.spec")
    subnet_spec = file_to_dict("specs/calm_subnet.spec")
    INFO("autodc_spec: " + str(autodc_spec))
    INFO("subnet_spec: " + str(subnet_spec))
    autodc_ip = autodc_spec["directoryUrl"].split("/")[2].split(":")[0]

    create_vm(cluster=cluster,
              vm_name='AutoDC2',
              image_name='AutoDC2.qcow2',
              network_name=subnet_spec["name"],
              assigned_ip=autodc_ip)
예제 #8
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        icon_spec = file_to_dict("specs/calm_icon.spec")
        INFO(f"icon_spec: {icon_spec}")

        # Loop through the blueprints to upload
        for icon in icon_spec["entities"]:

            # Create our payload
            payload = {"name": icon["name"]}

            # Upload our icon
            resp = upload_icon_via_v3_post(pc_external_ip, pc_password,
                                           payload, icon)

            # Log appropriately based on response
            if (resp.code == 200 or resp.code == 202):
                INFO(f"{icon['name']} icon created successfully.")
            else:
                raise Exception(f"{icon['name']} icon create" +
                                f" failed with:\n" +
                                f"Error Code: {resp.code}\n" +
                                f"Error Message: {resp.message}")

    except Exception as ex:
        INFO(ex)
예제 #9
0
def main(project_name):

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        project_spec = file_to_dict("specs/calm_project.spec")
        INFO(f"project_spec pre-update: {project_spec}")
        subnet_spec = file_to_dict("specs/calm_subnet.spec")
        INFO(f"subnet_spec pre-update: {subnet_spec}")

        # Get our info from the infra
        subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                      subnet_spec["vlan"])
        account_info = body_via_v3_post(pc_external_ip, "accounts",
                                        pc_password, None)

        # Cycle through our accounts to find the right one
        for account in account_info.json["entities"]:
            if account["status"]["resources"]["type"] == "nutanix_pc":

                # Update our project_spec
                project_spec["spec"]["name"] = project_name
                project_spec["spec"]["resources"]["subnet_reference_list"][0]\
                            ["name"] = subnet_info["name"]
                project_spec["spec"]["resources"]["subnet_reference_list"][0]\
                            ["uuid"] = subnet_info["uuid"]
                project_spec["spec"]["resources"]["account_reference_list"][0]\
                            ["name"] = account["metadata"]["name"]
                project_spec["spec"]["resources"]["account_reference_list"][0]\
                            ["uuid"] = account["metadata"]["uuid"]
                INFO(f"project_spec post-update: {project_spec}")

                # Make API call to create project
                resp = create_via_v3_post(pc_external_ip, "projects",
                                          pc_password, project_spec)

                # Log appropriately based on response
                if (resp.code == 200 or resp.code == 202):
                    INFO(
                        f"{project_spec['spec']['name']} Project created successfully."
                    )
                else:
                    raise Exception(
                        f"{project_spec['spec']['name']} Project create" +
                        f" failed with:\n" + f"Error Code: {resp.code}\n" +
                        f"Error Message: {resp.message}")

    except Exception as ex:
        INFO(ex)
예제 #10
0
def create_via_v3_post(ip, endpoint, password, body):

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(ip, f"{endpoint}"),
                                   username="******",
                                   password=password,
                                   method="post",
                                   payload=json.dumps(body),
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"create_via_v3_post: {ip}, {endpoint}")

    return resp
예제 #11
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in our public key and create our payload
        public_key = file_to_string("/root/.ssh/id_rsa.pub")
        INFO(f"public_key: {public_key}")
        payload = {"name": "plugin-runner", "key": public_key}

        # Make API call to configure the authconfig
        resp = create_via_v1_post(
            pc_external_ip,
            "cluster/public_keys",
            pc_password,
            payload,
        )

        # Log appropriately based on response
        if resp.code == 200 or resp.code == 202:
            INFO("SSH Key added to PC successfully.")
        else:
            raise Exception(f"SSH Key failed to add to PC with:\n" +
                            f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                            f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #12
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec file and conver to dict
        image_spec = file_to_dict("specs/calm_image.spec")
        INFO(f"image_spec: {image_spec}")

        # Loop through each image
        for image in image_spec["entities"]:

            # Make API call to create image
            resp = create_via_v3_post(pc_external_ip, "images", pc_password,
                                      image)

            # Log appropriately based on response
            if (resp.code == 200 or resp.code == 202):
                INFO(f"image['spec']['name'] Image created successfully.")
            else:
                raise Exception(f"image['spec']['name'] Image create " +
                                f"failed with:\n" +
                                f"Error Code: {resp.code}\n" +
                                f"Error Message: {resp.message}")

    except Exception as ex:
        INFO(ex)
예제 #13
0
def update_via_v3_put(ip, endpoint, password, entity_uuid, body):

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(
        ip, f"{endpoint}/{entity_uuid}"),
                                   username="******",
                                   password=password,
                                   method="put",
                                   payload=json.dumps(body),
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"update_via_v3_put: {ip}, {endpoint}, {entity_uuid}")

    # Return the response
    return resp
예제 #14
0
def body_via_v3_get(ip, endpoint, password, entity_uuid):

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(
        ip, f"{endpoint}/{entity_uuid}"),
                                   username="******",
                                   password=password,
                                   method="get",
                                   payload=None,
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"body_via_v3_get: {ip}, {endpoint}, {entity_uuid}")

    # Return the response
    return resp
예제 #15
0
def del_via_v3_delete(ip, endpoint, password, entity_uuid):
    """Delete a given entity with a DELETE"""

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(
        ip, f"{endpoint}/{entity_uuid}"),
                                   username="******",
                                   password=password,
                                   method="delete",
                                   payload=None,
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"del_via_v3_delete: {ip}, {endpoint}, {entity_uuid}")

    # Return the response
    return resp
예제 #16
0
def create_via_v1_post(ip, endpoint, password, body):
    """Create a new entity via a v1 post call, return the response"""

    # Make the API call
    parameters = RequestParameters(
        uri=create_v1_url(ip, f"{endpoint}"),
        username="******",
        password=password,
        method="post",
        payload=json.dumps(body),
        files=None,
    )
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"create_via_v1_post: {ip}, {endpoint}")

    return resp
예제 #17
0
def upload_bp_via_v3_post(ip, password, body, filename):

    # Create the file dictionary
    files = {"file": open(f"blueprints/{filename}", "rb")}

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(ip,
                                                     "blueprints/import_file"),
                                   username="******",
                                   password=password,
                                   method="post",
                                   payload=body,
                                   files=files)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"upload_bp_via_v3_post: {ip}, {body}")

    return resp
예제 #18
0
def body_via_v3_post(ip, endpoint, password, payload):

    # Determine payload
    if payload is None:
        payload = {"length": 100}

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(ip, f"{endpoint}/list"),
                                   username="******",
                                   password=password,
                                   method="post",
                                   payload=json.dumps(payload),
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"body_via_v3_post: {ip}, {endpoint}")

    # Return the response
    return resp
예제 #19
0
def uuid_via_v3_post(ip, endpoint, password, entity_name):

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(ip, f"{endpoint}/list"),
                                   username="******",
                                   password=password,
                                   method="post",
                                   payload="{\"length\": 100}",
                                   files=None)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"uuid_via_v3_post: {ip}, {endpoint}, {entity_name}")

    # Return UUID
    for entity in resp.json["entities"]:
        if entity_name == "":
            return entity["metadata"]["uuid"]
        elif entity["status"]["name"] == entity_name:
            return entity["metadata"]["uuid"]
예제 #20
0
def upload_icon_via_v3_post(ip, password, body, icon):

    # Create the file dictionary
    files = {
        "image": (icon["name"], open(f"images/{icon['file']}",
                                     "rb"), "image/png")
    }

    # Make the API call
    parameters = RequestParameters(uri=create_v3_url(ip, "app_icons/upload"),
                                   username="******",
                                   password=password,
                                   method="post",
                                   payload=body,
                                   files=files)
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"upload_icon_via_v3_post: {ip}, {body}")

    return resp
예제 #21
0
def main():
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])

    INFO(config)

    cvm_info = config.get("tdaas_cluster")

    cvm_external_ip = cvm_info.get("ips")[0][0]
    cvm_internal_ip = cvm_info.get("ips")[0][1]

    cluster = NOSCluster(cluster=cvm_external_ip, configured=False)
    create_vm_image(cluster=cluster,
                    name='tinycore_loadrunner',
                    source_url='https://s3.amazonaws.com'
                    '/ntnx-portal-sb/temp/demo/'
                    'TinyCoreHRApp.vdi')

    create_vms(cluster=cluster,
               num_VMs=1,
               vm_name='tinyloadrunner',
               image_name='tinycore_loadrunner')

    time.sleep(30)
예제 #22
0
def uuid_via_v3_post(ip, endpoint, password, entity_name):
    """Return the UUID of a desired entity.  If entity_name is empty
     assume a single entity in response and send first UUID"""

    # Make the API call
    parameters = RequestParameters(
        uri=create_v3_url(ip, f"{endpoint}/list"),
        username="******",
        password=password,
        method="post",
        payload='{"length": 100}',
        files=None,
    )
    rest_client = RESTClient(parameters)
    resp = rest_client.request()
    INFO(f"uuid_via_v3_post: {ip}, {endpoint}, {entity_name}")

    # Return UUID
    for entity in resp.json["entities"]:
        if entity_name == "":
            return entity["metadata"]["uuid"]
        elif entity["status"]["name"] == entity_name:
            return entity["metadata"]["uuid"]
예제 #23
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Convert our spec to dict
        apps_spec = file_to_dict("specs/calm_bp_publish.json")

        # Get our non-default projects before the loop
        projects_payload = {"filter": "name!=default"}
        projects_resp = body_via_v3_post(pc_external_ip, "projects",
                                         pc_password, projects_payload)

        # Loop through our to-be-published apps
        for app in apps_spec["entities"]:

            # Construct payload and make call
            mp_payload = {"filter": f"name=={app['mp_name']}"}
            mp_post = body_via_v3_post(pc_external_ip,
                                       "calm_marketplace_items", pc_password,
                                       mp_payload)

            # Loop through our response to find matching version
            for mp_item in mp_post.json["entities"]:
                if (mp_item["status"]["app_state"] == "ACCEPTED"
                        and mp_item["status"]["version"] == app["bp_version"]
                        and mp_item["status"]["app_source"]
                        == app["app_source"]):

                    # Make a GET with our UUID
                    mp_get = body_via_v3_get(
                        pc_external_ip,
                        "calm_marketplace_items",
                        pc_password,
                        mp_item["metadata"]["uuid"],
                    )

                    # Modify the response body
                    mp_body = mp_get.json
                    del mp_body["status"]
                    mp_body["spec"]["resources"]["app_state"] = "PUBLISHED"
                    for project in projects_resp.json["entities"]:
                        mp_body["spec"]["resources"][
                            "project_reference_list"].append(
                                project["metadata"]["project_reference"])

                    # Publish the blueprint
                    pub_resp = update_via_v3_put(
                        pc_external_ip,
                        "calm_marketplace_items",
                        pc_password,
                        mp_body["metadata"]["uuid"],
                        mp_body,
                    )

                    # Log appropriately based on response
                    if pub_resp.code == 200 or pub_resp.code == 202:
                        INFO(
                            f"{mp_body['spec']['name']} MP item published successfully."
                        )
                    else:
                        raise Exception(
                            f"{mp_body['spec']['name']} MP App Publish failed with:\n"
                            + f"Resp: {resp}\n" +
                            f"Error Code: {pub_resp.code}\n" +
                            f"Error Message: {pub_resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #24
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and convert to dicts
        env_spec = file_to_dict("specs/calm_environment.json")
        image_spec = file_to_dict("specs/pc_image.json")
        subnet_spec = file_to_dict("specs/calm_subnet.json")
        secret_spec = file_to_dict("specs/calm_secrets.json")

        # Get our subnet info from the infra
        subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                      subnet_spec["entities"][0]["vlan"])
        INFO(f"subnet_uuid: {subnet_info['uuid']}")

        # Get our image info from the infra
        cent_image_name = image_spec["entities"][0]["metadata"]["name"]
        cent_image_uuid = uuid_via_v3_post(pc_external_ip, "images",
                                           pc_password, cent_image_name)
        INFO(f"cent_image_uuid: {cent_image_uuid}")
        # win_image_name = image_spec["entities"][1]["metadata"]["name"]
        # win_image_uuid = uuid_via_v3_post(pc_external_ip, "images",
        #                                   pc_password, win_image_name)
        # INFO(f"win_image_uuid: {win_image_uuid}")

        # Generate UUIDs for new components
        env_name = str(uuid.uuid4())
        env_uuid = str(uuid.uuid4())
        cent_substrate_uuid = str(uuid.uuid4())
        # win_substrate_uuid = str(uuid.uuid4())
        cent_key_uuid = str(uuid.uuid4())
        cent_pass_uuid = str(uuid.uuid4())
        # win_pass_uuid = str(uuid.uuid4())

        # Sub in our UUIDs and names:
        # env
        env_spec["spec"]["name"] = env_name
        env_spec["metadata"]["name"] = env_name
        env_spec["metadata"]["uuid"] = env_uuid

        # substrate
        env_spec["spec"]["resources"]["substrate_definition_list"][0][
            "uuid"] = cent_substrate_uuid
        # env_spec["spec"]["resources"]["substrate_definition_list"][1]\
        #        ["uuid"] = win_substrate_uuid

        # account
        env_spec["spec"]["resources"]["substrate_definition_list"][0][
            "readiness_probe"]["login_credential_local_reference"][
                "uuid"] = cent_key_uuid
        # env_spec["spec"]["resources"]["substrate_definition_list"][1]\
        #        ["readiness_probe"]["login_credential_local_reference"]\
        #        ["uuid"] = win_pass_uuid

        # subnet
        env_spec["spec"]["resources"]["substrate_definition_list"][0][
            "create_spec"]["resources"]["nic_list"][0]["subnet_reference"][
                "uuid"] = subnet_info["uuid"]
        # env_spec["spec"]["resources"]["substrate_definition_list"][1]\
        #        ["create_spec"]["resources"]["nic_list"][0]\
        #        ["subnet_reference"]["uuid"] = subnet_info["uuid"]

        # image
        env_spec["spec"]["resources"]["substrate_definition_list"][0][
            "create_spec"]["resources"]["disk_list"][0][
                "data_source_reference"]["name"] = cent_image_name
        env_spec["spec"]["resources"]["substrate_definition_list"][0][
            "create_spec"]["resources"]["disk_list"][0][
                "data_source_reference"]["uuid"] = cent_image_uuid
        # env_spec["spec"]["resources"]["substrate_definition_list"][1]\
        #        ["create_spec"]["resources"]["disk_list"][0]\
        #        ["data_source_reference"]["name"] = win_image_name
        # env_spec["spec"]["resources"]["substrate_definition_list"][1]\
        #        ["create_spec"]["resources"]["disk_list"][0]\
        #        ["data_source_reference"]["uuid"] = win_image_uuid

        # secrets
        for secret in secret_spec["entities"]:
            if secret["name"] == "CENTOS_KEY":
                suuid = cent_key_uuid
            elif secret["name"] == "CENTOS_PASS":
                suuid = cent_pass_uuid
            else:
                continue
            env_spec["spec"]["resources"]["credential_definition_list"].append(
                {
                    "name": secret["name"],
                    "type": secret["type"],
                    "username": secret["username"],
                    "secret": {
                        "attrs": {
                            "is_secret_modified": True
                        },
                        "value": secret["secret"],
                    },
                    "uuid": suuid,
                })

        # Make the API call to create the environment
        INFO(f"env_spec: {env_spec}")
        resp = create_via_v3_post(pc_external_ip, "environments", pc_password,
                                  env_spec)

        # Log appropriately based on response
        if resp.code == 200 or resp.code == 202:
            INFO(f"{env_spec['spec']['name']} Env created successfully.")
        else:
            raise Exception(
                f"{env_spec['spec']['name']} Env create failed with:\n" +
                f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #25
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    # Get PE info from the config dict
    pe_info = config.get("tdaas_cluster")
    pe_external_ip = pe_info.get("ips")[0][0]
    pe_internal_ip = pe_info.get("ips")[0][1]
    pe_password = pe_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        subnet_spec = file_to_dict("specs/calm_subnet.json")
        INFO(f"subnet_spec: {subnet_spec}")
        secret_spec = file_to_dict("specs/calm_secrets.json")
        INFO(f"secret_spec: {secret_spec}")

        # Get our subnet and image info from the infra
        subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                      subnet_spec["entities"][0]["vlan"])
        infra_subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                            subnet_spec["entities"][1]["vlan"])
        image_info = body_via_v3_post(pc_external_ip, "images", pc_password,
                                      None).json

        # If we have Public UVMs / Proxy IPs, then get our array
        proxy_array = []
        if "proxy_vm" in config:
            proxy_array = create_proxy_array(config["proxy_vm"])

        # Get a list of DRAFT blueprints
        payload = {"filter": "state==DRAFT"}
        draft_resp = body_via_v3_post(pc_external_ip, "blueprints",
                                      pc_password, payload).json

        # Loop through the blueprints to modify
        for bp in draft_resp["entities"]:

            # Get the body of our blueprint
            bp_body = body_via_v3_get(pc_external_ip, "blueprints",
                                      pc_password, bp["metadata"]["uuid"]).json

            # Remove unneeded status
            del bp_body["status"]

            # Configure secrets
            for secret in bp_body["spec"]["resources"][
                    "credential_definition_list"]:
                secret["secret"]["attrs"]["is_secret_modified"] = True
                # Handle PE and PC Creds which are unique
                if secret["name"].lower() == "pc_creds":
                    secret["secret"]["username"] = "******"
                    secret["secret"]["value"] = pc_password
                elif secret["name"].lower() == "pe_creds":
                    secret["secret"]["username"] = "******"
                    secret["secret"]["value"] = pe_password
                # Find a matching type/username from our secret_spec
                else:
                    for ss in secret_spec["entities"]:
                        if (secret["type"] == ss["type"]
                                and secret["username"] == ss["username"]):
                            secret["secret"]["value"] = ss["secret"]
                INFO(f"secret: {secret}")

            # Configure NICs and Images
            for substrate in bp_body["spec"]["resources"][
                    "substrate_definition_list"]:
                if substrate["type"] == "AHV_VM":

                    # For NICs, determine if it's an infra or user VM based blueprint
                    for nic in substrate["create_spec"]["resources"][
                            "nic_list"]:
                        if "infra" in bp_body["metadata"]["name"].lower():
                            # Ensure we have a proxy_vm config
                            if len(proxy_array) > 0:
                                nic["subnet_reference"][
                                    "uuid"] = infra_subnet_info["uuid"]
                                nic["subnet_reference"][
                                    "name"] = infra_subnet_info["name"]
                                proxy_ips = proxy_array.pop()
                                nic["ip_endpoint_list"][0]["ip"] = proxy_ips[1]
                            else:
                                ERROR(
                                    f'Blueprint "{bp_body["metadata"]["name"]}" has '
                                    +
                                    f'"infra" in the name, but there were not enough '
                                    + f" proxy IPs configured: {config}. If" +
                                    f" this application needs external access, "
                                    +
                                    f"please ensure enough proxy IPs are in your GCP "
                                    +
                                    f'cluster.  Otherwise, remove "infra" from the '
                                    + f"blueprint name.")
                        else:
                            nic["subnet_reference"]["uuid"] = subnet_info[
                                "uuid"]
                            nic["subnet_reference"]["name"] = subnet_info[
                                "name"]
                        print(json.dumps(nic, sort_keys=True, indent=4))

                    for disk in substrate["create_spec"]["resources"][
                            "disk_list"]:
                        if (disk["data_source_reference"] is not None
                                and disk["data_source_reference"]["kind"]
                                == "image"):
                            for image in image_info["entities"]:
                                if (image["status"]["name"] ==
                                        disk["data_source_reference"]["name"]):
                                    disk["data_source_reference"][
                                        "uuid"] = image["metadata"]["uuid"]
                                    print(
                                        json.dumps(disk,
                                                   sort_keys=True,
                                                   indent=4))

            # Update our blueprint
            resp = update_via_v3_put(
                pc_external_ip,
                "blueprints",
                pc_password,
                bp["metadata"]["uuid"],
                bp_body,
            )

            # Log appropriately based on response
            if resp.code == 200 or resp.code == 202:
                INFO(
                    f"{bp['metadata']['name']} blueprint updated successfully."
                )
            else:
                raise Exception(
                    f"{bp['metadata']['name']} blueprint update failed with:\n"
                    + f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                    f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #26
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        subnet_spec = file_to_dict("specs/calm_subnet.spec")
        INFO(f"subnet_spec: {subnet_spec}")
        secret_spec = file_to_dict("specs/calm_secrets.spec")
        INFO(f"secret_spec: {secret_spec}")

        # Get our subnet and image info from the infra
        subnet_info = get_subnet_info(pc_external_ip, pc_password,
                                      subnet_spec["vlan"])
        image_info = body_via_v3_post(pc_external_ip, "images", pc_password,
                                      None).json

        # Get a list of DRAFT blueprints
        payload = {"filter": "state==DRAFT"}
        draft_resp = body_via_v3_post(pc_external_ip, "blueprints",
                                      pc_password, payload).json

        # Loop through the blueprints to modify
        for bp in draft_resp["entities"]:

            # Get the body of our blueprint
            bp_body = body_via_v3_get(pc_external_ip, "blueprints",
                                      pc_password, bp["metadata"]["uuid"]).json

            # Remove unneeded status
            del bp_body["status"]

            # Configure secrets
            for secret in bp_body["spec"]["resources"]\
                                 ["credential_definition_list"]:
                secret["secret"]["attrs"]["is_secret_modified"] = True
                # Find a matching type/username from our secret_spec
                for ss in secret_spec["entities"]:
                    if secret["type"] == ss["type"] and\
                       secret["username"] == ss["username"]:
                        secret["secret"]["value"] = ss["secret"]
                print(json.dumps(secret, sort_keys=True, indent=4))

            # Configure NICs and Images
            for substrate in bp_body["spec"]["resources"][
                    "substrate_definition_list"]:
                if substrate["type"] == "AHV_VM":
                    for nic in substrate["create_spec"]["resources"][
                            "nic_list"]:
                        nic["subnet_reference"]["uuid"] = subnet_info["uuid"]
                        nic["subnet_reference"]["name"] = subnet_info["name"]
                        print(json.dumps(nic, sort_keys=True, indent=4))
                    for disk in substrate["create_spec"]["resources"][
                            "disk_list"]:
                        if disk["data_source_reference"] is not None and\
                           disk["data_source_reference"]["kind"] == "image":
                            for image in image_info["entities"]:
                                if image["status"]["name"] == disk[
                                        "data_source_reference"]["name"]:
                                    disk["data_source_reference"][
                                        "uuid"] = image["metadata"]["uuid"]
                                    print(
                                        json.dumps(disk,
                                                   sort_keys=True,
                                                   indent=4))

            # Update our blueprint
            resp = update_via_v3_put(pc_external_ip, "blueprints", pc_password,
                                     bp["metadata"]["uuid"], bp_body)

            # Log appropriately based on response
            if (resp.code == 200 or resp.code == 202):
                INFO(
                    f"{bp['metadata']['name']} blueprint updated successfully."
                )
            else:
                raise Exception(f"{bp['metadata']['name']} blueprint update" +
                                f" failed with:\n" +
                                f"Error Code: {resp.code}\n" +
                                f"Error Message: {resp.message}")

    except Exception as ex:
        INFO(ex)
예제 #27
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and convert to dicts
        launch_spec = file_to_dict("specs/calm_bp_launch.spec")
        INFO(f"launch_spec: {launch_spec}")

        # Loop through the blueprints to launch
        for launch in launch_spec["entities"]:

            # Get our blueprint uuid
            payload = {"filter": f"name=={launch['bp_name']}"}
            bp = body_via_v3_post(pc_external_ip, "blueprints", pc_password,
                                  payload).json
            if bp["metadata"]["total_matches"] != 1:
                raise Exception(
                    str(bp["metadata"]["total_matches"]) +
                    " blueprints found, when 1 should" + " have been found.")
            else:
                bp_uuid = bp["entities"][0]["metadata"]["uuid"]

            # Get our runtime editables
            editables = body_via_v3_get(pc_external_ip, "blueprints",
                                        pc_password,
                                        bp_uuid + "/runtime_editables").json
            for profile in editables["resources"]:
                if profile["app_profile_reference"]["name"] ==\
                   launch["profile_name"]:
                    profile_ref = profile["app_profile_reference"]
                    run_editables = profile["runtime_editables"]
            INFO(f"{launch['bp_name']} profile_ref: {profile_ref}")
            INFO(f"{launch['bp_name']} run_editables: {run_editables}")

            # Set our runtime variables
            if "variable_list" in run_editables:
                for run_edit_var in run_editables["variable_list"]:
                    for launch_var in launch["variables"]:
                        if run_edit_var["name"] == launch_var["name"]:
                            run_edit_var["value"]["value"] = launch_var[
                                "value"]
                INFO(f"{launch['bp_name']} run_editables: {run_editables}")

            # Create our payload and launch our app
            payload = {
                "spec": {
                    "app_name": launch["app_name"],
                    "app_description": launch["app_description"],
                    "app_profile_reference": profile_ref,
                    "runtime_editables": run_editables
                }
            }
            resp = create_via_v3_post(
                pc_external_ip, "blueprints/" + bp_uuid + "/simple_launch",
                pc_password, payload)

            # Log appropriately based on response
            if (resp.code == 200 or resp.code == 202):
                INFO(f"{launch['app_name']} app launched successfully.")
            else:
                raise Exception(f"{launch['app_name']} app launch" +
                                f" failed with:\n" +
                                f"Error Code: {resp.code}\n" +
                                f"Error Message: {resp.message}")

            time.sleep(2)

    except Exception as ex:
        INFO(ex)
예제 #28
0
def main(launch):

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and convert to dicts
        launch_spec = file_to_dict(f"specs/{launch}")
        INFO(f"launch_spec: {launch_spec}")

        # Loop through the blueprints to launch
        for launch in launch_spec["entities"]:

            # Get our blueprint uuid
            payload = {"filter": f"name=={launch['bp_name']}"}
            bp = body_via_v3_post(
                pc_external_ip, "blueprints", pc_password, payload
            ).json
            if bp["metadata"]["total_matches"] != 1:
                raise Exception(
                    str(bp["metadata"]["total_matches"])
                    + " blueprints found, when 1 should"
                    + " have been found."
                )
            else:
                bp_uuid = bp["entities"][0]["metadata"]["uuid"]

            # Get our runtime editables
            editables = body_via_v3_get(
                pc_external_ip,
                "blueprints",
                pc_password,
                bp_uuid + "/runtime_editables",
            ).json
            for profile in editables["resources"]:
                if profile["app_profile_reference"]["name"] == launch["profile_name"]:
                    profile_ref = profile["app_profile_reference"]
                    run_editables = profile["runtime_editables"]
            INFO(f"{launch['bp_name']} profile_ref: {profile_ref}")
            INFO(f"{launch['bp_name']} run_editables: {run_editables}")

            # Determine if this blueprint has an app dependency
            if "dependencies" in launch and len(launch["dependencies"]) > 0:
                # Get a list of running apps
                apps = body_via_v3_post(pc_external_ip, "apps", pc_password, None).json
                # Cycle through the apps
                for app in apps["entities"]:
                    # Cycle through our launch dependencies
                    for depend in launch["dependencies"]:
                        # Find the matching app name
                        if app["status"]["name"] == depend["app_name"]:
                            # Get app body
                            app_body = body_via_v3_get(
                                pc_external_ip,
                                "apps",
                                pc_password,
                                app["metadata"]["uuid"],
                            ).json
                            # Loop through our dependency values
                            for value in depend["values"]:
                                # Get value from our body+key combo
                                app_val = recursive_dict_lookup(app_body, value["keys"])
                                # Set our app_val to the appropriate variable value
                                for launch_var in launch["variables"]:
                                    if value["name"] == launch_var["name"]:
                                        launch_var["value"] = app_val
                INFO(f'{launch["bp_name"]} vars after depend: {launch["variables"]}')

            # Set our runtime variables
            if "variable_list" in run_editables:
                for run_edit_var in run_editables["variable_list"]:
                    for launch_var in launch["variables"]:
                        if run_edit_var["name"] == launch_var["name"]:
                            run_edit_var["value"]["value"] = launch_var["value"]
                INFO(f"{launch['bp_name']} run_editables: {run_editables}")

            # Create our payload and launch our app
            payload = {
                "spec": {
                    "app_name": launch["app_name"],
                    "app_description": launch["app_description"],
                    "app_profile_reference": profile_ref,
                    "runtime_editables": run_editables,
                }
            }
            resp = create_via_v3_post(
                pc_external_ip,
                "blueprints/" + bp_uuid + "/simple_launch",
                pc_password,
                payload,
            )

            # Log appropriately based on response
            if resp.code == 200 or resp.code == 202:
                INFO(f"{launch['app_name']} app launched successfully.")
            else:
                raise Exception(
                    f"{launch['app_name']} app launch failed with:\n"
                    + f"Resp: {resp}\n"
                    + f"Error Code: {resp.code}\n"
                    + f"Error Message: {resp.message}"
                )

            time.sleep(2)

    except Exception as ex:
        ERROR(traceback.format_exc())
예제 #29
0
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Read in the spec files and conver to dicts
        publish_spec = file_to_dict("specs/calm_bp_publish.json")
        INFO(f"publish_spec: {publish_spec}")

        # Get user and icon info
        user_info = body_via_v3_get(pc_external_ip, "users", pc_password,
                                    "me").json
        icon_info = body_via_v3_post(pc_external_ip, "app_icons", pc_password,
                                     None).json

        # Loop through the blueprints to upload
        for publish in publish_spec["entities"]:

            # Create our payload and get bp uuid
            payload = {"filter": f"name=={publish['bp_name']}"}
            bp_info = body_via_v3_post(pc_external_ip, "blueprints",
                                       pc_password, payload).json
            bp_uuid = bp_info["entities"][0]["metadata"]["uuid"]

            # Get bp spec with uuid
            bp = body_via_v3_get(
                pc_external_ip,
                "blueprints",
                pc_password,
                f"{bp_uuid}/export_json?keep_secrets=true",
            ).json

            # Modify our body
            bp["spec"]["name"] = publish["mp_name"]
            bp["spec"]["description"] = publish["mp_description"]
            bp["status"]["name"] = publish["mp_name"]
            bp["status"]["description"] = publish["mp_description"]
            spec = copy.deepcopy(bp["spec"])
            status = copy.deepcopy(bp["status"])
            del bp["spec"]["resources"]
            del bp["status"]
            bp["metadata"]["kind"] = "marketplace_item"
            bp["spec"]["resources"] = {"app_attribute_list": ["FEATURED"]}
            bp["spec"]["resources"]["app_state"] = "PENDING"
            bp["spec"]["resources"]["project_reference_list"] = []
            bp["spec"]["resources"]["change_log"] = ""
            bp["spec"]["resources"]["app_source"] = "LOCAL"
            bp["spec"]["resources"]["app_group_uuid"] = str(uuid.uuid4())
            bp["spec"]["resources"]["author"] = user_info["status"]["name"]
            for icon in icon_info["entities"]:
                if icon["status"]["name"] == publish["icon_name"]:
                    bp["spec"]["resources"]["icon_reference_list"] = [{
                        "icon_reference": {
                            "kind": "file_item",
                            "uuid": icon["metadata"]["uuid"],
                        },
                        "icon_type":
                        "ICON",
                    }]
            bp["spec"]["resources"]["version"] = publish["bp_version"]
            bp["spec"]["resources"]["app_blueprint_template"] = {"spec": spec}
            bp["spec"]["resources"]["app_blueprint_template"][
                "status"] = status

            # Upload our marketplace item
            resp = create_via_v3_post(pc_external_ip, "calm_marketplace_items",
                                      pc_password, bp)

            # Log appropriately based on response
            if resp.code == 200 or resp.code == 202:
                INFO(f"{publish['mp_name']} bp published successfully.")
            else:
                raise Exception(
                    f"{publish['mp_name']} bp publish failed with:\n" +
                    f"Resp: {resp}\n" + f"Error Code: {resp.code}\n" +
                    f"Error Message: {resp.message}")

    except Exception as ex:
        ERROR(traceback.format_exc())
def main():

    # Get and log the config from the Env variable
    config = json.loads(os.environ["CUSTOM_SCRIPT_CONFIG"])
    INFO(config)

    # Get PC info from the config dict
    pc_info = config.get("tdaas_pc")
    pc_external_ip = pc_info.get("ips")[0][0]
    pc_internal_ip = pc_info.get("ips")[0][1]
    pc_password = pc_info.get("prism_password")

    try:

        # Convert our spec to dict
        subnet_spec = file_to_dict("specs/calm_subnet.json")

        # Get our info from the infra
        subnet_info = get_subnet_info(
            pc_external_ip, pc_password, subnet_spec["entities"][0]["vlan"]
        )
        if "proxy_vm" in config:
            public_subnet_info = get_subnet_info(
                pc_external_ip, pc_password, subnet_spec["entities"][1]["vlan"]
            )
        account_info = body_via_v3_post(pc_external_ip, "accounts", pc_password, None)
        env_uuid = uuid_via_v3_post(pc_external_ip, "environments", pc_password, "")

        # Get the pojects body
        project_resp = body_via_v3_post(pc_external_ip, "projects", pc_password, None)

        # Loop through each project to add the env
        for project in project_resp.json["entities"]:

            # Delete the unneeded "status"
            del project["status"]

            # If default project, add subnet_ref_list
            if project["spec"]["name"] == "default":

                # add subnet if not present
                if len(project["spec"]["resources"]["subnet_reference_list"]) == 0:
                    project["spec"]["resources"]["subnet_reference_list"].append(
                        {
                            "kind": "subnet",
                            "name": subnet_info["name"],
                            "uuid": subnet_info["uuid"],
                        }
                    )
                    if "proxy_vm" in config:
                        project["spec"]["resources"]["subnet_reference_list"].append(
                            {
                                "kind": "subnet",
                                "name": public_subnet_info["name"],
                                "uuid": public_subnet_info["uuid"],
                            }
                        )

                # Add account if not present
                if len(project["spec"]["resources"]["account_reference_list"]) == 0:
                    for account in account_info.json["entities"]:
                        if account["status"]["resources"]["type"] == "nutanix_pc":
                            project["spec"]["resources"][
                                "account_reference_list"
                            ].append(
                                {
                                    "kind": "account",
                                    "name": account["metadata"]["name"],
                                    "uuid": account["metadata"]["uuid"],
                                }
                            )

            # Add env if not present
            if len(project["spec"]["resources"]["environment_reference_list"]) == 0:
                project["spec"]["resources"]["environment_reference_list"].append(
                    {"kind": "environment", "uuid": env_uuid}
                )

            # Make the API call to update the Project
            INFO(f"project: {project}")
            resp = update_via_v3_put(
                pc_external_ip,
                "projects",
                pc_password,
                project["metadata"]["uuid"],
                project,
            )

            # Log appropriately based on response
            if resp.code == 202 or resp.code == 200:
                INFO(f"{project['spec']['name']} Project updated successfully.")
            else:
                raise Exception(
                    f"{project['spec']['name']} Project update failed with:\n"
                    + f"Resp: {resp}\n"
                    + f"Error Code: {resp.code}\n"
                    + f"Error Message: {resp.message}"
                )

    except Exception as ex:
        ERROR(traceback.format_exc())