Use an OCI Dynamic Inventory with Oracle Linux Automation Engine
Introduction
Oracle Linux Automation Engine, the open-source software for provisioning and configuration management, uses an inventory file to work against managed nodes or hosts in your infrastructure. This inventory file contains a list of servers, their IP addresses, and other optional connection information.
A static inventory file works well if your infrastructure hardly changes.
However, your infrastructure is likely in constant flux when using the cloud. Therefore it would be great to have a way to have your inventory dynamically updated as hosts come and go.
Objectives
In this lab, you'll learn to:
- Setup Oracle Linux Automation Engine
- Create an OCI Dynamic Inventory
- Use the OCI Dynamic Inventory with a Playbook.
Prerequisites
- Install an Oracle Linux system with the following configuration:
- a non-root user with
sudo
permissions
- a non-root user with
Install Oracle Linux Automation Engine Control Node
Note: When using the free lab environment, see Oracle Linux Lab Basics for connection and other usage instructions.
The control node is the system from where the Oracle Linux Automation Engine playbooks run. Before running playbooks, installing the Oracle Linux Automation Engine packages is required.
If not already connected, open a terminal and connect via ssh to the ol-node-01 system.
ssh oracle@<ip_address_of_ol-node-01>
Install the Oracle Linux Automation Engine package and dependencies.
sudo dnf install -y ansible-core
The
ansible-core
package is available in theol8_appstream
repository as of Oracle LinuxTest the package installation.
ansible --version
The output will display the commands version, configuration details, and python version dependency.
Example output:
[oracle@ol-node-01 ~]$ ansible --version ansible [core 2.14.2] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/oracle/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.11/site-packages/ansible ansible collection location = /home/oracle/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.2 (main, Jun 14 2023, 13:00:29) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18.0.2)] (/usr/bin/python3.11) jinja version = 3.1.2 libyaml = True
Note: If the output shows
ERROR: Ansible requires the locale encoding to be UTF-8; Detected None.
, this indicates an incorrect locale setting foransible
. Fix the issue by setting these two environment variables:export LC_ALL="en_US.UTF-8" export LC_CTYPE="en_US.UTF-8"
The output shows that Oracle Linux Automation Engine defaults to using Python 3.11. Therefore, that is the environment where we must install the Oracle Cloud Infrastructure (OCI) SDK for Python.
Setup Oracle Cloud Infrastructure SDK for Python
The OCI Dynamic Inventory plugin requires a working OCI SDK for Python configuration on the control node. We can install the OCI SDK using the Oracle Linux RPM or PIP, the package installer for Python.
Install the OCI SDK for Python using PIP.
Install the packages and dependencies for PIP.
sudo dnf install -y python3.11-pip python3.11-setuptools
Install the Python packages
/usr/bin/python3.11 -m pip install oci
Add the
--proxy
option if you are behind a proxy. Details are available in the help by running the commandpython3.9 -m pip help install
.
Test the OCI SDK for Python installation by printing its version.
python3.11 -c "import oci;print(oci.__version__)"
Create the OCI SDK default configuration directory.
mkdir -p ~/.oci
Create the SDK default configuration file
The free lab provides a pre-generated SDK configuration which we can copy to the control node.
Open a new terminal from the desktop environment.
Note: Do not connect to the ol-node-01.
Copy all of the SDK configuration files to the control node.
scp ~/.oci/* oracle@<ip_address_of_ol-node-01>:~/.oci/.
exit
Example Configuration:
The following example shows key values in a configuration file.[DEFAULT] user=ocid1.user.oc1..<unique_ID> fingerprint=<your_fingerprint> key_file=~/.oci/oci_api_key.pem tenancy=ocid1.tenancy.oc1..<unique_ID> region=us-ashburn-1
Note: When following this tutorial outside of the free lab environment, see the instructions provided within the SDK and CLI Configuration File and Required Keys and OCIDs sections of the OCI Documentation.
Switch to the terminal window connected to the control node.
Update the location of the
key_file
in the SDK configuration file.When copying the SDK configuration file from the desktop environment, we must modify the user's home directory portion of the
key_file
.sed -i 's/luna.user/oracle/g' ~/.oci/config
If you modify the file manually with your favorite editor of choice, you can replace
/home/luna.user
with the shorthand syntax of~
.Verify that the SDK configuration works.
Switch or open a terminal to the control node.
Create a test Python script.
echo 'import oci object_storage_client = oci.object_storage.ObjectStorageClient(oci.config.from_file()) result = object_storage_client.get_namespace() print("Current object storage namespace: {}".format(result.data))' > test.py
The
test.py
script displays the Object Storage Namespace for the configured OCI Tenancy and Compartment.Run the script
python3.11 test.py
Example Output:
[oracle@ol-node-01 ~]$ python3.11 test.py Current object storage namespace: frn7gzeg0xzn
The namespace is unique to the configured tenancy.
Install the Oracle Cloud Infrastructure Ansible Collection
The OCI Ansible Collection contains a set of modules to automate cloud infrastructure provisioning and configuration, orchestration of complex operational processes, and deployment and update of your software assets.
Create a project directory.
mkdir ~/myproject
cd ~/myproject
Create a Requirements file.
cat << EOF | tee requirements.yml > /dev/null --- collections: - name: oracle.oci EOF
Install the OCI Ansible Collection.
ansible-galaxy collection install -r requirements.yml
If you already had a previous version installed, get the latest release by running with the
--force
option.ansible-galaxy collection install --force oracle.oci
Working with OCI Dynamic Inventory
Oracle includes its dynamic inventory plugin in its OCI Ansible Collection.
Configure the inventory plugin by creating a YAML configuration source.
The source filename needs to be
<filename>.oci.yml
or<filename>.oci.yaml
. Where<filename>
is a user-defined useful identifier.cat << EOF > myproject.oci.yml --- plugin: oracle.oci.oci # Optional fields to specify oci connection config: config_file: ~/.oci/config config_profile: DEFAULT EOF
Test the Inventory Plugin
Create an inventory graph.
ansible-inventory -i myproject.oci.yml --graph
Example Output:
ansible-inventory -i myproject.oci.yml --graph [WARNING]: * Failed to parse /home/oracle/myproject/myproject.oci.yml with auto plugin: Compartment ocid1.tenancy.oc1..<unique_ID> either does not exist or you don't have permission to access it. complete error : {'opc-request-id': '7DAB68C994C1487BA5DDA511775A42F3/C7C0F8988AC247B9DF065A80 6764D799/12DA93943F59BABCE34CD40668838B61', 'code': 'NotAuthorizedOrNotFound', 'message': 'Authorization failed or requested resource not found', 'status': 404} [WARNING]: * Failed to parse /home/oracle/myproject/myproject.oci.yml with yaml plugin: Plugin configuration YAML file, not YAML inventory [WARNING]: * Failed to parse /home/oracle/myproject/myproject.oci.yml with ini plugin: Invalid host pattern 'plugin:' supplied, ending in ':' is not allowed, this character is reserved to provide a port. [WARNING]: Unable to parse /home/oracle/myproject/myproject.oci.yml as an inventory source [WARNING]: No inventory was parsed, only implicit localhost is available @all: |--@ungrouped:
The output shows warnings and errors. So what went wrong?
The error occurs because the plugin requires knowing the compartment OCID.
Note: Providing the tenancy OCID and having the correct permissions will generate an inventory for the entire tenancy.
Since the plugin cannot read the compartment OCID information directly from the SDK configuration file, add it to the plugin source file.
Grab the compartment OCID from the SDK configuration file and assign it to the variable
comp_ocid
.comp_ocid=$(grep -i compartment ~/.oci/config | sed -e 's/compartment-id=//g')
Append a compartment entry to the plugin source file.
cat << EOF >> myproject.oci.yml compartments: - compartment_ocid: "$comp_ocid" fetch_compute_hosts: true EOF
The
fetch_compute_hosts
set totrue
results in the inventory only gathering information on compute hosts and ignoring other instance types deployed within the compartment.Rerun the test.
ansible-inventory -i myproject.oci.yml --graph
Example Output:
[oracle@ol-node-01 myproject]$ ansible-inventory -i myproject.oci.yml --graph [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details @all: |--@FRSl_EU-FRANKFURT-1-AD-1: | |--130.162.222.180 |--@Oracle-Tags#CreatedBy=oracleidentitycloudservice_ds-lab-wizard_oracle.com-es-a41b84b1a5: | |--130.162.222.180 |--@Oracle-Tags#CreatedOn=2022-04-01T16_41_51.622Z: | |--130.162.222.180 |--@all_hosts: | |--130.162.222.180 |--@luna-4f87e995-d976-4463-9de2-76497b5ba7b2: | |--130.162.222.180 |--@region_eu-frankfurt-1: | |--130.162.222.180 |--@ungrouped:
Our example shows the single control node instance as a listing of inventory groups designated by the
@
character and displays the instance's public IP address.What if we wanted the private IP address?
Grabbing the private IP address is necessary based on the physical location of the controller node or the configured network topology within the cloud infrastructure. Another reason for grabbing the private IP address is when the requested compute instances only have a private IP address.
Change Hostname Format
Add the following section to the plugin source file.
cat << EOF >> myproject.oci.yml hostname_format_preferences: - "private_ip" - "public_ip" EOF
The example format above will prioritize a system's private IP address over the public IP address. For more details on this configuration, see Hostname Format Preferences in the documentation.
Test again.
ansible-inventory -i myproject.oci.yml --graph
Example Output:
[oracle@ol-node-01 myproject]$ ansible-inventory -i myproject.oci.yml --graph [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details @all: |--@FRSl_EU-FRANKFURT-1-AD-1: | |--10.0.0.150 |--@Oracle-Tags#CreatedBy=oracleidentitycloudservice_ds-lab-wizard_oracle.com-es-a41b84b1a5: | |--10.0.0.150 |--@Oracle-Tags#CreatedOn=2022-04-01T16_41_51.622Z: | |--10.0.0.150 |--@all_hosts: | |--10.0.0.150 |--@luna-4f87e995-d976-4463-9de2-76497b5ba7b2: | |--10.0.0.150 |--@region_eu-frankfurt-1: | |--10.0.0.150 |--@ungrouped:
Run a Playbook
With the dynamic inventory setup and configured, we can use it to run a simple playbook.
Before moving forward, return the hostname format preferences to the default settings.
sed -i '/hostname_format/,$d' myproject.oci.yml; sed -i '$d' myproject.oci.yml
Note: This step is necessary as the lab environment does not know how to communicate with the private IP address.
Create a playbook that pings the host.
cat << EOF > ping.yml --- - hosts: all tasks: - name: Ansible ping test ansible.builtin.ping: EOF
The
- hosts: all
will ping all systems reported in the inventory as@all
is the top-level group. You can modify this playbook to use a different group from the graph output, and be sure to remove the@
character.Run the playbook.
ansible-playbook -u opc -i myproject.oci.yml ping.yml
Accept the
ECDSA key fingerprint
when prompted.The
-i
option sets the dynamic inventory file used.The
-u
option sets the remote SSH user when attempting a connection. Since we already connected asoracle
to the system we plan to ping; we need to specify a different SSH account.Example Output:
[oracle@ol-node-01 myproject]$ ansible-playbook -i myproject.oci.yml ping.yml -u opc [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details PLAY [all] ************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************* [WARNING]: Platform linux on host 130.162.222.180 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. ok: [130.162.222.180] TASK [Ansible ping test] *********************************************************************************************** ok: [130.162.222.180] PLAY RECAP ************************************************************************************************************* 130.162.222.180 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Summary
The completion of the playbook with ok
status confirms Oracle Linux Automation Engine creates the OCI dynamic inventory and can use it to communicate with the instances it discovers.