Chapter 1. Creating an Oracle Cloud integration To add an Oracle Cloud account to cost management, you must add your Oracle Cloud account as an integration from the Red Hat Hybrid Cloud Console user interface and configure Oracle Cloud to provide metrics. After you add your Oracle Cloud account to cost management as a data integration, you must configure a function script to copy the cost and usage reports to a bucket that cost management can access. Prerequisites Red Hat account user with Cloud Administrator entitlements Access to Oracle Cloud Console with access to the compartment you want to add to cost management A service on Oracle Cloud generating service usage As you will complete some of the following steps in Oracle Cloud, and some steps in the Red Hat Hybrid Cloud Console , log in to both applications and keep them open in a web browser. To begin, add your Oracle Cloud integration to cost management from the Integrations page using the Add a cloud integration dialog. 1.1. Adding an Oracle Cloud Infrastructure account and naming your integration Add your Oracle Cloud account as a integration. After adding an Oracle Cloud integration, the cost management application processes the cost and usage data from your Oracle Cloud account and makes it viewable. Procedure From Red Hat Hybrid Cloud Console , click Settings Menu > Integrations . On the Settings page, click Integrations . In the Cloud tab, click Add integration . In the Add a cloud integration wizard, select Oracle Cloud Infrastructure as the integration type. Click . Enter a name for your integration and click . In the Select application step, select Cost management . Click . 1.2. Collecting and storing your global compartment-id Continue in the Add a cloud integration wizard by collecting your global compartment-id , which is also known as your tenant-id in Microsoft Azure, so cost management can access your Oracle Cloud compartment. Procedure In the Add a cloud integration wizard, on the Global compartment-id step, copy the command in step one oci iam compartment list . In a new tab, log in to your Oracle Cloud account. In the menu bar, click Developer tools Cloud Shell . Paste the command you copied from the Add a cloud integration wizard in the Cloud Shell window. In the response, copy the value pair for the compartment-id key. In the following example, the ID starts with ocid1.tenancy.oc1 . Example response { "data": [ { "compartment-id": "ocid1.tenancy.oc1..00000000000000000000000000000000000000000000", "defined-tags": { "Oracle-Tags": { ... } }, ... } ] } Return to the Global compartment-id step in the Add a cloud integration wizard, and paste your tenant-id in the Global compartment-id field. Click . 1.3. Creating a policy to create cost and usage reports Continue in the Add a cloud integration wizard by creating a custom policy and compartment for Oracle Cloud to create and store cost and usage reports. Procedure In the Add a cloud integration wizard, on the Create new policy and compartment page, copy the oci iam policy create command. Paste the command that you copied into the Cloud Shell in your Oracle Cloud tab to create a cost and usage reports policy. You can also add a policy description. Return to the Create new policy and compartment step in the Add a cloud integration wizard and copy the oci iam compartment create command. Paste the command that you copied into the Cloud Shell in your Oracle Cloud tab to create a cost management compartment. In the response, copy the value for the id key. In the following example, copy the id that includes ocid1.compartment.oc1 . Example response { "data": [ { "compartment-id": "tenant-id", "defined-tags": { "Oracle-Tags": { ... } }, "description": "Cost management compartment for cost and usage data", "freeform-tags": {}, "id": "ocid1.compartment.oc1..0000000000000000000000000000000000000000000", ... }, ... ] } Return to the Create new policy and compartment step in the Add a cloud integration wizard and paste the id value you copied from the response in the last step into the New compartment-id field. Click . 1.4. Creating a bucket for accessible cost and usage reports Create a bucket to store cost and usage reports that that cost management can access. Procedure In the Create bucket step, create a bucket to store cost and usage data so that cost management can access it. Copy the command from the step and paste into the Cloud Shell in your Oracle Cloud tab to create a bucket. Refer to the example response for the steps. Example response { "data": { ... "name": "cost-management", "namespace": "cost-management-namespace", ... } } Copy the value pair for the name key. In the example, this value is cost-management . Return to the Create bucket step in the Add a cloud integration wizard. Paste the value you copied into New data bucket name . Return to your Cloud Shell and copy the value for the namespace key. In the example, copy cost-management-namespace . Return to the Create bucket step in the Add a cloud integration wizard and check your shell prompt for your region. For example, your shell prompt might be user@cloudshell:~ (uk-london-1)USD . In this example, uk-london-1 is your region. Copy your region and return to the Create bucket step in the Add a cloud integration wizard. In the Create bucket step in the Add a cloud integration wizard, paste your region in New bucket region . Click . 1.5. Replicating reports to a bucket Schedule a task to regularly move the cost information to the bucket you created by creating a function and then a virtual machine to trigger it. In the Populate bucket step, visit the link to the script you can use to create a function that must be paired with a virtual machine or CronJob to run daily. The Oracle Cloud documentation provides the following example of how to schedule a recurring job to run the cost transfer script . Note As non-Red Hat products and documentation can change, instructions for configuring the third-party processes provided in this guide are general and correct at the time of publishing. Contact Oracle Cloud for support. Procedure In the Oracle Cloud console , open the Navigation menu and click Developer Services Functions . Use the following Python script to create a function application: # #

