Oracle Cloud Infrastructure(OCI) Ansible Dynamic Inventory Script

If you use Ansible to work with hosts provisioned in OCI, using a static inventory file may not work well, as OCI compute instances may get provisioned and terminated over time, or be created or managed by other external tools (API, console, SDK, Terraform etc). Using the OCI dynamic inventory script will help ensure that the latest set of OCI compute instances are dynamically fetched and available for your playbooks to be executed upon.

To use the OCI dynamic inventory script, grab the script and the default configuration files from

Dynamic Inventory Script

Prerequisites

Note: Before using the script, please ensure that you have a valid OCI SDK configuration. Refer OCI SDK Configuration documentation for details on how to configure ~/.oci/config.

Script and Configuration Details

The oci_inventory.py script uses the OCI Python SDK to query OCI compute instances in your tenancy, and builds a dynamic inventory that can then be used in your Ansible playbooks. Arguments to the oci_inventory.py can help you control the configuration profile to use, the compartment to limit your search to, etc.

The oci_inventory.ini configuration file can be optionally used to configure the OCI configuration profile to use, control how the inventory details are cached, and how hosts are named in your inventory.

The oci_inventory.py script accepts the following command line arguments:

usage: oci_inventory.py [-h] [--list] [--host HOST] [-config CONFIG_FILE]
              [--profile PROFILE] [--compartment COMPARTMENT]
              [--refresh-cache] [--debug]

optional arguments:
  -h, --help            show this help message and exit
  --list                List instances (default: True)
  --host HOST           Get all information about a compute instance
  -config CONFIG_FILE, --config-file CONFIG_FILE
                        OCI config file location
  --profile PROFILE     OCI config profile for connecting to OCI
  --compartment COMPARTMENT
                        Name of the compartment
  --refresh-cache, -r   Force refresh of cache by making API requests to OCI
                        (default: False - use cache files)
  --debug               Send debug messages to STDERR

The oci_inventory.py script also accepts the following environment variables:

Environment Variable Description
OCI_CONFIG_FILE Specifies the OCI SDK configuration file to use.
OCI_INI_PATH Specifies the inventory script's configuration file to use.
OCI_CONFIG_PROFILE Specifies the profile in the OCI SDK configuration file, to be used.
OCI_USER_ID Specifies the OCID of the OCI user to use to fetch the inventory.
OCI_USER_FINGERPRINT Specifies the OCI user's key-pair's fingerprint being used to use to fetch the inventory.
OCI_USER_KEY_FILE Specifies the full path including the filename of the private key of the OCI user being used to use to fetch the inventory.
OCI_TENANCY Specifies the OCID of the tenancy to use to fetch the inventory
OCI_REGION Specifies the OCI Region to use to fetch the inventory
OCI_USER_KEY_PASS_PHRASE Specifies the passphrase of the key (if encrypted), to use to fetch the inventory.
OCI_CACHE_DIR Specifies the directory where cache files of the inventory script will reside. A file named "ansible-oci.cache" will be written to this directory. It is recommended that the directory pointed to by this environment variable be read-able and write-able (unix file permissions 600) only by the user running the inventory script.
OCI_CACHE_MAX_AGE The number of seconds a cache file is considered valid. To disable caching and get the latest inventory from OCI, set this value to 0.
OCI_HOSTNAME_FORMAT Host naming format to use in the generated inventory. Use 'fqdn' to list hosts using the instance's Fully Qualified Domain Name (FQDN). Use 'public_ip' to list hosts using public IP address. Use 'private_ip' to list hosts using private IP address.

The order of precedence for the configuration used by the inventory script is:

  1. command line arguments
  2. environment variables
  3. options in script configuration file.

The configuration file used for the script defaults to ./oci_inventory.ini file. The OCI SDK configuration file defaults to ~/.oci/config file. The script uses the DEFAULT profile from the config file if no profile name is specified.

The generated inventory is grouped along the following axes:

  • region
  • compartment_name
  • availability domain
  • vcn_id
  • subnet_id
  • security_list_id
  • image_id
  • instance shape
  • freeform tags with group name as “tag_key=value”
  • defined tags with group name as “namespace#key=value”
  • metadata (key, value) with group name as “key=value”
  • extended metadata (key, value) with group name as “key=value”

