diff --git a/.github/workflows/opentelemetry-collector-molecule.yml b/.github/workflows/opentelemetry-collector-molecule.yml new file mode 100644 index 00000000..d1c35d8a --- /dev/null +++ b/.github/workflows/opentelemetry-collector-molecule.yml @@ -0,0 +1,43 @@ +--- +name: OpenTelemetry Collector Molecule + +on: + push: + branches: + - main + pull_request: + branches: + - main + +defaults: + run: + working-directory: roles/opentelemetry_collector + +jobs: + molecule: + name: Molecule + runs-on: ubuntu-latest + strategy: + matrix: + scenario: + - default + - latest + - non-contrib + + steps: + - name: Check out the codebase. + uses: actions/checkout@v4 + + - name: Set up Python 3. + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install test dependencies. + run: pip3 install ansible molecule molecule-plugins[docker] docker pytest-testinfra + + - name: Run Molecule tests. + run: molecule test -s ${{ matrix.scenario }} + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' diff --git a/roles/opentelemetry_collector/README.md b/roles/opentelemetry_collector/README.md index 11c7cda6..c21544f9 100644 --- a/roles/opentelemetry_collector/README.md +++ b/roles/opentelemetry_collector/README.md @@ -4,7 +4,7 @@ This Ansible role to install and configure the OpenTelemetry Collector, which ca ## Requirements -Please ensure that `curl` is intalled on Ansible controller. +Please ensure that `curl` is installed on Ansible controller. ## Role Variables @@ -12,7 +12,7 @@ Available variables with their default values are listed below (`defaults/main.y | Variable Name | Description | Default Value | |---------------|-------------|---------------| -| `otel_collector_version` | Version of OpenTelemetry Collector to install. | `"0.90.1"` | +| `otel_collector_version` | Version of OpenTelemetry Collector to install. Set to 'latest' to automatically determine and install the latest release | `"0.90.1"` | | `otel_collector_binary_url` | URL for downloading the OpenTelemetry Collector binary. This URL is constructed based on the collector version, type, and architecture. | `"https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v{{ otel_collector_version }}/{% if otel_collector_type == 'contrib' %}otelcol-contrib_{{ otel_collector_version }}_linux_{{ otel_collector_arch }}{% else %}otelcol_{{ otel_collector_version }}_linux_{{ otel_collector_arch }}{% endif %}.tar.gz"` | | `arch_mapping` | Mapping of `ansible_architecture` values to OpenTelemetry Collector binary architecture names. | See below\* | | `otel_collector_arch` | Architecture for the OpenTelemetry Collector binary, determined based on the `ansible_architecture` fact. | `"{{ arch_mapping[ansible_architecture] | default('amd64') }}"` | diff --git a/roles/opentelemetry_collector/defaults/main.yml b/roles/opentelemetry_collector/defaults/main.yml index f615b6c7..461371eb 100644 --- a/roles/opentelemetry_collector/defaults/main.yml +++ b/roles/opentelemetry_collector/defaults/main.yml @@ -2,6 +2,8 @@ otel_collector_version: "0.90.1" otel_collector_binary_url: "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v{{ otel_collector_version }}/{% if otel_collector_type == 'contrib' %}otelcol-contrib_{{ otel_collector_version }}_linux_{{ otel_collector_arch }}{% else %}otelcol_{{ otel_collector_version }}_linux_{{ otel_collector_arch }}{% endif %}.tar.gz" +otel_collector_latest_url: 'https://api.github.com/repos/open-telemetry/opentelemetry-collector-releases/releases/latest' + arch_mapping: x86_64: amd64 aarch64: arm64 diff --git a/roles/opentelemetry_collector/molecule/default/converge.yml b/roles/opentelemetry_collector/molecule/default/converge.yml new file mode 100644 index 00000000..7d0801e5 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/default/converge.yml @@ -0,0 +1,27 @@ +--- +- name: "Run role" + hosts: all + any_errors_fatal: true + roles: + - grafana.grafana.opentelemetry_collector + vars: + otel_collector_receivers: + hostmetrics: + scrapers: + cpu: + memory: + otel_collector_processors: + memory_limiter: + check_interval: 2s + limit_percentage: 80 + spike_limit_percentage: 25 + batch: + otel_collector_exporters: + prometheus: + endpoint: '127.0.0.1:9999' + otel_collector_service: + pipelines: + metrics: + receivers: '{{ otel_collector_receivers.keys() }}' + processors: '{{ otel_collector_processors.keys() }}' + exporters: '{{ otel_collector_exporters.keys() }}' diff --git a/roles/opentelemetry_collector/molecule/default/molecule.yml b/roles/opentelemetry_collector/molecule/default/molecule.yml new file mode 100644 index 00000000..6258bc20 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/default/molecule.yml @@ -0,0 +1,44 @@ +--- +platforms: + - name: almalinux-9 + image: dokken/almalinux-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: centos-stream-9 + image: dokken/centos-stream-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: debian-11 + image: dokken/debian-11 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-36 + image: dokken/fedora-36 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-37 + image: dokken/fedora-37 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-20.04 + image: dokken/ubuntu-20.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-22.04 + image: dokken/ubuntu-22.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd diff --git a/roles/opentelemetry_collector/molecule/default/tests/test_default.py b/roles/opentelemetry_collector/molecule/default/tests/test_default.py new file mode 100644 index 00000000..f773241b --- /dev/null +++ b/roles/opentelemetry_collector/molecule/default/tests/test_default.py @@ -0,0 +1,35 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +def test_directories(host): + dirs = [ + "/etc/otel-collector", + ] + files = ["/etc/otel-collector/config.yaml"] + for directory in dirs: + d = host.file(directory) + assert d.is_directory + assert d.exists + for file in files: + f = host.file(file) + assert f.exists + assert f.is_file + + +def test_service(host): + s = host.service("otel-collector") + # assert s.is_enabled + assert s.is_running + + +def test_socket(host): + assert host.socket("tcp://127.0.0.1:9999").is_listening diff --git a/roles/opentelemetry_collector/molecule/latest/converge.yml b/roles/opentelemetry_collector/molecule/latest/converge.yml new file mode 100644 index 00000000..9d62bd90 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/latest/converge.yml @@ -0,0 +1,28 @@ +--- +- name: "Run role" + hosts: all + any_errors_fatal: true + roles: + - grafana.grafana.opentelemetry_collector + vars: + otel_collector_version: latest + otel_collector_receivers: + hostmetrics: + scrapers: + cpu: + memory: + otel_collector_processors: + memory_limiter: + check_interval: 2s + limit_percentage: 80 + spike_limit_percentage: 25 + batch: + otel_collector_exporters: + prometheus: + endpoint: '127.0.0.1:9999' + otel_collector_service: + pipelines: + metrics: + receivers: '{{ otel_collector_receivers.keys() }}' + processors: '{{ otel_collector_processors.keys() }}' + exporters: '{{ otel_collector_exporters.keys() }}' diff --git a/roles/opentelemetry_collector/molecule/latest/molecule.yml b/roles/opentelemetry_collector/molecule/latest/molecule.yml new file mode 100644 index 00000000..6258bc20 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/latest/molecule.yml @@ -0,0 +1,44 @@ +--- +platforms: + - name: almalinux-9 + image: dokken/almalinux-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: centos-stream-9 + image: dokken/centos-stream-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: debian-11 + image: dokken/debian-11 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-36 + image: dokken/fedora-36 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-37 + image: dokken/fedora-37 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-20.04 + image: dokken/ubuntu-20.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-22.04 + image: dokken/ubuntu-22.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd diff --git a/roles/opentelemetry_collector/molecule/latest/tests/test_default.py b/roles/opentelemetry_collector/molecule/latest/tests/test_default.py new file mode 100644 index 00000000..f773241b --- /dev/null +++ b/roles/opentelemetry_collector/molecule/latest/tests/test_default.py @@ -0,0 +1,35 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +def test_directories(host): + dirs = [ + "/etc/otel-collector", + ] + files = ["/etc/otel-collector/config.yaml"] + for directory in dirs: + d = host.file(directory) + assert d.is_directory + assert d.exists + for file in files: + f = host.file(file) + assert f.exists + assert f.is_file + + +def test_service(host): + s = host.service("otel-collector") + # assert s.is_enabled + assert s.is_running + + +def test_socket(host): + assert host.socket("tcp://127.0.0.1:9999").is_listening diff --git a/roles/opentelemetry_collector/molecule/non-contrib/converge.yml b/roles/opentelemetry_collector/molecule/non-contrib/converge.yml new file mode 100644 index 00000000..92d542df --- /dev/null +++ b/roles/opentelemetry_collector/molecule/non-contrib/converge.yml @@ -0,0 +1,27 @@ +--- +- name: "Run role" + hosts: all + any_errors_fatal: true + roles: + - grafana.grafana.opentelemetry_collector + vars: + otel_collector_type: '' + otel_collector_receivers: + hostmetrics: + scrapers: + cpu: + memory: + otel_collector_processors: + memory_limiter: + check_interval: 2s + limit_percentage: 80 + spike_limit_percentage: 25 + batch: + otel_collector_exporters: + debug: + otel_collector_service: + pipelines: + metrics: + receivers: '{{ otel_collector_receivers.keys() }}' + processors: '{{ otel_collector_processors.keys() }}' + exporters: '{{ otel_collector_exporters.keys() }}' diff --git a/roles/opentelemetry_collector/molecule/non-contrib/molecule.yml b/roles/opentelemetry_collector/molecule/non-contrib/molecule.yml new file mode 100644 index 00000000..6258bc20 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/non-contrib/molecule.yml @@ -0,0 +1,44 @@ +--- +platforms: + - name: almalinux-9 + image: dokken/almalinux-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: centos-stream-9 + image: dokken/centos-stream-9 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: debian-11 + image: dokken/debian-11 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-36 + image: dokken/fedora-36 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: fedora-37 + image: dokken/fedora-37 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-20.04 + image: dokken/ubuntu-20.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd + - name: ubuntu-22.04 + image: dokken/ubuntu-22.04 + pre_build_image: true + privileged: true + cgroup_parent: docker.slice + command: /lib/systemd/systemd diff --git a/roles/opentelemetry_collector/molecule/non-contrib/tests/test_default.py b/roles/opentelemetry_collector/molecule/non-contrib/tests/test_default.py new file mode 100644 index 00000000..ec37d6e4 --- /dev/null +++ b/roles/opentelemetry_collector/molecule/non-contrib/tests/test_default.py @@ -0,0 +1,31 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ["MOLECULE_INVENTORY_FILE"] +).get_hosts("all") + + +def test_directories(host): + dirs = [ + "/etc/otel-collector", + ] + files = ["/etc/otel-collector/config.yaml"] + for directory in dirs: + d = host.file(directory) + assert d.is_directory + assert d.exists + for file in files: + f = host.file(file) + assert f.exists + assert f.is_file + + +def test_service(host): + s = host.service("otel-collector") + # assert s.is_enabled + assert s.is_running diff --git a/roles/opentelemetry_collector/tasks/install.yml b/roles/opentelemetry_collector/tasks/install.yml index 8a814dd2..1c246a95 100644 --- a/roles/opentelemetry_collector/tasks/install.yml +++ b/roles/opentelemetry_collector/tasks/install.yml @@ -1,3 +1,25 @@ +- name: Discover latest OpenTelemetry Collector version + ansible.builtin.set_fact: + otel_collector_version: "{{ (lookup('url', otel_collector_latest_url, split_lines=False) | from_json).get('tag_name') | replace('v', '') }}" + run_once: true + until: otel_collector_version is version('0.0.0', '>=') + retries: 10 + when: + - otel_collector_version == 'latest' + +- name: Discover installed version + block: + - name: Get installed version + register: otel_collector_version_check + changed_when: false + failed_when: false + check_mode: false # Always run, this does not change anything on the system + ansible.builtin.command: '{{ otel_collector_installation_dir }}/{{ otel_collector_executable }} -v' + + - name: Set installed version variable + ansible.builtin.set_fact: + otel_collector_installed_version: "{{ otel_collector_version_check.stdout_lines[0] | default('otelcorecol version 0.0.0') | ansible.builtin.regex_search('\\d+\\.\\d+\\.\\d+') }}" + - name: Create otel group ansible.builtin.group: name: "{{ otel_collector_service_group }}" @@ -29,14 +51,14 @@ dest: "/tmp/otelcol-{{ otel_collector_type }}-{{ otel_collector_version }}.tar.gz" mode: '0755' become: true - register: download_result + when: otel_collector_installed_version is version(otel_collector_version, '!=') - name: Remove existing OpenTelemetry Collector installation directory ansible.builtin.file: path: "{{ otel_collector_installation_dir }}" state: absent become: true - when: download_result.changed + when: otel_collector_installed_version is version(otel_collector_version, '!=') - name: Create OpenTelemetry Collector installation directory ansible.builtin.file: @@ -54,4 +76,4 @@ remote_src: yes become: true register: extract_result - when: not ansible_check_mode + when: not ansible_check_mode and otel_collector_installed_version is version(otel_collector_version, '!=')