Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion tasks/common/custom-facts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@
'MemoryHigh': memory,
'Restart': restart_policy
}
| combine((systemd.enable_accounting | default(true)) | ternary({'CPUAccounting': 'yes', 'MemoryAccounting': 'yes', 'IOAccounting': 'yes', 'TasksAccounting': 'yes', 'IPAccounting': 'yes'}, {}), recursive=True)
| combine(
(systemd.enable_accounting | default(true)) |
ternary({'CPUAccounting': 'yes', 'MemoryAccounting': 'yes', 'IOAccounting': 'yes',
'TasksAccounting': 'yes', 'IPAccounting': 'yes'}, {}), recursive=True)
}}
_default_unit_install:
WantedBy: multi-user.target
Expand Down
21 changes: 12 additions & 9 deletions tasks/common/storage-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,31 @@
ansible.builtin.file:
path: "{{ host_data_dir }}"
state: directory
owner: "{{ user | default(ansible_user) }}"
group: "{{ group | default(user) | default(ansible_user) }}"
owner: "{{ user | default(ansible_user_id) }}"
group: "{{ group | default(user) | default(ansible_user_id) }}"
mode: "0755"
recurse: false

- name: Ensure existence of config directories {{ _config_file_directories }}
become: true
ansible.builtin.file:
path: "{{ host_data_dir + item.value.destinationPath | dirname }}"
state: directory
owner: "{{ user | default(ansible_user) }}"
group: "{{ group | default(user) | default(ansible_user) }}"
owner: "{{ user | default(ansible_user_id) }}"
group: "{{ group | default(user) | default(ansible_user_id) }}"
mode: "0755"
recurse: false
with_dict: "{{ config }}"

- name: Generate local rendering of service config files {{ _config_file_names }}
become: true
ansible.builtin.copy:
content: "{{ item.value.data | default(omit) }}"
dest: "{{ host_data_dir + item.value.destinationPath }}"
mode: "{{ item.value.mode | default(644) }}"
mode: "{{ item.value.mode | default('0644') }}"
src: "{{ item.value.sourcePath | default(omit) }}"
owner: "{{ user | default(ansible_user) }}"
group: "{{ group | default(user) | default(ansible_user) }}"
owner: "{{ user | default(ansible_user_id) }}"
group: "{{ group | default(user) | default(ansible_user_id) }}"
with_dict: "{{ config }}"

- name: Ensure existence of host data directories {{ _data_dirs_hostpaths }}
Expand All @@ -35,6 +38,6 @@
path: "{{ item.value.hostPath }}"
state: directory
mode: "0755"
owner: "{{ user | default(ansible_user) }}"
group: "{{ group | default(user) | default(ansible_user) }}"
owner: "{{ user | default(ansible_user_id) }}"
group: "{{ group | default(user) | default(ansible_user_id) }}"
with_dict: "{{ data_dirs }}"
20 changes: 20 additions & 0 deletions tasks/common/user-setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
- name: Ensure service group [{{ group | default(user) }}] exists
when: user is defined and user != 'root' and user != ansible_user_id
become: true
ansible.builtin.group:
name: "{{ group | default(user) }}"
state: present
system: true

- name: Ensure service user [{{ user }}] exists
when: user is defined and user != 'root' and user != ansible_user_id
become: true
ansible.builtin.user:
name: "{{ user }}"
group: "{{ group | default(user) }}"
state: present
system: true
create_home: false
shell: /usr/sbin/nologin
comment: "Service user for {{ name }}"
2 changes: 1 addition & 1 deletion tasks/container/setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
community.docker.docker_container:
name: "{{ name }}"
image: "{{ image }}"
user: "{{ user | default('root') }}"
user: root
command: "{{ command | default(omit) }}"
env: "{{ config_env }}"
published_ports: "{{ _port_list }}"
Expand Down
4 changes: 4 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
- name: Setup service components
when: uninstall is not defined or not uninstall | bool
block:
- name: Ensure service user exists
ansible.builtin.include_tasks: common/user-setup.yml
when: user is defined

- name: Manage storage/data setup
ansible.builtin.include_tasks: common/storage-setup.yml

Expand Down
11 changes: 11 additions & 0 deletions tests/molecule/container-basic/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,14 @@ verifier:
directory: ./tests
scenario:
name: container-basic
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- verify
- cleanup
- destroy
6 changes: 6 additions & 0 deletions tests/molecule/container-basic/tests/test_container_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ def test_container_running(host):
container = host.docker("nginx-container")
assert container.is_running

def test_container_user_is_root(host):
"""Verify that the container always runs as root."""
container = host.docker("nginx-container")
user = container.inspect()["Config"]["User"]
assert user == "root", f"Container user is not 'root', it is '{user}'."

