Monday, 20 January 2020

OCI CLI Environment Variables

The OCI CLI client provides a number of arguments that are useful as you look up your components from the command line. As you build an internal tooling to query either your or your customers resources, it can start to get "interesting" if you need to start building a custom argument list.

Since version 2.6.9 of the client, a number of environment variables are supported that you can set rather than building a complex argument list. I think leveraging these variables makes for a cleaner code base in your bash scripts.

If you check the release notes from version 2.6.9, you will see they introduced they following variables:

  • OCI_CLI_PROFILE
  • OCI_CLI_REGION
  • OCI_CLI_USER
  • OCI_CLI_FINGERPRINT
  • OCI_CLI_KEY_FILE
  • OCI_CLI_TENANCY
  • OCI_CLI_ENDPOINT
  • OCI_CLI_CONFIG_FILE
  • OCI_CLI_RC_FILE
  • OCI_CLI_CERT_BUNDLE
  • OCI_CLI_AUTH
  • OCI_CLI_DELEGATION_TOKEN_FILE
  • OCI_CLI_SECURITY_TOKEN_FILE
For the most recent version of what's supported, you can review the code base where they define all the available environment variables that you can use:

https://github.com/oracle/oci-cli/blob/master/src/oci_cli/cli_constants.py


So, what are some examples I use in leveraging these variables?

I take an argument into my script to receive the profile. If this is set I set the variable OCI_CLI_PROFILE to whatever was passed in and unset the variable OCI_CLI_AUTH which I have pre-set to instance_principal.

if [[ "$ociProfile" != "" ]]
then
    export OCI_CLI_PROFILE=$ociProfile
    unset OCI_CLI_AUTH
fi

Another example. I have some scripts that are auditing the whole tenancy, and whenever you run an OCI command it is against a single region at a time. There is a command that lists any region you have a subscription to, so we can pull that list, run a loop and then export the relevant region in each iteration.

regions=$(oci iam region-subscription list)

for regionIdx in $(echo "$regions" | jq '.data | keys | .[]'); do
    regionName=$(echo "$regions" | jq -r ".data[$regionIdx].\"region-name\"")
    regionRequiresNotification=false

    export OCI_CLI_REGION="$regionName"
    echo "exported region $OCI_CLI_REGION"
done

Well - that's just a couple of examples. The names of the variables are pretty self explanatory for what they relate to.

OCI: Enabling X11 Forwarding on an Oracle Linux instance

I was connecting to one of my works servers the other day hoping to copy the contents of a file into my clipboard, which would require the use of an X11 forwarded session, but as I connected to the server with X11 forwarding enabled, I was sad to see the following message:

X11 forwarding request failed on channel 0

This is on Oracle Linux.

Note, if I connect to an Ubuntu instance, I get the message:

/usr/bin/xauth:  file /home/ubuntu/.Xauthority does not exist


But this file is created, and X forwarding works from the get-go.

OK, back to Oracle Linux - how do we fix this?

Actually, the fix is a simple one.

SSH is already configured to enable X11Forwarding. The other change you need make is to turn off the setting X11UseLocalhost. So part of your configuration would likely look like this:

X11Forwarding yes
#X11DisplayOffset 10
X11UseLocalhost no

After that, you will want to reload the SSH daemon. Do this by running the command:

sudo systemctl reload sshd

Finally, you need to install xauth. This is enabled through the package xorg-x11-xauth.

sudo yum install xorg-x11-xauth

The next time you connect to the server, you should see the file .Xauthority in your home directory. And you will be able to run any X apps remotely.

You connect to the server with the X flag:

ssh -X opc@server



For what it's worth, you use the xclip package to copy the contents of files.

So, for example, to copy the sshd_config, you would run:

cat /etc/ssh/sshd_config  | xclip -selection c 


Friday, 17 January 2020

Trimming down on OCI CLI output with a query in the RC file

Oracle Cloud Infrastructure has a command client, which leverages their REST API. One thing you can do to streamline your usage is to make use of an RC file. The RC file that would be automatically used is the one at the path: `~/.oci/oci_cli_rc`, but you can also point to an alternative file path if you have named it something different.

At the most basic level what you would typically want to do is provide some alias for arguments. A common argument being `--compartment-id`, but we can alias that to simply `-c` by specifying in our RC file:

[OCI_CLI_PARAM_ALIASES]
-c = --compartment-id


This is all good, but what I think is neat is that you can provide queries to manipulate the output that is returned to the screen.

What's a use case for this? Well one example, it's not uncommon to list the compartments so you can figure out the compartment ID, but by default there is a lot of information returned that I am almost never interested in. When your tenancy isn't very complex, it's not a problem, but when it starts to get more complex, the last thing you want to do is be scrolling pages of compartment properties you aren't interested in.

So, you define queries in a confiuration section named: [OCI_CLI_CANNED_QUERIES]. So, first lets look at the full output, so we can define which properties we want returned. What I want, and in this order is:

1. Parent compartment ID
2. Compartment ID
3. Name

So, I define my query like:

[OCI_CLI_CANNED_QUERIES]

simple_list=data[*].{"id": "id", "parent-id": "compartment-id", "name": "name"}


With that saved into my RC file, now I can run my list operation and point to by pre-defined query like so:

oci iam compartment list --query query://simple_list

And my output becomes:

[
  {
    "id": "ocid1.compartment.oc1..xxx",
    "name": "education",
    "parent-id": "ocid1.tenancy.oc1..xxx"
  },
  {
    "id": "ocid1.compartment.oc1..xxx",
    "name": "ManagedCompartmentForPaaS",
    "parent-id": "ocid1.tenancy.oc1..xxx"
  },
  {
    "id": "ocid1.compartment.oc1..xxx",
    "name": "terraform",
    "parent-id": "ocid1.tenancy.oc1..xxx"
  }
]


Much more easy to consume, right?

As you can see, the display order doesn't match the way in which I defined the query fields - it looks to come out in alphabetical order, if that matters to you.

This is just one example of what you can do. Other examples in the documentation include:

  • Returning data a simple comma separated list of values
  • Applying a filter - check out Christoph's blog with some advances examples:
  • Restricting output to a number of records

This query leverages the JMESPath technology. 

You can also see the Oracle provided query examples here: https://docs.cloud.oracle.com/iaas/Content/API/SDKDocs/cliconfigure.htm#SpecifyingNamedQueries