Commands:
{ "data": [ { "compartment-id": "ocid1.tenancy.oc1..00000000000000000000000000000000000000000000", "defined-tags": { "Oracle-Tags": { } }, } ] }
{ "data": [ { "compartment-id": "tenant-id", "defined-tags": { "Oracle-Tags": { } }, "description": "Cost management compartment for cost and usage data", "freeform-tags": {}, "id": "ocid1.compartment.oc1..0000000000000000000000000000000000000000000", }, ] }
{ "data": { "name": "cost-management", "namespace": "cost-management-namespace", } }
# Copyright 2022 Red Hat Inc. SPDX-License-Identifier: Apache-2.0 # ########################################################################################## Script to collect cost/usage reports from OCI and replicate them to another bucket # Pre-req's you must have a service account or other for this script to gain access to oci # NOTE! You must update the vars below for this script to work correctly # user: ocid of user that has correct permissions for bucket objects key_file: Location of auth file for defind user fingerprint: Users fingerprint tenancy: Tenancy for collecting/copying cost/usage reports region: Home Region of your tenancy bucket: Name of Bucket reports will be replicated to namespace: Object Storage Namespace filename: Name of json file to store last report downloaded default hre is fine ########################################################################################## import datetime import io import json import logging import oci from fdk import response def connect_oci_storage_client(config): # Connect to OCI SDK try: object_storage = oci.object_storage.ObjectStorageClient(config) return object_storage except (Exception, ValueError) as ex: logging.getLogger().info("Error connecting to OCI SDK CLIENT please check credentials: " + str(ex)) def fetch_reports_file(object_storage, namespace, bucket, filename): # Fetch last download report file from bucket last_reports_file = None try: last_reports_file = object_storage.get_object(namespace, bucket, filename) except (Exception, ValueError) as ex: logging.getLogger().info("Object file does not exist, will attempt to create it: " + str(ex)) if last_reports_file: json_acceptable_string = last_reports_file.data.text.replace("'", '"') try: last_reports = json.loads(json_acceptable_string) except (Exception, ValueError) as ex: logging.getLogger().info( "Json string file not formatted correctly and cannont be parsed, creating fresh file. " + str(ex) ) last_reports = {"cost": "", "usage": ""} else: last_reports = {"cost": "", "usage": ""} return last_reports def get_report_list(object_storage, reporting_namespace, reporting_bucket, prefix, last_file): # Create a list of reports report_list = object_storage.list_objects( reporting_namespace, reporting_bucket, prefix=prefix, start_after=last_file, fields="timeCreated" ) logging.getLogger().info("Fetching list of cost csv files") return report_list def copy_reports_to_bucket( object_storage, report_type, report_list, bucket, namespace, region, reporting_namespace, reporting_bucket, last_reports, ): # Iterate through cost reports list and copy them to new bucket # Start from current month start_from = datetime.date.today().replace(day=1) if report_list.data.objects != []: for report in report_list.data.objects: if report.time_created.date() > start_from: try: copy_object_details = oci.object_storage.models.CopyObjectDetails( destination_bucket=bucket, destination_namespace=namespace, destination_object_name=report.name, destination_region=region, source_object_name=report.name, ) object_storage.copy_object( namespace_name=reporting_namespace, bucket_name=reporting_bucket, copy_object_details=copy_object_details, ) except (Exception, ValueError) as ex: logging.getLogger().info(f"Failed to copy {report.name} to bucket: {bucket}. " + str(ex)) last_reports[report_type] = report.name else: logging.getLogger().info(f"No new {report_type} reports to copy to bucket: {bucket}.") return last_reports def handler(ctx, data: io.BytesIO = None): name = "OCI-cost-mgmt-report-replication-function" try: body = json.loads(data.getvalue()) name = body.get("name") except (Exception, ValueError) as ex: logging.getLogger().info("Error parsing json payload: " + str(ex)) logging.getLogger().info("Inside Python OCI reporting copy function") # PLEASE CHANGE THIS!!!! # user = "ocid1.user.oc1..aaaaaa" # CHANGEME key_file = "auth_files/service-account.pem" # CHANGEME fingerprint = "00.00.00" # CHANGEME tenancy = "ocid1.tenancy.oc1..aaaaaaa" # CHANGEME region = "region" # CHANGEME bucket = "cost-mgmt-bucket" # CHANGEME namespace = "namespace" # CHANGEME filename = "last_reports.json" # Get the list of reports # https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clienvironmentvariables.htm!!! config = { "user": user, "key_file": key_file, "fingerprint": fingerprint, "tenancy": tenancy, "region": region, } # The Object Storage namespace used for OCI reports is bling; the bucket name is the tenancy OCID. reporting_namespace = "bling" reporting_bucket = config["tenancy"] region = config["region"] # Connect to OCI object_storage = connect_oci_storage_client(config) # Grab reports json and set previously downloaded file values last_reports = fetch_reports_file(object_storage, namespace, bucket, filename) last_cost_file = last_reports.get("cost") last_usage_file = last_reports.get("usage") # Get list of cost/usage files cost_report_list = get_report_list( object_storage, reporting_namespace, reporting_bucket, "reports/cost-csv", last_cost_file ) usage_report_list = get_report_list( object_storage, reporting_namespace, reporting_bucket, "reports/usage-csv", last_usage_file ) # Copy cost/usage files to new bucket last_reports = copy_reports_to_bucket( object_storage, "cost", cost_report_list, bucket, namespace, region, reporting_namespace, reporting_bucket, last_reports, ) last_reports = copy_reports_to_bucket( object_storage, "usage", usage_report_list, bucket, namespace, region, reporting_namespace, reporting_bucket, last_reports, ) # Save updated filenames to bucket object as string object_storage.put_object(namespace, bucket, filename, str(last_reports)) return response.Response( ctx, response_data=json.dumps( { "message": "Last reports saved from {}, Cost: {}, Usage: {}".format( name, last_reports["cost"], last_reports["usage"] ) } ), headers={"Content-Type": "application/json"}, )
user = "ocid1.user.oc1..aaaaaa" # CHANGEME key_file = "auth_files/service-account.pem" # CHANGEME fingerprint = "00.00.00" # CHANGEME tenancy = "ocid1.tenancy.oc1..aaaaaaa" # CHANGEME region = "region" # CHANGEME bucket = "cost-mgmt-bucket" # CHANGEME namespace = "namespace" # CHANGEME filename = "last_reports.json"