How to use the OCI Python SDK to make API Calls

How to use the OCI Python SDK to make API Calls

Introduction

Oracle Cloud Infrastructure (OCI) provides a wide array of applications and services that you can play with.

Among the many features and services that OCI provides, there is one I’d like to point out: You can evenly access all of its capabilities through the OCI UI Console, Command Line Interface (CLI), Cloud Shell, SDKs, and REST API depending on your preference or need.

Maybe you’re trying to build some scripts to make your life easier or to automate some of your work, and you’d like to know how to execute API calls against OCI.

In this post, we’ll talk about the OCI Python SDK and how to use it to make API calls.

API Security 

Before going straight to the subject, it is important to mention some key information about API security in OCI:
    • HTTPS and TLS 1.2 is required
    • All OCI API requests must be signed for authentication purposes
    • If the client’s clock is skewed more than 5 minutes from the server’s, an HTTP status code 401 will be returned

OCI SDKs

OCI provides 4 SDKs at the time of this article:
    • SDK for Java
    • Go SDK
    • Ruby SDK
    • Python SDK

You can check the list here.

When you’re building a script for OCI, you have two choices:
    1. Call the REST APIs directly, using cURL or requests or any other method depending on your platform or preferences
    2. Use an SDK if your preferred language is Java, Go, Ruby or Python – mine happens to be Python!

      Note: Of course, for creating and managing resources you can use Terraform and Ansible – but this is another subject for another time.

For me, I found it much easier to use the Python SDK in my scripts and I’ll show you why.

Authentication prerequisites

Before using the SDK (the same applies to the CLI and the REST APIs), there are a few prerequisites that need to be done:
  1. Create a user in IAM that will be used in the script, and put that user in at least one IAM group with any desired permissions
    1. This step is optional if you already have a user with the necessary permissions
  2. Generate an API Signing Key
  3. Get the Key’s fingerprint
  4. Note down your OCI tenancy’s OCID and your user’s OCID
    1. Follow these steps if you need help finding them
  5. Upload the public key to your tenancy
  6. Install the Python SDK

SDK configuration

Oracle Cloud Infrastructure SDKs require basic configuration information. You can provide this information by:
    • Using a configuration file
    • Declaring a configuration at runtime
The configuration contains some basic information needed for authentication:
    • User OCID
    • API Key Fingerprint
    • Full path to the API signing key
    • Passphrase for the key, if the key has one
    • Tenancy OCID
    • OCI Region name

Configuration File

config file example:
[DEFAULT]
user=ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq
fingerprint=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq
region=us-ashburn-1

[ADMIN_USER]
user=ocid1.user.oc1..aaaaaaaa65vwl7zut55hiavppn4nbfwyccuecuch5tewwm32rgqvm6i34unq
fingerprint=72:00:22:7f:d3:8b:47:a4:58:05:b8:95:84:31:dd:0e
key_file=keys/admin_key.pem
pass_phrase=mysecretphrase

As you can see in the example, there are two Profiles – a DEFAULT and an ADMIN_USER. You can create multiple profiles in your config file for different use cases if needed.

Read the file and validate the config
from oci.config import from_file
# Using the default location and the default profile for the config file: ~/.oci/config
config = from_file()

# Using a different profile from the default location
config = from_file(profile_name="admin_user")

# Using the default profile from a different file
config = from_file(file_location="~/.oci/config.prod")

# Using different location and different profile
config = from_file( "/.oci/config_files/config", "ADMIN_USER")


Configuration at runtime

As the config is actually a dict, you can also build it and validate it inside your script:
config = {
    "user": user_ocid,
    "key_file": key_file,
    "fingerprint": key_fingerprint,
    "tenancy": tenancy_ocid,
    "region": region_name
}

from oci.config import validate_config
validate_config(config)


Signing requests

Once the configuration is validated, we need to create a signer based on that configuration. The signer is used to sign all requests made by that user – as this is a security measure required by OCI.
def generate_signer_from_config(config_file, config_section):
    # validate the config from file
    config = oci.config.from_file(config_file, config_section)

    # generate the signer using the config info
    signer = oci.signer.Signer(
        tenancy=config["tenancy"],
        user=config["user"],
        fingerprint=config["fingerprint"],
        private_key_file_location=config.get("key_file"),
        # pass_phrase is optional and can be None
        pass_phrase=oci.config.get_config_value_or_default(
            config, "pass_phrase"),
        # private_key_content is optional and can be None
        private_key_content=config.get("key_content")
    )

    return signer

Note: pass_phrase and private_key_content are optional and have default values ‘None’ if they are not provided

Execute requests

And now, we can finally make our calls!
For each client you’ll be initializing, you’ll pass the config and the signer generated earlier:
# initialize the IdentityClient
identity_client = oci.identity.IdentityClient(self.config, signer=self.signer )
# get the tenancy info that we need
tenancy_data = identity_client.get_tenancy(config["tenancy"]).data
From now on, you can make any calls you want using the OCI Python SDK.

You can find the complete documentation of the SDK here.

Conclusions & Complete Solution

For the first time using the OCI APIs, this process may be a little long because of the extra security measures but once you configure the prerequisites one time and you understand how it works, the rest should be pretty straight forward.

You can find below, a complete example of how to get the tenancy information and the list of subscribed regions using the DEFAULT profile from a config file.

config file 
[DEFAULT]
user=<MY USER OCID>
fingerprint=<MY API KEY FINGERPRING>
key_file=./.oci/oci_api_key.pem
tenancy=<MY TENANCY OCID>
region=eu-frankfurt-1

get_oci_tenancy.py

import oci

# get the config from file for the DEFAULT profile
config = oci.config.from_file("./.oci/config", "DEFAULT")


def generate_signer_from_config(config):
    # Generate the signer for the API calls using the info from the config file
    signer = oci.signer.Signer(
        tenancy=config["tenancy"],
        user=config["user"],
        fingerprint=config["fingerprint"],
        private_key_file_location=config.get("key_file"),
        # pass_phrase is optional and can be None
        pass_phrase=oci.config.get_config_value_or_default(
            config, "pass_phrase"),
        # private_key_content is optional and can be None
        private_key_content=config.get("key_content")
    )

    return signer


# generate the signer
signer = generate_signer_from_config(config)

### Let's call some APIs ###

# initialize the IdentityClient
identity_client = oci.identity.IdentityClient(config, signer=signer)
# get the tenancy info
tenancy_data = identity_client.get_tenancy(config["tenancy"]).data

print(f"My tenancy name is {tenancy_data.name}")

# get the list of all the regions the tenancy is subscribed to
regions = identity_client.list_region_subscriptions(config["tenancy"]).data

print(f"These are all the OCI regions I am subscribed to: {regions}")

My project’s arborescence is:

.
 |-.oci
 | |-config
 | |-oci_api_key.pem
 | |-oci_api_key_public.pem
 |-get_oci_tenancy.py

I hope this was helpful to you.

Ionut Adrian Vladu

I enjoy building python scripts for…everything! I am a Cloud enthusiast and I like to keep up with technology. When I'm not behind a computer, I like taking photos -- Visit My 500px profile -- or sit back and enjoy Formula 1 race weekends. Currently, working as a Tech Cloud Specialist @ Oracle
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments