5 Creating Custom Execution Environments

The builder utility allows you to customize and create execution environments that you can upload to Private Automation Hub where Oracle Linux Automation Manager can access them and use them to run playbooks. Being able to use customized container images as execution environments to run playbooks allows you to ensure you have all the packages and dependencies you need on the container image necessary to run playbooks in a consistent and dependable way.

Note:

While the Builder utility enables you to create custom execution environments, in the case of an issue with the custom execution environment, Oracle support may ask you to revert to the Oracle provided OLAM-EE default image to troubleshoot the problem.
Execution environments that you customize with the Builder utility contains:
  • The base OLAM-EE container image accessible from the Oracle Container Registry.
  • A special builder image required for images created with the Builder utility.
  • One or more ansible collections.
  • Python or system dependencies (for example, modules, plugins in collections, custom scripts, bash commands), or a combination of both.

You can use the Builder utility to create execution environments with format version 1 or version 2.

The default olam-ee available on the Oracle Container Registry uses the latest version of the Oracle Linux 8 container image. When building custom execution environments, we always use the latest version available of ansible-core and its python dependencies for the Oracle Linux 8 release provided. For example, ansible-core 2.14 has Python 3.11 as a dependency.

In some cases, you may need to specify different versions of Python to run jobs on different execution environments running in Oracle Linux Automation Manager. A few examples where this occurs are the following:
  • The builder utility builds the execution environment using Python 3.9. If you build a custom execution environment that uses Pypi packages and modules, then specify the following variable on job templates so the custom execution environment that runs the job uses Python 3.9:
    "ansible_python_interpreter: /usr/bin/python3.9" 
  • The OCI ansible collection with the OCI SDK was built using Python 3.8. If you build a custom execution environment that uses the OCI SDK, then specify the following variable on job templates so the custom execution environment that runs the job uses Python 3.8:
    "ansible_python_interpreter: /usr/bin/python3.8"

For more information about setting variables on job templates, see the Oracle Linux Automation Manager 2: User's Guide.

Configuring a Custom Execution Environment Using Format 1

To configure a custom execution environment using format 1, do the following:
  1. On the host where you have installed the Builder utility, create a working directory for Builder utility. For example,
    mkdir ~/builder-utility 
    cd ~/builder-utility
  2. Create the following files:
    touch ansible.cfg execution-environment.yml requirements.yml requirements.txt bindep.txt
  3. In the execution-environment.yml file, add the following parameters:
    ---
    version: 1
    build_arg_defaults:
      EE_BASE_IMAGE: 'container-registry.oracle.com/oracle_linux_automation_manager/olam-ee:latest'
      EE_BUILDER_IMAGE: 'container-registry.oracle.com/oracle_linux_automation_manager/olam-builder:latest'
      ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: "--ignore-certs"
    ansible_config: 'ansible.cfg'
    dependencies:
      galaxy: requirements.yml
      python: requirements.txt
      system: bindep.txt
    additional_build_steps:
      prepend: |
        RUN whoami
        RUN cat /etc/os-release
      append:
        - RUN echo This is a post-install command!
        - RUN ls -la /etc
    
    In the previous example,
    • EE_BASE_IMAGE: This parameter requires the base olam-ee, which you can obtain from container-registry.oracle.com/oracle_linux_automation_manager/olam-ee. Alternatively, you can also obtain a copy of this image from Private Automation Hub if you have configured Private Automation Hub for this purpose.
    • EE_BUILDER_IMAGE: This parameter requires the olam-builder image, which you can obtain from container-registry.oracle.com/oracle_linux_automation_manager/olam-builder. The builder container image contains build libraries necessary to create customer execution environments. Alternatively, you can also obtain a copy of this image from Private Automation Hub if you have configured Private Automation Hub for this purpose.
    • ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: Use the "--ignore-certs" option. This parameter allows you to obtain an image from a repository without using self signed certificates.
    • ansible_config: You can specify the ansible.cfg file to pass a token and other settings for a private account to a Private Automation Hub server. Otherwise, the Builder utility uses ansible.galaxy to download Ansible collections. Listing the config file path as a string includes it as a build argument in the initial phase of the build.
    • dependencies: This section is a dictionary value that defines the Ansible Galaxy, Python, and system dependencies that must be installed into the final container.

      Note:

      Any dependencies listed in this section that are outside of the Oracle Linux or Oracle Linux Automation Manager scope of coverage are outside of the scope of coverage for support.
      Valid keys for this section are as follows:
      • galaxy: This parameter is the path to a file that defines the collection dependencies. The Builder utility installs these with the ansible-galaxy collection install -r requirements.yml command. The supplied value may be a relative path from the directory of the execution environment definition’s folder, or an absolute path.
        The format for specifying a collection in the requirements.yml file can be as follows:
        ---
        collections:
          - name: <namespace>.<collection_name>

        In the previous example, <namespace> is the namespace of the collection (for example, oracle) and <collection_name> is the name of the collection to be installed (for example, oci). You can repeat this combination for each collection you want to use.

        You can also indicate a specific version, source type, and source location as follows:
        ---
        collections:
        - name <namespace>.<collection_name>
          version: <version_number or "<range_identifyer><version_number>"
          type: <source_type>
             
        In the previous example, <version_number> can be any collection version number. When specified with one or more <range_identifyer>, then the version number is always the most recent version of the collection possible within the range specified. For example, the following indicates that the version should be greater than or equal to 4.0.0, but less than 5.0.0:
        ---
        collections:
        - name: oracle.oci
          version: ">=4.0.0,<5.0.0"
          type: galaxy
        You can use the following range identifiers:
        • *

          The most recent version. This is the default.

        • !=

          Not equal to the version specified.

        • ==

          Exactly the version specified.

        • >=

          Greater than or equal to the version specified.

        • >

          Greater than the version specified.

        • <=

          Less than or equal to the version specified.

        • <

          Less than the version specified.

      • python: This string value is the path to a file containing the Python dependencies to be installed with the pip install -r requirements.txt command. The supplied value may be a relative path from the directory of the execution environment definition’s folder, or an absolute path.

        The format for specifying a python dependency in the requirements.yml file can be as follows:

        <someproject>
        <someproject><version_specifier><version_number>
        <someproject><version_specifier><version_number>,<version_specifier><version_number>
        
        In the previous example, <someproject> is the name of the project. You can specify the project name alone, which find the latest version of that project, or you can specify a project with one or more <version_identifier> and <verion_number> combinations to return a specific version of the project you want to install. For example:
        requests>=2.4.2
        xmltodict
        azure-cli-core==2.11.1

        For more information about available version specifiers, see https://peps.python.org/pep-0440/#version-specifiers.

      • system: This string value is points to a bindep.txt requirements file. This will be processed by bindep and then passed to dnf, other platforms are not yet supported. For example:
        gcc
        libcurl-devel
        libxml2-devel
        python39-devel
        openssl-devel

        For more information about writing a system requirements file and optionally specifying version constraints, see https://docs.opendev.org/opendev/bindep/latest/readme.html#writing-requirements-files.

    • additional_build_steps: Additional commands may be specified in the additional_build_steps section, either for before the main build steps (prepend) or after (append). The syntax needs to be one of the following:
      • a multi-line string (example shown in the prepend section above)
      • a list (as shown via append)
  4. Save the file.
  5. Complete the ansible.cfg and any dependency files as required.
  6. Run the following command from your working directory:
    ansible-builder build -t <repository:tag>
                   
    In the previous example, <repository:tag> is the repository and tag of the custom execution environment. For example, host1/'custom_ee:latest.

    Note:

    For more information as the builder utility processes, use the -v 3 option at the end of the command provides the most information while 1 is the least. For example,
    ansible-builder build -v 3
  7. Verify that the images have been created. Run the following Podman command:
    podman images