def test_container_exposes_ports(host):
socket = host.socket("tcp://0.0.0.0:8080")
assert socket.is_listening
11 changes: 11 additions & 0 deletions tests/molecule/container-full/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,14 @@ verifier:
directory: ./tests
scenario:
name: container-full
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- verify
- cleanup
- destroy
1 change: 0 additions & 1 deletion tests/molecule/container-full/tests/test_container_full.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ def test_container_exposes_ports(host):
def test_container_user_is_root(host):
container = host.docker("full-container")
user = container.inspect()["Config"]["User"]

assert user == "root", f"Container user is not 'root', it is '{user}'."

def test_container_creates_hostdirectory(host):
Expand Down
11 changes: 11 additions & 0 deletions tests/molecule/systemd-basic/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,14 @@ verifier:
directory: ./tests
scenario:
name: systemd-basic
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- verify
- cleanup
- destroy
4 changes: 2 additions & 2 deletions tests/molecule/systemd-full/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
vars:
setup_mode: systemd
name: test-service
user: root
user: prometheus
binary_url: https://github.com/prometheus/prometheus/releases/download/v2.47.0/prometheus-2.47.0.linux-amd64.tar.gz
binary_strip_components: 1
binary_file_name_override: prometheus # set to trigger existence of extracted binary check
destination_directory: /usr/bin
command: /usr/bin/prometheus --config.file=/test/mnt/etc/prometheus/prometheus.yml
command: /usr/bin/prometheus --config.file=/test/mnt/etc/prometheus/prometheus.yml --storage.tsdb.path=/var/tmp/prometheus
cpus: 50
memory: 512M
config:
Expand Down
11 changes: 11 additions & 0 deletions tests/molecule/systemd-full/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,14 @@ verifier:
directory: ./tests
scenario:
name: systemd-full
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- verify
- cleanup
- destroy
29 changes: 26 additions & 3 deletions tests/molecule/systemd-full/tests/test_systemd_full.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_systemd_service_properties(host):

# Verify key systemd properties
assert "ExecStart=/usr/bin/prometheus --config.file=/test/mnt/etc/prometheus/prometheus.yml" in service_content, "ExecStart is not correctly set."
assert "User=root" in service_content, "The service user is not correctly set to root."
assert "User=prometheus" in service_content, "The service user is not correctly set to prometheus."
assert "CPUQuota=50%" in service_content, "CPUQuota is not correctly set."
assert "MemoryHigh=512M" in service_content, "MemoryHigh is not correctly set."
assert "Restart=on-failure" in service_content, "Restart policy is not correctly set."
Expand Down Expand Up @@ -59,8 +59,8 @@ def test_data_directory_exists(host):
data_dir = host.file("/var/tmp/prometheus")
assert data_dir.exists, "The data directory does not exist."
assert data_dir.is_directory, "The data directory is not a directory."
assert data_dir.user == "root", "The data directory is not owned by root."
assert data_dir.group == "root", "The data directory group is not root."
assert data_dir.user == "prometheus", "The data directory is not owned by prometheus."
assert data_dir.group == "prometheus", "The data directory group is not prometheus."


def test_service_logs_no_errors(host):
Expand Down Expand Up @@ -88,3 +88,26 @@ def test_systemd_ip_accounting(host):
accounting_output = host.run("systemctl show test-service --property=IPIngressBytes,IPEgressBytes")
assert accounting_output.rc == 0, "Failed to get IP accounting data from systemd."
assert "IPIngressBytes=" in accounting_output.stdout and "IPEgressBytes=" in accounting_output.stdout, "IP accounting data is not available."

def test_service_group_exists(host):
"""Verify that the prometheus service group was created."""
group = host.group("prometheus")
assert group.exists, "The prometheus group does not exist."
# System groups typically have GID < 1000
assert group.gid < 1000, f"The prometheus group is not a system group (GID: {group.gid})."

def test_service_user_exists(host):
"""Verify that the prometheus service user was created."""
user = host.user("prometheus")
assert user.exists, "The prometheus user does not exist."
assert user.shell == "/usr/sbin/nologin", "The prometheus user shell is not set to /usr/sbin/nologin."
assert user.group == "prometheus", "The prometheus user is not in the prometheus group."
# System users typically have UID < 1000
assert user.uid < 1000, f"The prometheus user is not a system user (UID: {user.uid})."

def test_config_file_ownership(host):
"""Verify that config files are owned by the prometheus user."""
config_file = host.file("/test/mnt/etc/prometheus/prometheus.yml")
assert config_file.exists, "The Prometheus configuration file does not exist."
assert config_file.user == "prometheus", "The config file is not owned by prometheus."
assert config_file.group == "prometheus", "The config file group is not prometheus."