diff --git a/README.md b/README.md index 074144f..fe9111d 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,26 @@ -# linux-virt-labs +# Linux and Virtualization Labs [![License: UPL](https://img.shields.io/badge/license-UPL-green)](https://img.shields.io/badge/license-UPL-green) [![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=oracle-devrel_linux-virt-labs)](https://sonarcloud.io/dashboard?id=oracle-devrel_linux-virt-labs) -## THIS IS A NEW, BLANK REPO THAT IS NOT READY FOR USE YET. PLEASE CHECK BACK SOON! - ## Introduction -MISSING + +This repository contains a growing group of assets that accompany our [training material](https://oracle-samples.github.io/oltrain/), that consists of hand-on labs and videos. ## Getting Started -MISSING + +Many of the scripts consist of Oracle Linux Automation Engine playbooks to deploy our lab environments on OCI. + +- [Single-Host Oracle Linux Automation Manager](https://github.com/oracle-devrel/linux-virt-labs/oracle-linux-automation-manager) ### Prerequisites -MISSING -## Notes/Issues -MISSING +To run these playbooks, ensure you have the following installed and configured: -## URLs -* Nothing at this time +- Ansible +- [OCI Ansible Collection](https://oci-ansible-collection.readthedocs.io/en/latest/installation/index.html) +- [OCI Python SDK](https://docs.oracle.com/en-us/iaas/tools/python/2.122.0/installation.html) +- [SDK CLI configuration file](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#apisigningkey_topic_How_to_Generate_an_API_Signing_Key_Console) +- public SSH key ## Contributing This project is open source. Please submit your contributions by forking this repository and submitting a pull request! Oracle appreciates any contributions that are made by the open source community. diff --git a/labs/olam-hello-world.yaml b/labs/olam-hello-world.yaml new file mode 100644 index 0000000..e722e16 --- /dev/null +++ b/labs/olam-hello-world.yaml @@ -0,0 +1,15 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Hello World sample playbook + hosts: localhost + gather_facts: false + + tasks: + + - name: Print welcome message + ansible.builtin.debug: + msg: "Hello! Welcome to Oracle Linux Automation Manager." \ No newline at end of file diff --git a/oracle-linux-automation-manager/build.yaml b/oracle-linux-automation-manager/build.yaml new file mode 100644 index 0000000..a22d08e --- /dev/null +++ b/oracle-linux-automation-manager/build.yaml @@ -0,0 +1,92 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Launch an instance + oci_compute_instance: + availability_domain: "{{ my_availability_domain }}" + compartment_id: "{{ my_compartment_id }}" + name: "{{ item.value.instance_name | default('instance-'~timestamp) }}" + image_id: "{{ ol_image_id }}" + shape: "{{ instance_shape }}" + shape_config: + ocpus: "{{ instance_ocpus }}" + memory_in_gbs: "{{ instance_memory }}" + create_vnic_details: + assign_public_ip: true + hostname_label: "{{ item.value.instance_name | default('instance-'~timestamp) }}" + subnet_id: "{{ my_subnet_id }}" + metadata: + ssh_authorized_keys: "{{ lookup('file', lookup('env','HOME') + '/.ssh/' + private_key + '.pub' ) }}" + agent_config: + is_monitoring_disabled: false + is_management_disabled: false + are_all_plugins_disabled: false + plugins_config: + - + name: "OS Management Service Agent" + desired_state: DISABLED + register: result + vars: + timestamp: "{{ now().strftime('%Y%m%d-%H%M%S') }}" + +- name: Print instance details + ansible.builtin.debug: + msg: + - "Launched a new instance:" + - "{{ result }}" + when: debug_enabled + +- name: Set the compute instance id + ansible.builtin.set_fact: + instance_id: "{{ result.instance.id }}" + +- name: Set the compute instance display_name + ansible.builtin.set_fact: + instance_display_name: "{{ result.instance.display_name }}" + +- name: Get the vnic attachment details of instance + oci_compute_vnic_attachment_facts: + compartment_id: "{{ my_compartment_id }}" + instance_id: "{{ instance_id }}" + register: result + +- name: Get vnic details + oci_network_vnic_facts: + id: "{{ result.vnic_attachments[0].vnic_id }}" + register: result + +- name: Set the instance private ip address + ansible.builtin.set_fact: + instance_private_ip: "{{ result.vnic.private_ip }}" + +- name: Set the instance public ip address + ansible.builtin.set_fact: + instance_public_ip: "{{ result.vnic.public_ip }}" + +- name: Print the public and private ip of the newly created instance + ansible.builtin.debug: + msg: + - "Instance name: {{ instance_display_name }}" + - " public ip: {{ instance_public_ip }}" + - " private ip: {{ instance_private_ip }}" + when: debug_enabled + +- name: Add host to in-memory host file + ansible.builtin.add_host: + name: "{{ instance_display_name }}" + groups: "in_memory" + ansible_user: opc + ansible_ssh_private_key_file: "{{ lookup('env','HOME') + '/.ssh/' + private_key }}" + ansible_ssh_common_args: "-o StrictHostKeyChecking=no" + ansible_host: "{{ instance_public_ip }}" + ansible_port: 22 + instance_ocid: "{{ instance_id }}" + +# - name: Add instance to the state file +# ansible.builtin.lineinfile: +# path: /tmp/ansible.state +# line: "id{{ groups['in_memory'].index(instance_display_name) }}: {{ instance_id }}" +# create: true diff --git a/oracle-linux-automation-manager/create_instance.yaml b/oracle-linux-automation-manager/create_instance.yaml new file mode 100644 index 0000000..253acab --- /dev/null +++ b/oracle-linux-automation-manager/create_instance.yaml @@ -0,0 +1,355 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Gather facts and create instances + hosts: localhost + collections: + - oracle.oci + - community.general + + vars: + oci_config_section: DEFAULT + ad_placement: 1 + compartment_name: + compartment_id: + compute_instances: + 1: + instance_name: "control-node" + 2: + instance_name: "olam-node" + os: "Oracle Linux" + os_version: "8" + instance_shape: "VM.Standard.E4.Flex" + instance_ocpus: 2 + instance_memory: 16 + private_key: "id_rsa" + # ansible_python_interpreter: /usr/bin/python3.6 + debug_enabled: false + + tasks: + + # - name: Check if state file exists + # ansible.builtin.stat: + # path: /tmp/ansible.state + # register: state_exists + + # - name: Fail if state file already exists + # ansible.builtin.fail: + # msg: "Exit instance creation as a state file already exists." + # when: hosts_exists.stat.exists + + - name: Get location of oci_config + ansible.builtin.set_fact: + oci_config_file: "{{lookup('env','HOME') + '/.oci/config'}}" + + - name: Get tenancy ocid + ansible.builtin.set_fact: + my_tenancy_id: "{{ lookup('ini', 'tenancy section={{ oci_config_section }} file={{ oci_config_file }}') }}" + + - name: Get region id + ansible.builtin.set_fact: + my_region_id: "{{ lookup('ini', 'region section={{ oci_config_section }} file={{ oci_config_file }}') }}" + + - name: Print regions selected + ansible.builtin.debug: + msg: "{{ my_region_id }}" + when: debug_enabled + + - name: Get list availbility domains + oci_identity_availability_domain_facts: + compartment_id: "{{ my_tenancy_id }}" + region: "{{ my_region_id }}" + register: result + + - name: Print availability domains + ansible.builtin.debug: + msg: "{{ result }}" + when: debug_enabled + + - name: Set list of availability domains + ansible.builtin.set_fact: + availability_domains: "{{ result.availability_domains }}" + + - name: Set to availability domain from list + ansible.builtin.set_fact: + my_availability_domain: "{{ availability_domains[ (lookup('ansible.builtin.vars', 'ad_placement')| int)-1 ].name }}" + + - name: Print availability domain ad_placement + ansible.builtin.debug: + msg: "{{ my_availability_domain }}" + when: debug_enabled + +## Get compartment id from .oci/config or env OCI_COMPARTMENT_OCID + + - name: Get compartment id + ansible.builtin.set_fact: + my_compartment_id: "{{ compartment_id | default(lookup('ansible.builtin.env', 'OCI_COMPARMENT_OCID'), true) | default(lookup('ini', 'compartment-id section={{ oci_config_section }} file={{ oci_config_file }}'), true) }}" + + - name: Print compartment id + ansible.builtin.debug: + msg: "{{ my_compartment_id }}" + when: debug_enabled + + - name: Fail when compartment_id is not defined + ansible.builtin.fail: + msg: "Variable for compartment_id is not defined." + when: my_compartment_id is not defined + + - name: Generate random hex string + ansible.builtin.set_fact: + vcn_code: "{{ query('community.general.random_string', upper=false, lower=false, override_special=hex_chars, numbers=false) }}" + vars: + hex_chars: '0123456789abcdef' + + - name: Create a virtual cloud network + oci_network_vcn: + compartment_id: "{{ my_compartment_id }}" + display_name: "Linuxvirt Virtual Cloud Network" + cidr_blocks: "10.0.0.0/16" + dns_label: "vcn" + register: result + + - name: Set vcn id + ansible.builtin.set_fact: + my_vcn_id: "{{ result.vcn.id }}" + + - name: Create internet_gateway + oci_network_internet_gateway: + compartment_id: "{{ my_compartment_id }}" + vcn_id: "{{ my_vcn_id }}" + is_enabled: true + display_name: "Linuxvirt Internet Gateway" + state: 'present' + register: result + + - name: Set internet gateway id + ansible.builtin.set_fact: + my_internet_gateway_id: "{{ result.internet_gateway.id }}" + + - name: Create route_table + oci_network_route_table: + compartment_id: "{{ my_compartment_id }}" + vcn_id: "{{ my_vcn_id }}" + display_name: "Linuxvirt Route Table" + route_rules: + - network_entity_id: "{{ my_internet_gateway_id }}" + cidr_block: "0.0.0.0/0" + destination_type: CIDR_BLOCK + state: 'present' + register: result + + - name: Set route table id + ansible.builtin.set_fact: + my_rt_id: "{{ result.route_table.id }}" + + - name: Create security_list + oci_network_security_list: + display_name: "Linuxvirt Security List" + compartment_id: "{{ my_compartment_id }}" + vcn_id: "{{ my_vcn_id }}" + egress_security_rules: + - destination: "0.0.0.0/0" + protocol: 6 + ingress_security_rules: + - source: "0.0.0.0/0" + protocol: 6 + tcp_options: + destination_port_range: + max: 22 + min: 22 + register: result + + - name: Set security list id + ansible.builtin.set_fact: + my_security_list_id: "{{ result.security_list.id }}" + + - name: Create subnet + oci_network_subnet: + compartment_id: "{{ my_compartment_id }}" + vcn_id: "{{ my_vcn_id }}" + cidr_block: "10.0.0.48/28" + display_name: "Linuxvirt Subnet" + prohibit_public_ip_on_vnic: false + route_table_id: "{{ my_rt_id }}" + security_list_ids: "{{ my_security_list_id }}" + dns_label: "lv" + register: result + + - name: Set subnet id + ansible.builtin.set_fact: + my_subnet_id: "{{ result.subnet.id }}" + + - name: Get image + oci_compute_image_facts: + compartment_id: "{{ my_compartment_id }}" + operating_system: "{{ os }}" + operating_system_version: "{{ os_version }}" + sort_by: TIMECREATED + sort_order: ASC + register: result + + - name: Set compute image id + ansible.builtin.set_fact: + ol_image_id: "{{ result.images[0].id }}" + + # - name: Create the state file + # ansible.builtin.copy: + # dest: /tmp/ansible.state + # content: | + # vcn_id: {{ my_vcn_id }} + # internet_gateway_id: {{ my_internet_gateway_id }} + # route_table_id: {{ my_rt_id }} + # security_list_id: {{ my_security_list_id }} + # subnet_id: {{ my_subnet_id }} + + - name: Build an instance + ansible.builtin.include_tasks: "build.yaml" + loop: "{{ lookup('dict', compute_instances) }}" + + - name: Print in-memory inventory + ansible.builtin.debug: + msg: "{{ groups['in_memory'] }}" + when: debug_enabled + +- name: Configure new instances + hosts: in_memory + become: yes + gather_facts: false + vars: + username: "oracle" + user_default_password: "oracle" + private_key: "id_rsa" + debug_enabled: false + + tasks: + + - name: Wait for system to become reachable + ansible.builtin.wait_for_connection: + + - name: Run facts module to get latest information + ansible.builtin.setup: + + - name: Add user account with access to sudo + ansible.builtin.user: + name: "{{ username }}" + password: "{{ user_default_password | password_hash('sha512') }}" + comment: Ansible created user + groups: wheel + append: yes + update_password: on_create + + - name: Set authorized key for user using local pubilc key file + ansible.posix.authorized_key: + user: "{{ username }}" + state: present + key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/' + private_key + '.pub' ) }}" + + - name: Set user with passwordless sudo access + ansible.builtin.lineinfile: + path: '/etc/sudoers.d/{{ username }}' + regexp: '{{ username }} ALL=' + line: '{{ username}} ALL=(ALL:ALL) NOPASSWD: ALL' + state: present + create: yes + + - name: Add locale settings to .bashrc + ansible.builtin.lineinfile: + dest: ~/.bashrc + line: "{{ item }}" + with_items: + - 'export LC_ALL="en_US.UTF-8"' + - 'export LC_CTYPE="en_US.UTF-8"' + become_user: "{{ username }}" + + - name: Generate ssh keypair for user + community.crypto.openssh_keypair: + path: ~/.ssh/id_rsa + size: 2048 + comment: ocne ssh keypair + become_user: "{{ username }}" + + - name: Fetch public key file from server + ansible.builtin.fetch: + src: "~/.ssh/id_rsa.pub" + dest: "buffer/{{ inventory_hostname }}-id_rsa.pub" + flat: yes + become_user: "{{ username }}" + + - name: Copy public key to each destination + ansible.posix.authorized_key: + user: "{{ username }}" + state: present + key: "{{ lookup('file', 'buffer/{{ item }}-id_rsa.pub') }}" + loop: "{{ groups['in_memory'] | flatten(levels=1) }}" + + - name: Print hostvars for groups + ansible.builtin.debug: + msg: "{{ hostvars[item] }}" + loop: "{{ groups['in_memory'] | flatten(levels=1) }}" + when: debug_enabled + + - name: Accept new ssh fingerprints + ansible.builtin.shell: | + ssh-keyscan -t ecdsa-sha2-nistp256 {{ hostvars[item].ansible_host }} >> ~/.ssh/known_hosts + with_items: + - "{{ groups['in_memory'] }}" + become_user: "{{ username }}" + + - name: Install Oracle Linux Automation Manager + ansible.builtin.include_tasks: deploy-olam-tasks.yaml + vars: + control_node_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + when: inventory_hostname == 'olam-node' + + - name: Print instance details + ansible.builtin.debug: + msg: + - "Instance name: {{ hostvars[inventory_hostname]['ansible_hostname'] }}" + - " public ip: {{ hostvars[inventory_hostname]['ansible_host'] }}" + - " private ip: {{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + + - name: Pause play to interact with the servers + ansible.builtin.pause: + prompt: "Playbook paused... hit to continue or to abort. Aborting at this stage requires manual removal of all cloud resources this playbook creates." + +- name: Terminate instances and delete OCI resources + hosts: localhost + collections: + - oracle.oci + - community.general + + tasks: + + - name: Terminate the instances + oci_compute_instance: + id: "{{ hostvars[item]['instance_ocid'] }}" + state: absent + loop: "{{ groups['in_memory'] | flatten(levels=1) }}" + + - name: Delete the subnet + oci_network_subnet: + id: "{{ my_subnet_id }}" + state: absent + + - name: Delete the security list + oci_network_security_list: + id: "{{ my_security_list_id }}" + state: absent + + - name: Delete the route table + oci_network_route_table: + id: "{{ my_rt_id }}" + state: absent + + - name: Delete the Internet Gateway + oci_network_internet_gateway: + id: "{{ my_internet_gateway_id }}" + state: absent + + - name: Delete the VCN + oci_network_vcn: + vcn_id: "{{ my_vcn_id }}" + state: absent \ No newline at end of file diff --git a/oracle-linux-automation-manager/deploy-olam-tasks.yaml b/oracle-linux-automation-manager/deploy-olam-tasks.yaml new file mode 100644 index 0000000..b37423e --- /dev/null +++ b/oracle-linux-automation-manager/deploy-olam-tasks.yaml @@ -0,0 +1,300 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Install Oracle EPEL repository + ansible.builtin.dnf: + name: oracle-epel-release-el8 + state: present + when: + - ansible_facts['distribution_major_version'] == '8' + +- name: Install version lock plugin + ansible.builtin.dnf: + name: python3-dnf-plugin-versionlock + enablerepo: ol8_developer_EPEL + state: present + +- name: Version lock python3-click + community.general.yum_versionlock: + state: present + name: python3-click + +- name: Install additional packages for ansible + ansible.builtin.dnf: + name: + - python3-psycopg2 + - python3-pyOpenSSL + - python3-pip + enablerepo: ol8_developer_EPEL + state: latest + +- name: Install pexpect using pip + ansible.builtin.pip: + name: pexpect + +# Install database + +- name: Enable the PostgreSQL 13 module stream + ansible.builtin.copy: + dest: /etc/dnf/modules.d/postgresql.module + content: | + [postgresql] + name=postgresql + stream=13 + profiles= + state=enabled + when: + - ansible_distribution_major_version | int >= 8 + +- name: Install the database + ansible.builtin.dnf: + name: postgresql-server + state: present + +- name: Ensure postgresql data directory exists + ansible.builtin.file: + path: "/var/lib/pgsql/data" + owner: "postgres" + group: "postgres" + state: directory + mode: 0700 + +# Handle the ol-automation-manager-DB-init.sh script + +- name: Check if postgresql is initialized + ansible.builtin.stat: + path: "/var/lib/pgsql/data/PG_VERSION" + register: pgdata_dir_version + +- name: initialize postgresql database + ansible.builtin.command: "postgresql-setup --initdb" + when: not pgdata_dir_version.stat.exists + become_user: postgres + +- name: Change database password storage encryption + ansible.builtin.replace: + path: /var/lib/pgsql/data/postgresql.conf + regexp: '^#password_encryption.*' + replace: 'password_encryption = scram-sha-256' + +- name: Enable and start postgresql.service + ansible.builtin.systemd: + name: postgresql + state: started + enabled: yes + +- name: Create awx postgresql user + community.postgresql.postgresql_user: + name: awx + password: password + role_attr_flags: NOSUPERUSER + become_user: postgres + +- name: Create awx postgresql db + community.postgresql.postgresql_db: + name: awx + owner: awx + become_user: postgres + +- name: Update host-based authentication + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/pg_hba.conf + line: "host all all 0.0.0.0/0 scram-sha-256" + +- name: Set the database listening address + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/postgresql.conf + insertbefore: '^#port = 5432' + line: "listen_addresses = '{{ control_node_ip }}'" + +- name: Restart the database + ansible.builtin.systemd: + name: postgresql + state: restarted + +# Install Single-Host OLAM v2 + +- name: Install Oracle Linux Automation Manager repository + ansible.builtin.dnf: + name: oraclelinux-automation-manager-release-el8 + state: present + +- name: Disable Oracle Linux Automation Manager 1.0 repository + ansible.builtin.ini_file: + path: "/etc/yum.repos.d/oraclelinux-automation-manager-ol8.repo" + section: ol8_automation1 + option: enabled + value: "0" + mode: 0644 + +- name: Enable Oracle Linux Automation Manager 2.0 repository + ansible.builtin.ini_file: + path: "/etc/yum.repos.d/oraclelinux-automation-manager-ol8.repo" + section: ol8_automation2 + option: enabled + value: "1" + mode: 0644 + +- name: Install Oracle Linux Automation Manager + ansible.builtin.dnf: + name: ol-automation-manager + state: present + +- name: Edit unixsocket in /etc/redis.conf + ansible.builtin.lineinfile: + path: /etc/redis.conf + regexp: '^unixsocket ' + insertafter: '^# unixsocketperm ' + line: unixsocket /var/run/redis/redis.sock + +- name: Edit unixsocketperm in /etc/redis.conf + ansible.builtin.lineinfile: + path: /etc/redis.conf + regexp: '^unixsocketperm ' + insertafter: '^unixsocket ' + line: unixsocketperm 775 + +- name: Configure CLUSTER_HOST_ID setting + ansible.builtin.copy: + dest: /etc/tower/conf.d/olam.py + content: | + CLUSTER_HOST_ID = "{{ control_node_ip }}" + owner: awx + group: awx + mode: '0640' + +- name: Configure DATABASE settings + ansible.builtin.copy: + dest: /etc/tower/conf.d/db.py + content: | + DATABASES = { + 'default': { + 'ATOMIC_REQUESTS': True, + 'ENGINE': 'awx.main.db.profiled_pg', + 'NAME': 'awx', + 'USER': 'awx', + 'PASSWORD': 'password', + 'HOST': '{{ control_node_ip }}', + 'PORT': '5432', + } + } + owner: awx + group: awx + mode: '0640' + +- name: Provision olam ansible container environment + containers.podman.podman_image: + name: container-registry.oracle.com/oracle_linux_automation_manager/olam-ee + become_user: awx + +- name: Check if awx provisioned + ansible.builtin.stat: + path: /var/lib/awx/.awx-provisioned + register: awx_provision + +- name: Run awx-manage + ansible.builtin.shell: | + awx-manage migrate + awx-manage provision_instance --hostname={{ control_node_ip }} --node_type=hybrid + awx-manage register_default_execution_environments + awx-manage register_queue --queuename=default --hostnames={{ control_node_ip }} + awx-manage register_queue --queuename=controlplane --hostnames={{ control_node_ip }} + awx-manage create_preload_data + touch /var/lib/awx/.awx-provisioned + args: + executable: /bin/bash + become_user: awx + register: awx_migrate + when: not awx_provision.stat.exists + changed_when: awx_migrate is not search('already exists') + +- name: Set awx password + ansible.builtin.expect: + command: "awx-manage createsuperuser --username admin --email admin@example.com" + responses: + 'Password:': admin + 'Password \(again\):': admin + register: awx_password + become_user: awx + ignore_errors: yes + changed_when: awx_password.stdout is not search('is already taken') + +- name: Print the AWX admin password + ansible.builtin.debug: + var: awx_password + when: debug_enabled + +- name: Generate an OpenSSL private key with a different size (2048 bits) + community.crypto.openssl_privatekey: + path: /etc/tower/tower.key + size: 2048 + +- name: Generate an OpenSSL Certificate Signing Request + community.crypto.openssl_csr: + path: /etc/tower/tower.csr + privatekey_path: /etc/tower/tower.key + +- name: Generate a Self Signed OpenSSL certificate + community.crypto.x509_certificate: + path: /etc/tower/tower.crt + privatekey_path: /etc/tower/tower.key + csr_path: /etc/tower/tower.csr + provider: selfsigned + +- name: Remove default server section in nginx configuration + ansible.builtin.template: + src: ../templates/nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: 0644 + +- name: Remove default configuration in receptor + ansible.builtin.template: + src: ../templates/receptor.conf.j2 + dest: /etc/receptor/receptor.conf + owner: root + group: root + mode: '0644' + +- name: Set firewall service rules + ansible.posix.firewalld: + zone: public + service: "{{ item }}" + permanent: yes + state: enabled + immediate: yes + loop: + - http + - https + +- name: Set firewall port rules + ansible.posix.firewalld: + zone: public + port: "{{ item }}" + permanent: yes + state: enabled + immediate: yes + loop: + - 27199/tcp + +- name: Enable and start ol-automation service + ansible.builtin.systemd: + name: "{{ item }}" + state: started + enabled: yes + with_items: + - ol-automation-manager + +- name: Check if user is lingering + ansible.builtin.stat: + path: "/var/lib/systemd/linger/awx" + register: user_lingering + +- name: Enable lingering is needed + ansible.builtin.command: "loginctl enable-linger awx" + when: not user_lingering.stat.exists + diff --git a/oracle-linux-automation-manager/deploy-olam.yaml b/oracle-linux-automation-manager/deploy-olam.yaml new file mode 100644 index 0000000..98a4a9e --- /dev/null +++ b/oracle-linux-automation-manager/deploy-olam.yaml @@ -0,0 +1,315 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Deploy a single node instance of Oracle Linux Automation Manager + hosts: olam-node + collections: + - ansible.posix + - community.general + - community.postgresql + - community.crypto + become: yes + + vars: + control_node_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + debug_enabled: false + + tasks: + + - name: Install Oracle EPEL repository + ansible.builtin.dnf: + name: oracle-epel-release-el8 + state: present + when: + - ansible_facts['distribution_major_version'] == '8' + + - name: Install version lock plugin + ansible.builtin.dnf: + name: python3-dnf-plugin-versionlock + enablerepo: ol8_developer_EPEL + state: present + + - name: Version lock python3-click + community.general.yum_versionlock: + state: present + name: python3-click + + - name: Install additional packages for ansible + ansible.builtin.dnf: + name: + - python3-psycopg2 + - python3-pyOpenSSL + - python3-pip + enablerepo: ol8_developer_EPEL + state: latest + + - name: Install pexpect using pip + ansible.builtin.pip: + name: pexpect + + # Install database + + - name: Enable the PostgreSQL 13 module stream + ansible.builtin.copy: + dest: /etc/dnf/modules.d/postgresql.module + content: | + [postgresql] + name=postgresql + stream=13 + profiles= + state=enabled + when: + - ansible_distribution_major_version | int >= 8 + + - name: Install the database + ansible.builtin.dnf: + name: postgresql-server + state: present + + - name: Ensure postgresql data directory exists + ansible.builtin.file: + path: "/var/lib/pgsql/data" + owner: "postgres" + group: "postgres" + state: directory + mode: 0700 + + # Handle the ol-automation-manager-DB-init.sh script + + - name: Check if postgresql is initialized + ansible.builtin.stat: + path: "/var/lib/pgsql/data/PG_VERSION" + register: pgdata_dir_version + + - name: initialize postgresql database + ansible.builtin.command: "postgresql-setup --initdb" + when: not pgdata_dir_version.stat.exists + become_user: postgres + + - name: Change database password storage encryption + ansible.builtin.replace: + path: /var/lib/pgsql/data/postgresql.conf + regexp: '^#password_encryption.*' + replace: 'password_encryption = scram-sha-256' + + - name: Enable and start postgresql.service + ansible.builtin.systemd: + name: postgresql + state: started + enabled: yes + + - name: Create awx postgresql user + community.postgresql.postgresql_user: + name: awx + password: password + role_attr_flags: NOSUPERUSER + become_user: postgres + + - name: Create awx postgresql db + community.postgresql.postgresql_db: + name: awx + owner: awx + become_user: postgres + + - name: Update host-based authentication + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/pg_hba.conf + line: "host all all 0.0.0.0/0 scram-sha-256" + + - name: Set the database listening address + ansible.builtin.lineinfile: + path: /var/lib/pgsql/data/postgresql.conf + insertbefore: '^#port = 5432' + line: "listen_addresses = '{{ control_node_ip }}'" + + - name: Restart the database + ansible.builtin.systemd: + name: postgresql + state: restarted + + # Install Single-Host OLAM v2 + + - name: Install Oracle Linux Automation Manager repository + ansible.builtin.dnf: + name: oraclelinux-automation-manager-release-el8 + state: present + + - name: Disable Oracle Linux Automation Manager 1.0 repository + ansible.builtin.ini_file: + path: "/etc/yum.repos.d/oraclelinux-automation-manager-ol8.repo" + section: ol8_automation1 + option: enabled + value: "0" + mode: 0644 + + - name: Enable Oracle Linux Automation Manager 2.0 repository + ansible.builtin.ini_file: + path: "/etc/yum.repos.d/oraclelinux-automation-manager-ol8.repo" + section: ol8_automation2 + option: enabled + value: "1" + mode: 0644 + + - name: Install Oracle Linux Automation Manager + ansible.builtin.dnf: + name: ol-automation-manager + state: present + + - name: Edit unixsocket in /etc/redis.conf + ansible.builtin.lineinfile: + path: /etc/redis.conf + regexp: '^unixsocket ' + insertafter: '^# unixsocketperm ' + line: unixsocket /var/run/redis/redis.sock + + - name: Edit unixsocketperm in /etc/redis.conf + ansible.builtin.lineinfile: + path: /etc/redis.conf + regexp: '^unixsocketperm ' + insertafter: '^unixsocket ' + line: unixsocketperm 775 + + - name: Configure CLUSTER_HOST_ID setting + ansible.builtin.copy: + dest: /etc/tower/conf.d/olam.py + content: | + CLUSTER_HOST_ID = "{{ control_node_ip }}" + owner: awx + group: awx + mode: '0640' + + - name: Configure DATABASE settings + ansible.builtin.copy: + dest: /etc/tower/conf.d/db.py + content: | + DATABASES = { + 'default': { + 'ATOMIC_REQUESTS': True, + 'ENGINE': 'awx.main.db.profiled_pg', + 'NAME': 'awx', + 'USER': 'awx', + 'PASSWORD': 'password', + 'HOST': '{{ control_node_ip }}', + 'PORT': '5432', + } + } + owner: awx + group: awx + mode: '0640' + + - name: Provision olam ansible container environment + containers.podman.podman_image: + name: container-registry.oracle.com/oracle_linux_automation_manager/olam-ee + become_user: awx + + - name: Check if awx provisioned + ansible.builtin.stat: + path: /var/lib/awx/.awx-provisioned + register: awx_provision + + - name: Run awx-manage + ansible.builtin.shell: | + awx-manage migrate + awx-manage provision_instance --hostname={{ control_node_ip }} --node_type=hybrid + awx-manage register_default_execution_environments + awx-manage register_queue --queuename=default --hostnames={{ control_node_ip }} + awx-manage register_queue --queuename=controlplane --hostnames={{ control_node_ip }} + awx-manage create_preload_data + touch /var/lib/awx/.awx-provisioned + args: + executable: /bin/bash + become_user: awx + register: awx_migrate + when: not awx_provision.stat.exists + changed_when: awx_migrate is not search('already exists') + + - name: Set awx password + ansible.builtin.expect: + command: "awx-manage createsuperuser --username admin --email admin@example.com" + responses: + 'Password:': admin + 'Password \(again\):': admin + register: awx_password + become_user: awx + ignore_errors: yes + changed_when: awx_password.stdout is not search('is already taken') + + - name: Print the AWX admin password + ansible.builtin.debug: + var: awx_password + when: debug_enabled + + - name: Generate an OpenSSL private key with a different size (2048 bits) + community.crypto.openssl_privatekey: + path: /etc/tower/tower.key + size: 2048 + + - name: Generate an OpenSSL Certificate Signing Request + community.crypto.openssl_csr: + path: /etc/tower/tower.csr + privatekey_path: /etc/tower/tower.key + + - name: Generate a Self Signed OpenSSL certificate + community.crypto.x509_certificate: + path: /etc/tower/tower.crt + privatekey_path: /etc/tower/tower.key + csr_path: /etc/tower/tower.csr + provider: selfsigned + + - name: Remove default server section in nginx configuration + ansible.builtin.template: + src: ../templates/nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: 0644 + + - name: Remove default configuration in receptor + ansible.builtin.template: + src: ../templates/receptor.conf.j2 + dest: /etc/receptor/receptor.conf + owner: root + group: root + mode: '0644' + + - name: Set firewall service rules + ansible.posix.firewalld: + zone: public + service: "{{ item }}" + permanent: yes + state: enabled + immediate: yes + loop: + - http + - https + + - name: Set firewall port rules + ansible.posix.firewalld: + zone: public + port: "{{ item }}" + permanent: yes + state: enabled + immediate: yes + loop: + - 27199/tcp + + - name: Enable and start ol-automation service + ansible.builtin.systemd: + name: "{{ item }}" + state: started + enabled: yes + with_items: + - ol-automation-manager + + - name: Check if user is lingering + ansible.builtin.stat: + path: "/var/lib/systemd/linger/awx" + register: user_lingering + + - name: Enable lingering is needed + ansible.builtin.command: "loginctl enable-linger awx" + when: not user_lingering.stat.exists + diff --git a/oracle-linux-automation-manager/get_facts.yaml b/oracle-linux-automation-manager/get_facts.yaml new file mode 100644 index 0000000..3ea5a94 --- /dev/null +++ b/oracle-linux-automation-manager/get_facts.yaml @@ -0,0 +1,25 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +- name: Gather facts for localhost + hosts: localhost + gather_facts: false + + tasks: + + - name: Get minimum set of available facts + ansible.builtin.setup: + gather_subset: + - 'min' + register: min_facts + + - name: Print minimum set of facts + ansible.builtin.debug: + msg: "{{ min_facts }}" + + - name: Print system date + ansible.builtin.debug: + var: ansible_date_time.date diff --git a/oracle-linux-automation-manager/requirements.yaml b/oracle-linux-automation-manager/requirements.yaml new file mode 100644 index 0000000..c6c0774 --- /dev/null +++ b/oracle-linux-automation-manager/requirements.yaml @@ -0,0 +1,28 @@ +--- +# Copyright (c) 2024 Oracle and/or its affiliates. +# This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +# The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +# See LICENSE.TXT for details. + +# roles: + +collections: + - name: https://github.com/ansible-collections/community.general.git + type: git + version: main + + - name: https://github.com/ansible-collections/ansible.posix.git + type: git + version: main + + - name: https://github.com/oracle/oci-ansible-collection.git + type: git + version: master + + - name: https://github.com/ansible-collections/community.postgresql.git + type: git + version: main + + - name: https://github.com/ansible-collections/community.crypto.git + type: git + version: main \ No newline at end of file diff --git a/oracle-linux-automation-manager/templates/nginx.conf.j2 b/oracle-linux-automation-manager/templates/nginx.conf.j2 new file mode 100644 index 0000000..3a13ff4 --- /dev/null +++ b/oracle-linux-automation-manager/templates/nginx.conf.j2 @@ -0,0 +1,97 @@ +{# +Copyright (c) 2024 Oracle and/or its affiliates. +This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +See LICENSE.TXT for details. +#} + +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; + +# server { +# listen 80 default_server; +# listen [::]:80 default_server; +# server_name _; +# root /usr/share/nginx/html; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# location / { +# } +# +# error_page 404 /404.html; +# location = /40x.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } +# +# Settings for a TLS enabled server. +# +# server { +# listen 443 ssl http2 default_server; +# listen [::]:443 ssl http2 default_server; +# server_name _; +# root /usr/share/nginx/html; +# +# ssl_certificate "/etc/pki/nginx/server.crt"; +# ssl_certificate_key "/etc/pki/nginx/private/server.key"; +# ssl_session_cache shared:SSL:1m; +# ssl_session_timeout 10m; +# ssl_ciphers PROFILE=SYSTEM; +# ssl_prefer_server_ciphers on; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# location / { +# } +# +# error_page 404 /404.html; +# location = /40x.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } + +} + diff --git a/oracle-linux-automation-manager/templates/receptor.conf.j2 b/oracle-linux-automation-manager/templates/receptor.conf.j2 new file mode 100644 index 0000000..5ca20c3 --- /dev/null +++ b/oracle-linux-automation-manager/templates/receptor.conf.j2 @@ -0,0 +1,25 @@ +{# +Copyright (c) 2024 Oracle and/or its affiliates. +This software is made available to you under the terms of the Universal Permissive License (UPL), Version 1.0. +The Universal Permissive License (UPL), Version 1.0 (see COPYING or https://oss.oracle.com/licenses/upl) +See LICENSE.TXT for details. +#} + +- node: + id: {{ control_node_ip }} + +- log-level: debug + +- tcp-listener: + port: 27199 + +- control-service: + service: control + filename: /var/run/receptor/receptor.sock + +- work-command: + worktype: local + command: /var/lib/ol-automation-manager/venv/awx/bin/ansible-runner + params: worker + allowruntimeparams: true +# verifysignature: true