Configuring a Custom Execution Environment Using Format 2

To configure a custom execution environment using format 2, do the following:
  1. On the host where you have installed the Builder utility, create a working directory for Builder utility. For example,
    mkdir ~/builder-utility 
    cd ~/builder-utility
  2. Create the following files:
    touch ansible.cfg execution-environment.yml requirements.yml requirements.txt bindep.txt
  3. In the execution-environment.yml file, add the following parameters:
    ---
    version: 2
    
    build_arg_defaults:
     ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: "--ignore-certs"
    
    ansible_config: 'ansible.cfg'
    
    dependencies:
     galaxy: requirements.yml
     python: requirements.txt
     system: bindep.txt
    
    images:
     base_image:
      name: container-registry.oracle.com/oracle_linux_automation_manager/olam-ee:latest
     builder_image:
      name: container-registry.oracle.com/oracle_linux_automation_manager/olam-builder:latest
    
    In the previous example,
    • ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: Use the "--ignore-certs" option.This parameter allows you to obtain an image from a repository without using self signed certificates.
    • ansible_config: You can specify the ansible.cfg file to pass a token and other settings for a Private Automation Hub server. Listing the config file path as a string includes it as a build argument in the initial phase of the build.
    • dependencies: This section is a dictionary value that is defines the Ansible Galaxy, Python, and system dependencies that must be installed into the final container. Valid keys for this section are as follows:
      • galaxy: This parameter is the path to a file that defines the collection dependencies. The Builder utility installs these with the ansible-galaxy collection install -r requirements.yml command. The supplied value may be a relative path from the directory of the execution environment definition’s folder, or an absolute path.
        The format for specifying a collection in the requirements.yml file can be as follows:
        ---
        collections:
        - name <namespace>.<collection_name>

        In the previous example, <namespace> is the namespace of the collection (for example, oracle) and <collection_name> is the name of the collection to be installed (for example, oci). You can repeat this combination for each collection you want to use.

        You can also indicate a specific version, source type, and source location as follows:
        ---
        collections:
          - <namespace>.<collection_name>
             version: <version_number or "<range_identifyer><version_number>"
             type: <source_type>
             
        In the previous example, <version_number> can be any collection version number. When specified with one or more <range_identifyer>, then the version number is always the most recent version of the collection possible within the range specified. For example, the following indicates that the version should be greater than or equal to 4.0.0, but less than 5.0.0:
        ---
        collections:
        - name: oracle.oci
          version: ">=4.0.0,<5.0.0"
          type: galaxy
        You can use the following range identifiers:
        • *

          The most recent version. This is the default.

        • !=

          Not equal to the version specified.

        • ==

          Exactly the version specified.

        • >=

          Greater than or equal to the version specified.

        • >

          Greater than the version specified.

        • <=

          Less than or equal to the version specified.

        • <

          Less than the version specified.

      • python: This string value is the path to a file containing the Python dependencies to be installed with the pip install -r ... command. The supplied value may be a relative path from the directory of the execution environment definition’s folder, or an absolute path.

        The format for specifying a python dependency in the requirements.yml file can be as follows:

        <someproject>
        <someproject><version_specifier><version_number>
        <someproject><version_specifier><version_number>,<version_specifier><version_number>
        
        In the previous example, <someproject> is the name of the project. You can specify the project name alone, which find the latest version of that project, or you can specify a project with one or more <version_identifier> and <verion_number> combinations to return a specific version of the project you want to install. For example:
        requests>=2.4.2
        xmltodict
        azure-cli-core==2.11.1

        For more information about available version specifiers, see https://peps.python.org/pep-0440/#version-specifiers.

      • system: This string value is points to a bindep requirements file. This will be processed by bindep and then passed to dnf, other platforms are not yet supported. For example:
        gcc 
        libcurl-devel 
        libxml2-devel  
        python39-devel 
        openssl-devel 

        For more information about writing a system requirements file and optionally specifying version constraints, see https://docs.opendev.org/opendev/bindep/latest/readme.html#writing-requirements-files.

    • additional_build_steps: Additional commands may be specified in the additional_build_steps section, either for before the main build steps (prepend) or after (append). The syntax needs to be one of the following:
      • a multi-line string (example shown in the prepend section above)
      • a list (as shown via append)
    • images: You can use the images key to define base and builder images. With the version 2 format, an execution environment definition may specify a base and builder container image whose signature must be validated before builder will build the resulting image, based on the value of the --container-policy CLI option. Key options are as follows:
      • base_image: This parameter requires the base olam-ee, which you can obtain from container-registry.oracle.com/oracle_linux_automation_manager/olam-ee. Alternatively, you can also obtain a copy of this image from Private Automation Hub if you have configured Private Automation Hub for this purpose.
      • builder_image: This parameter requires the olam-builder image, which you can obtain from container-registry.oracle.com/oracle_linux_automation_manager/olam-builder. The builder container image contains build libraries necessary to create customer execution environments. Alternatively, you can also obtain a copy of this image from Private Automation Hub if you have configured Private Automation Hub for this purpose.
  4. Save the file.
  5. Complete the ansible.cfg and any dependency files as required.
  6. Run the following command from your working directory:
    ansible-builder build -t <repository:tag>
                   
    In the previous example, <repository:tag> is the repository and tag of the custom execution environment. For example, host1/'custom_ee:latest.

    Note:

    For more information as the builder utility processes, use the -v 3 option at the end of the command provides the most information while 1 is the least. For example,
    ansible-builder build -v 3
  7. Verify that the images have been created. Run the following Podman command:
    podman images

