October 28, 2020

OCI CLI is your friend to custom scripting and automation: Quickly and Easily

By: Seshadri Dehalisan | Master Principal Enterprise Cloud Architect


Oracle Cloud Infrastructure (OCI) offers plethora of options for automation, configuration management and generating reports. Oracle Resource Manager and Terraform (using OCI providers) are great options for developing immutable infrastructure as a code (IaC). OCI also makes available software development kits (SDKs) to facilitate development of custom solutions. Languages supported are Java, Python, JavaScript, .Net, Go and Ruby.

Oracle also provides command line interface that provides the same core capabilities as the OCI console but also extends console functionality and facilitates developers and other user groups to automate the entire process of controlling and managing AWS services through scripts. These scripts make it easy for users to fully automate cloud infrastructure. This blog is intended to explain one of the most powerful but least utilized features of OCI CLI – ability to use JMESPath query and search.


OCI can output in multiple formats as itemized below and is affected with “output” flag.




The output is formatted as JSON string – default format


The output is formatted as a table using the characters +|- to form the cell borders. It typically presents the information in a "human-friendly" format that is much easier to read than the others, but not as programmatically useful.


If the output of a given query is a single string value, this will return the string without surrounding quotes

Let us start with an interesting case – you are trying to delete a subnet and you get the below error:


Now, while you get a dependency, you don’t necessarily know what resource it is. Here comes OCI’s search capability to rescue. You can identify the dependent resource by issuing the below command

oci search resource free-text-search --text ocid1.vnic.oc1.iad.axxxxxxxucso5yesdote2ep52lxk2fk33plwqatzhiwuijgrdzkcu7g


From the output, you identify the below message

"display-name": "vnic20201023122843",

        "freeform-tags": {

          "gatewayId": "ocid1.apigateway.oc1.iad.amaaaaaaxkh5s6iaq343mp3dcynh7tbxe5dvxuuhkvxyff7gfeiouwb7sqaa"


        "identifier": "ocid1.privateip.oc1.iad.abuwcljsbgwnquru262mccc4ykvcuxsdwfjkdum7kcwxw3wz63sc6undsjiq",

Assume, you are asked to list all the users in your tenancy. You can issue

oci iam user list --sort-by NAME --sort-order DESC


I have used sort arguments that are self-explanatory. This will list multiple tuples in the default output format, JSON. Going further, you are presented the challenge to list columns is_mfa_activated, time-created and lifecycle-state only. You can accomplish this as shown below:

# The output was in JSON. Let us pretty print it

oci iam user list --sort-by NAME --sort-order DESC --query 'data[*].[name,"is-mfa-activated","time-created","lifecycle-state"]' --output table



For details on JMESPath refer here (jmespath.org). Here, the argument query conforms to JMESPath query patterns. We are selecting all data array and just selectively displaying the required columns. A SQL equivalence will be select name, is-mfa-activated,time-created, lifecycle-state from data[*]. Note that JMESPath expects any columns that has hypen in name to be double quoted.

Now, let us go a step further and list out only a specific user called fleetadmin. Here, with the above query, we need to add a where clause as we would do in a SQL query where name=’fleetadmin. We can do it with OCI and JMESPath as below

oci iam user list --sort-by NAME --sort-order DESC \

--query 'data[?"name"==`fleetadmin`].{ociusername:name,mfa:"is-mfa-activated",timecreated:"time-created",userstate:"lifecycle-state"}' --output table

As is evident, ?”name” acts as a where clause and filters out fleetadmin. The possibilities are endless and you can leverage them in script.

Let us now get into some more practical use cases. Assume, you have a need to list out all the boot volumes that are greater than say 120GB. You can easily script it with OCI as follows

for adomain in `oci iam availability-domain list --query 'data[*].name'|egrep -v -e "\[" -e "\]"|sed 's/\"//g;s/\,//g'`


  echo $adomain

  oci bv boot-volume list --compartment-id ocid1.compartment.oc1..xxxxxxxxxxxxxxx \

  --availability-domain $adomain \

  --query 'data[?"size-in-gbs" > `120`].{deviceID:id,size:"size-in-gbs"}' \

  --output table



Now, let us go to using the search functionality of OCI CLI.

Use case: If you are asked to list all the instances that are either in stopped or terminated status, you need to ideally identify all the compartments and recursively list out the instances in above states.

Alternatively, you can do this

oci search resource structured-search --query-text "QUERY instance resources where lifeCycleState = 'TERMINATED'||lifeCycleState = 'STOPPED'"

Let us make the formatting bit better

oci search resource structured-search --query-text "QUERY instance resources where lifeCycleState = 'TERMINATED'||lifeCycleState = 'STOPPED'"  --query 'data.items[*].{ad:"availability-domain",instance:"identifier"}' --output tab

Here structured search is being leveraged. You can also use free-form search.

When using OCI CLI, you need to consider below best practices.


OCI CLI while powerful should be used as appropriate and if used correctly, provides great scripting and custom solutions capability. This is no substitute for Terraform or Oracle Resource Manager which provides robust Infrastructure as Code capabilities.