By default, all non-alphanumeric characters except HASH(#), EQUALS(=), PERIOD(.) and DASH(-) in group names and host names are replaced with an UNDERSCORE(_) when the inventory is generated, so that the names can be used as Ansible groups. To disable this replacement, set sanitize_names to False in the dynamic inventory settings file(default ./oci_inventory.ini). To also replace DASH(-) when sanitize_names is True, set replace_dash_in_names to True in the settings file.

How to Use

Using a Dynamic Inventory During Playbook Execution

Ensure that you have correct OCI SDK configuration (and optionally an oci_inventory.ini). Invoke the ansible-playbook command using

$ ansible-playbook -i <path-to-inventory-file>/oci_inventory.py <your-playbook-using-the-generated-inventory>

or use the ANSIBLE_HOSTS environment variable:

$ ANSIBLE_HOSTS=<path-to-inventory-file>/oci_inventory.py ansible-playbook <your-playbook-using-the-generated-inventory>

To Disable Cache and Fetch Latest

If you are running the dynamic inventory in a standalone manner, you can use “–refresh”/”-r” to ignore the cached inventory and fetch the latest inventory from OCI:

$ <path-to-inventory-file>/oci_inventory.py --refresh

If you are using the inventory script during an ansible-playbook invocation, set the OCI_CACHE_MAX_AGE environment variable to “0”(zero) to ignore the cache, and fetch the latest inventory from OCI:

$ OCI_CACHE_MAX_AGE=0 ansible-playbook -i <path-to-inventory-file>/oci_inventory.py <your-playbook-using-the-generated-inventory>

Debugging

If you want to look at the dynamic inventory generated by the script, run it in with “–list”, and check the output.

$ <path-to-inventory-file>/oci_inventory.py --list

To print additional debug information to STDERR, use

$ <path-to-inventory-file>/oci_inventory.py --debug

Get a Single Host’s Information

The inventory script can also be configured to provide information about a single host.

$ <path-to-inventory-file>/oci_inventory.py --host <host's-ip>

The script would then return the following variables for the specified host:

{
    "availability_domain": "IwGV:US-ASHBURN-AD-1",
    "compartment_id": "ocid1.compartment.oc1..xxxxxEXAMPLExxxxx",
    "defined_tags": {},
    "display_name": "ansible-test-instance-448",
    "extended_metadata": {},
    "freeform_tags": {},
    "id": "ocid1.instance.oc1.iad.xxxxxEXAMPLExxxxx",
    "image_id": "ocid1.image.oc1.iad.xxxxxEXAMPLExxxxx",
    "ipxe_script": null,
    "launch_mode": "CUSTOM",
    "launch_options": {
      "boot_volume_type": "ISCSI",
      "firmware": "UEFI_64",
      "network_type": "VFIO",
      "remote_data_volume_type": "ISCSI"
    },
    "lifecycle_state": "AVAILABLE",
    "metadata": {
      "baz": "quux",
      "foo": "bar"
    },
    "region": "iad",
    "shape": "VM.Standard1.1",
    "source_details": {
      "image_id": "ocid1.image.oc1.iad.xxxxxEXAMPLExxxxx",
      "source_type": "image"
    },
    "time_created": "2018-01-16T12:13:35.336000+00:00"
}

FAQs

  1. The generated inventory doesn’t reflect all the compute instances in my tenancy.
  • Check if the OCI user ocid that you are specifying (either via OCI_USER or in the “profile” of your OCI SDK configuration file) has the policy permissions to list those instances. The dynamic inventory script current makes the following API operation calls. Ensure that the corresponding permissions are given to the OCI user:
    • ListCompartments
    • ListVNICAttachments
    • GetSubnet
    • GetVCN
    • GetVNIC
    • GetInstance
  • The default OCI_HOSTNAME_FORMAT is “public_ip” and so the generated inventory would only contain compute instances with a public IP. This is useful when your ansible controller node is outside the OCI VCN (as Ansible can only reach instances with public IPs). However if you are running Ansible in a compute instance within your OCI VCN that has access to all subnets within yuor VCN and can reach compute instances with private ips, set OCI_HOSTNAME_FORMAT to “private_ip” to fetch nodes with private IPs as well.