Uploading a Custom Execution Environment

To upload a custom execution environment, do the following:
  1. From the host where you created the custom execution environment, use Podman to log into the Private Automation Hub instance you want to upload your custom execution environment to. For example,
    podman login <ip address or hostname> -u admin -p <password> --tls-verify=false

    In the previous example, <ip address or hostname> is the IP address or host name of the Private Automation Hub instance and <password> is the password for the admin user on the Private Automation Hub instance.

  2. Identify which custom image you want to upload. For example,
    podman images
  3. Push the image to your Private Automation Hub. For example,
    podman push <podman_image_id or repository:tag> <ip address or hostname/image_name:tag> --tls-verify=false
    In the previous example, <podman_image_id or repository:tag> is the image ID or the repository and tag of the custom execution environment you want to push and <ip address or hostname/image_name:tag> is the IP address or host name followed by the image name and the tag of the Private Automation Hub instance. For example, the following uses a podman repository name and tag followed by the hostname, image name, and tag to use on the private automation hub instance:
    podman push localhost/custom-image:2.1.3 private_automation_hub_host/custom-image:2.1.3 --tls-verify=false
    The following uses a podman image id followed by the hostname, image name, and tag to use on the private automation hub instance:
    podman push 330928308c01 private_automation_hub_host/custom-image:2.1.3 --tls-verify=false
  4. Verify that the execution environment now exists on your Private Automation Hub instance. For more information about this task, see View Execution Environment Details.