primer commit

This commit is contained in:
Rénich Bon Ćirić 2025-08-06 05:45:11 -06:00
commit 864b3e4008
Signed by: renich
GPG key ID: BDA314B08CB17657
105 changed files with 3185 additions and 0 deletions

38
roles/common/README.md Normal file
View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,27 @@
# SPDX-License-Identifier: MIT-0
---
# defaults file for roles/common
# All common variables are now defined in vars/default.yaml for global access.
# List of certificates to generate.
# is_user: true will generate a .p12 file for browser import.
koji_certs_to_generate:
- name: kojihub
cn: "{{ koji_hub_fqdn }}" # Server certs must use the FQDN for the CN
is_user: false
- name: kojiweb
cn: "{{ koji_hub_fqdn }}" # Server certs must use the FQDN for the CN
is_user: false
- name: kojira
cn: kojira
is_user: false
- name: kojid
cn: kojid
is_user: false
- name: kojiadmin
cn: kojiadmin
is_user: true
- name: postgresql
cn: "{{ koji_db_host }}"
is_user: false

View file

@ -0,0 +1,10 @@
# SPDX-License-Identifier: MIT-0
---
galaxy_info:
author: MxOS Team
description: Common tasks for Koji deployment
company: MxOS
license: MIT
min_ansible_version: "2.1"
galaxy_tags: []
dependencies: []

View file

@ -0,0 +1,75 @@
---
- name: "Generate private key for {{ cert.name }}"
community.crypto.openssl_privatekey:
path: "{{ koji_pki_dir }}/{{ cert.name }}.key"
size: "{{ koji_cert_key_size }}"
mode: "{{ koji_pki_private_key_mode }}"
- name: "Generate CSR for {{ cert.name }}"
community.crypto.openssl_csr:
path: "{{ koji_pki_dir }}/{{ cert.name }}.csr"
privatekey_path: "{{ koji_pki_dir }}/{{ cert.name }}.key"
common_name: "{{ cert.cn }}"
country_name: "{{ koji_cert_country }}"
state_or_province_name: "{{ koji_cert_state }}"
locality_name: "{{ koji_cert_locality }}"
organization_name: "{{ koji_cert_organization }}"
- name: Create temporary OpenSSL config for signing
ansible.builtin.copy:
dest: "{{ koji_pki_dir }}/openssl-{{ cert.name }}.cnf"
content: |
[v3_ca]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
{% if cert.is_server is defined and cert.is_server %}
extendedKeyUsage = serverAuth, clientAuth
{% else %}
extendedKeyUsage = clientAuth
{% endif %}
subjectAltName = @alt_names
[alt_names]
DNS.1 = {{ cert.cn }}
{% for san in cert.sans|default([]) %}
DNS.{{ loop.index + 1 }} = {{ san }}
{% endfor %}
- name: "Sign certificate for {{ cert.name }} with our CA"
ansible.builtin.shell:
cmd: >
openssl x509 -req
-in {{ koji_pki_dir }}/{{ cert.name }}.csr
-CA {{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt
-CAkey {{ koji_pki_dir }}/{{ koji_ca_name }}_cert.key
-CAserial {{ koji_pki_dir }}/ca.srl
-CAcreateserial
-out {{ koji_pki_dir }}/{{ cert.name }}.crt
-days {{ koji_cert_expiration_days }}
-sha256
-extfile {{ koji_pki_dir }}/openssl-{{ cert.name }}.cnf
-extensions v3_ca
creates: "{{ koji_pki_dir }}/{{ cert.name }}.crt"
- name: "Remove temporary openssl.cnf for {{ cert.name }}"
ansible.builtin.file:
path: "{{ koji_pki_dir }}/openssl-{{ cert.name }}.cnf"
state: absent
- name: "Generate PKCS12 bundle for user {{ cert.name }}"
community.crypto.openssl_pkcs12:
action: export
path: "{{ koji_pki_dir }}/{{ cert.name }}_browser_cert.p12"
privatekey_path: "{{ koji_pki_dir }}/{{ cert.name }}.key"
certificate_path: "{{ koji_pki_dir }}/{{ cert.name }}.crt"
ca_certificates:
- "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt"
friendly_name: "{{ cert.name }}"
mode: "{{ koji_pki_file_mode }}"
when: cert.is_user
- name: "Create PEM file for {{ cert.name }}"
ansible.builtin.shell:
cmd: "cat {{ koji_pki_dir }}/{{ cert.name }}.crt {{ koji_pki_dir }}/{{ cert.name }}.key > {{ koji_pki_dir }}/{{ cert.name }}.pem"
creates: "{{ koji_pki_dir }}/{{ cert.name }}.pem"

102
roles/common/tasks/main.yml Normal file
View file

@ -0,0 +1,102 @@
- name: "Setup: Koji PKI Directory Structure"
tags: setup
block:
- name: "Create Koji PKI directory"
ansible.builtin.file:
path: "{{ koji_pki_dir }}"
state: directory
mode: "{{ koji_pki_dir_mode }}"
- name: "Create certificate database files"
ansible.builtin.copy:
content: "{{ item.content }}"
dest: "{{ koji_pki_dir }}/{{ item.name }}"
mode: "{{ koji_pki_file_mode }}"
loop:
- { name: "index.txt", content: "" }
- { name: "serial", content: "01\n" }
- name: "Generate: Koji Certificate Authority (CA)"
tags: ca
block:
- name: "Generate CA private key"
community.crypto.openssl_privatekey:
path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.key"
size: "{{ koji_cert_key_size }}"
mode: "{{ koji_pki_private_key_mode }}"
- name: "Generate CA CSR"
community.crypto.openssl_csr:
path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.csr"
privatekey_path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.key"
common_name: "Koji Certificate Authority"
organization_name: "{{ koji_cert_organization }}"
state_or_province_name: "{{ koji_cert_state }}"
locality_name: "{{ koji_cert_locality }}"
country_name: "{{ koji_cert_country }}"
basic_constraints:
- "CA:TRUE"
key_usage:
- keyCertSign
- cRLSign
- name: "Generate self-signed CA certificate"
community.crypto.x509_certificate:
path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt"
csr_path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.csr"
privatekey_path: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.key"
provider: selfsigned
selfsigned_not_after: "+{{ koji_cert_expiration_days }}d"
- name: "Generate: Component and User Certificates"
ansible.builtin.include_tasks: generate_single_cert.yaml
loop: "{{ koji_certs_to_generate }}"
loop_control:
loop_var: cert
tags: components
- name: Create GPG key batch file
ansible.builtin.copy:
content: |
%echo Generating a basic OpenPGP key
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Koji Signing Key
Name-Email: koji@{{ koji_hub_fqdn }}
Expire-Date: 0
Passphrase: {{ gpg_key_passphrase }}
%commit
%echo done
dest: "{{ koji_pki_dir }}/gpg_batch"
mode: "0600"
delegate_to: localhost
run_once: true
- name: Generate GPG key
ansible.builtin.shell:
cmd: "gpg --batch --gen-key {{ koji_pki_dir }}/gpg_batch"
creates: "{{ koji_pki_dir }}/gpg_key.pub"
delegate_to: localhost
run_once: true
- name: Export GPG public key
ansible.builtin.shell:
cmd: "gpg --armor --export 'Koji Signing Key' > {{ koji_pki_dir }}/gpg_key.pub"
creates: "{{ koji_pki_dir }}/gpg_key.pub"
delegate_to: localhost
run_once: true
- name: "Remove existing host keys"
ansible.builtin.shell:
cmd: "ssh-keygen -R {{ item }}"
loop: "{{ groups['all'] }}"
ignore_errors: true
- name: "Add new host keys"
ansible.builtin.known_hosts:
name: "{{ item }}"
key: "{{ lookup('pipe', 'ssh-keyscan -t rsa {{ item }}') }}"
state: present
loop: "{{ groups['all'] }}"

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/common

View file

@ -0,0 +1,3 @@
---
common_ca_key_path: "{{ common_koji_pki_dir }}/{{ common_ca_name }}_cert.key"
common_ca_cert_path: "{{ common_koji_pki_dir }}/{{ common_ca_name }}_cert.crt"

38
roles/koji-hub/README.md Normal file
View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,9 @@
---
koji_hub_plugin_dir: /usr/lib/koji-hub/plugins
koji_hub_config_dir: /etc/koji-hub/hub.conf.d
koji_web_config_dir: /etc/kojiweb/
httpd_ssl_config_file: /etc/httpd/conf.d/ssl.conf
koji_hub_httpd_config_file: /etc/httpd/conf.d/kojihub.conf
koji_client_config_file: /etc/koji.conf.d/main.conf
admin_user_home: "/home/{{ koji_admin_user }}"
admin_user_koji_dir: "{{ admin_user_home }}/.koji"

View file

@ -0,0 +1,66 @@
import koji
import kojihub
import xmlrpc.client
import logging
logger = logging.getLogger(__name__)
class SigulSignPlugin(kojihub.Plugin):
def __init__(self, hub):
super(SigulSignPlugin, self).__init__(hub)
self.sigul_server = self.hub.config.get('SigulServer')
if not self.sigul_server:
logger.error("SigulServer not configured in Koji Hub. Automated signing will not work.")
return
self.sigul_proxy = xmlrpc.client.ServerProxy(self.sigul_server)
logger.info(f"SigulSignPlugin initialized with server: {self.sigul_server}")
def postBuild(self, build_id, build, request, **kwargs):
"""
Called after a build is completed.
We will attempt to sign the RPMs in this build.
"""
if build.get('state') != koji.BUILD_STATES['COMPLETE']:
logger.info(f"Build {build_id} not complete, skipping signing.")
return
logger.info(f"Attempting to sign RPMs for build {build_id} ({build.get('nvr')})")
# Get RPMs associated with the build
rpms = self.hub.getBuildRPMs(build_id)
if not rpms:
logger.info(f"No RPMs found for build {build_id}, skipping signing.")
return
for rpm in rpms:
rpm_id = rpm['id']
rpm_nvr = rpm['nvr']
rpm_path = rpm['path'] # This path is relative to KojiDir
# Construct full path to RPM on the Koji filesystem
# In a real scenario, you might need to fetch the RPM from Koji's storage
# For simplicity, we assume Sigul can access Koji's storage directly or via URL
full_rpm_path = f"{self.hub.config.get('KojiDir')}/{rpm_path}"
try:
# Call Sigul to sign the RPM
# This is a mock call. A real Sigul API call would be more complex.
logger.info(f"Calling Sigul to sign {full_rpm_path}")
# result = self.sigul_proxy.sign_rpm(full_rpm_path) # Example Sigul API call
result = {'success': True, 'signature': 'mock_signature_data'} # Mock result
if result.get('success'):
logger.info(f"Successfully signed RPM {rpm_nvr}. Importing signature to Koji.")
# Import signature back into Koji
# This is a simplified example. Koji's import-sig expects specific data.
# For a real plugin, you'd get the actual signature from Sigul and format it.
self.hub.importSig(rpm_id, 'mock_sig_id', 'mock_sig_type', result['signature'])
logger.info(f"Signature imported for {rpm_nvr}.")
else:
logger.error(f"Sigul failed to sign {rpm_nvr}: {result.get('error', 'Unknown error')}")
except Exception as e:
logger.error(f"Error signing RPM {rpm_nvr}: {e}")
# Register the plugin
kojihub.add_plugin(SigulSignPlugin)

View file

@ -0,0 +1,11 @@
#SPDX-License-Identifier: MIT-0
---
- name: Restart httpd
ansible.builtin.service:
name: httpd
state: restarted
- name: Reload firewalld
ansible.builtin.service:
name: firewalld
state: reloaded

View file

@ -0,0 +1,36 @@
---
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,275 @@
---
- name: Install Koji Hub, Web, httpd, and crypto packages
ansible.builtin.dnf:
name:
- httpd
- koji-hub
- koji-web
- mod_ssl
- mod_wsgi
- nmap-ncat
- policycoreutils-python-utils
- postgresql
- python3-cryptography
- rpmdevtools
- rpmlint
- koji-hub-plugins
state: present
- name: Create directories for certs and client configs
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: apache
group: apache
mode: "0700"
loop:
- "{{ koji_top_dir }}/certs"
- "{{ koji_top_dir }}/clients"
- "{{ koji_top_dir }}/packages"
- "{{ koji_top_dir }}/repos"
- "{{ koji_top_dir }}/work"
- "{{ koji_top_dir }}/scratch"
- "{{ koji_top_dir }}/repos-dist"
- name: Ensure admin user '{{ koji_admin_user }}' exists
ansible.builtin.user:
name: "{{ koji_admin_user }}"
state: present
create_home: true
- name: Add kojiadmin to wheel group for sudo access
ansible.builtin.user:
name: "{{ koji_admin_user }}"
groups: wheel
append: true
state: present
- name: Ensure wheel group has NOPASSWD sudo access
ansible.builtin.lineinfile:
path: /etc/sudoers
regexp: '^# %wheel\s+ALL=\(ALL\)\s+NOPASSWD:\s+ALL$'
line: '%wheel ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
state: present
- name: Ensure .koji directory exists for '{{ koji_admin_user }}'
ansible.builtin.file:
path: "{{ admin_user_koji_dir }}"
state: directory
mode: "{{ koji_client_dir_mode }}"
- name: Configure Koji client for admin user
ansible.builtin.template:
src: koji.conf.j2
dest: "{{ admin_user_koji_dir }}/config"
mode: "{{ koji_client_file_mode }}"
- name: Copy client certificates for '{{ koji_admin_user }}'
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ admin_user_koji_dir }}/{{ item.dest }}"
mode: "{{ koji_client_file_mode }}"
loop:
- src: "{{ koji_pki_dir }}/kojiadmin.pem"
dest: client.pem
- src: "{{ koji_pki_dir }}/kojiadmin.key"
dest: client.key
- src: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt"
dest: clientca.crt
- src: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt"
dest: serverca.crt
- name: Create Koji PKI directory on the hub
ansible.builtin.file:
path: "{{ koji_remote_pki_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Copy Koji certificates to the hub
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: "{{ item.mode }}"
loop:
- { src: "{{ koji_ca_name }}_cert.crt", dest: "{{ koji_remote_ca_trust_path }}", mode: "0644" }
- { src: "kojihub.crt", dest: "{{ koji_hub_cert_path }}", mode: "0644", group: "apache" }
- { src: "kojihub.key", dest: "{{ koji_hub_key_path }}", mode: "0640", group: "apache" }
- { src: "kojihub.pem", dest: "/etc/pki/koji/kojihub.pem", mode: "0644", group: "apache" }
- { src: "kojiadmin.pem", dest: "{{ koji_admin_cert_path }}", mode: "0644" }
- name: Update CA trust store
ansible.builtin.shell: update-ca-trust
changed_when: true
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Configure httpd for Koji
ansible.builtin.lineinfile:
path: "{{ item.path }}"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backup: true
loop:
- { path: "{{ httpd_ssl_config_file }}", regexp: "^SSLCertificateFile", line: "SSLCertificateFile {{ koji_hub_cert_path }}" }
- { path: "{{ httpd_ssl_config_file }}", regexp: "^SSLCertificateKeyFile", line: "SSLCertificateKeyFile {{ koji_hub_key_path }}" }
- { path: "{{ httpd_ssl_config_file }}", regexp: "^#?SSLCACertificateFile", line: "SSLCACertificateFile {{ koji_remote_ca_trust_path }}" }
notify: Restart httpd
- name: Enable SSL for Koji Hub
ansible.builtin.blockinfile:
path: "{{ koji_hub_httpd_config_file }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK"
block: |
<Location /kojihub/ssllogin>
SSLVerifyClient require
SSLVerifyDepth 10
SSLOptions +StdEnvVars
</Location>
notify: Restart httpd
- name: Template Koji Hub and Web configs
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
group: apache
mode: "0640"
loop:
- { src: "00-main.conf.j2", dest: "{{ koji_hub_config_dir }}/00-main.conf" }
- { src: "db.conf.j2", dest: "{{ koji_hub_config_dir }}/db.conf" }
- { src: "admin.conf.j2", dest: "{{ koji_hub_config_dir }}/admin.conf" }
- { src: "web.conf.j2", dest: "{{ koji_web_config_dir }}/web.conf" }
- { src: "policies.conf.j2", dest: "{{ koji_hub_config_dir }}/policies.conf" }
- { src: "99-local-policies.conf.j2", dest: "{{ koji_hub_config_dir }}/99-local-policies.conf" }
notify: Restart httpd
- name: Set SELinux booleans for Apache
ansible.posix.seboolean:
name: "{{ item }}"
state: true
persistent: true
loop:
- httpd_can_network_connect_db
- httpd_can_network_connect
- allow_httpd_anon_write
- httpd_use_nfs
- name: Start and enable httpd
ansible.builtin.service:
name: httpd
state: started
enabled: true
- name: Open firewall for http/https
ansible.posix.firewalld:
service: "{{ item }}"
permanent: true
state: enabled
loop: ["http", "https"]
notify: Reload firewalld
- name: Add database host to /etc/hosts
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ hostvars[groups['kojidb'][0]].ansible_default_ipv4.address }} {{ koji_db_host }}"
regexp: ".*{{ koji_db_host }}"
state: present
- name: Wait for database to be available
ansible.builtin.wait_for:
host: "{{ koji_db_host }}"
port: 5432
timeout: 120
- name: Check if Koji DB schema is loaded
ansible.builtin.shell:
cmd: psql -h {{ koji_db_host }} -U {{ koji_db_user }} -d {{ koji_db_name }} -c "SELECT 'users'::regclass;"
register: schema_check
failed_when: false
changed_when: false
environment:
PGPASSWORD: "{{ koji_db_password }}"
- name: Load Koji DB Schema
ansible.builtin.shell:
cmd: psql -h {{ koji_db_host }} -U {{ koji_db_user }} -d {{ koji_db_name }} -f /usr/share/koji/schema.sql
when: schema_check.rc != 0
environment:
PGPASSWORD: "{{ koji_db_password }}"
- name: Check if Koji DB schema is loaded
community.postgresql.postgresql_query:
login_db: "{{ koji_db_name }}"
query: "SELECT 'users'::regclass;"
login_host: "{{ koji_db_host }}"
login_user: "{{ koji_db_user }}"
login_password: "{{ koji_db_password }}"
register: schema_check
- name: Load Koji DB Schema
community.postgresql.postgresql_script:
db: "{{ koji_db_name }}"
path: /usr/share/koji/schema.sql
login_host: "{{ koji_db_host }}"
login_user: "{{ koji_db_user }}"
login_password: "{{ koji_db_password }}"
when: schema_check.failed
- name: Create kojiadmin user in database
community.postgresql.postgresql_query:
login_db: "{{ koji_db_name }}"
query: "INSERT INTO users (name, status, usertype) VALUES ('{{ koji_admin_user }}', 0, 0) ON CONFLICT DO NOTHING"
login_host: "{{ koji_db_host }}"
login_user: "{{ koji_db_user }}"
login_password: "{{ koji_db_password }}"
- name: Configure Koji client via ansible-settings.conf
ansible.builtin.template:
src: koji.conf.j2
dest: "{{ koji_client_config_file }}"
group: apache
mode: "0644"
- name: Grant admin privileges to kojiadmin user
community.postgresql.postgresql_query:
login_db: "{{ koji_db_name }}"
query: "INSERT INTO user_perms (user_id, perm_id, creator_id) VALUES ((SELECT id FROM users WHERE name = '{{ koji_admin_user }}'), (SELECT id FROM permissions WHERE name = 'admin'), (SELECT id FROM users WHERE name = '{{ koji_admin_user }}')) ON CONFLICT DO NOTHING"
login_host: "{{ koji_db_host }}"
login_user: "{{ koji_db_user }}"
login_password: "{{ koji_db_password }}"
- name: Ensure correct ownership of kojiadmin config
ansible.builtin.file:
path: "{{ admin_user_koji_dir }}"
owner: "{{ koji_admin_user }}"
group: "{{ koji_admin_user }}"
recurse: true
- name: Add Koji builder hosts
ansible.builtin.shell:
cmd: "sudo -u kojiadmin koji --config={{ admin_user_koji_dir }}/config add-host {{ item }} x86_64"
loop: "{{ groups['kojibuilders'] }}"
register: add_host_result
failed_when: "add_host_result.rc != 0 and 'already in the database' not in add_host_result.stderr"
changed_when: "add_host_result.rc == 0"
- name: Add Koji builder hosts to createrepo channel
ansible.builtin.shell:
cmd: "sudo -u kojiadmin koji --config={{ admin_user_koji_dir }}/config add-host-to-channel {{ item }} createrepo"
loop: "{{ groups['kojibuilders'] }}"
register: add_channel_result
failed_when: "add_channel_result.rc != 0 and 'already in the database' not in add_channel_result.stderr and 'already subscribed to the createrepo channel' not in add_channel_result.stderr"
changed_when: "add_channel_result.rc == 0"
- name: Set Koji builder host capacity
ansible.builtin.shell:
cmd: "sudo -u kojiadmin koji --config={{ admin_user_koji_dir }}/config edit-host --capacity={{ kojid_max_jobs }} {{ item }}"
loop: "{{ groups['kojibuilders'] }}"
changed_when: true

View file

@ -0,0 +1,5 @@
[hub]
KojiWebURL = https://{{ koji_hub_fqdn }}/koji
KojiDir = {{ koji_top_dir }}
AuthMethods = ssl, password
LoginCreatesUser = On

View file

@ -0,0 +1,2 @@
[hub-policy:admin]
user = {{ koji_admin_user }}

View file

@ -0,0 +1,2 @@
[hub]
AdminUsers = {{ koji_admin_user }}

View file

@ -0,0 +1,2 @@
[hub]
DBConnectionString = postgresql://{{ koji_db_user }}:{{ koji_db_password }}@{{ koji_db_host }}/{{ koji_db_name }}?sslmode=verify-full&sslrootcert=/etc/pki/tls/certs/ca-bundle.crt

View file

@ -0,0 +1,25 @@
# Koji Hub Configuration
[hub]
# Main directory for Koji data (packages, repos, etc.)
KojiDir = {{ koji_top_dir }}
# Authentication methods. 'ssl' is primary for clients, 'password' for web UI.
AuthMethods = ssl, password
# Automatically create a user account on first successful SSL login.
LoginCreatesUser = On
# Header used by Apache/mod_proxy to forward the original client IP.
ProxyUserHeader = X-Forwarded-For
# Message to display in the client when the hub is offline.
ServerOfflineMessage = The Koji build system is currently offline for maintenance.
# How long builder should wait for host-init to finish (seconds)
HostInitTimeout = 120
Plugins = sigul_sign
[sigul]
# Sigul server URL (replace with actual Sigul server address)
SigulServer = http://localhost:8080/sigul

View file

@ -0,0 +1,9 @@
[koji]
server = https://{{ koji_hub_fqdn }}/kojihub
weburl = http://{{ koji_hub_fqdn }}/koji
topurl = http://{{ koji_hub_fqdn }}/kojifiles
topdir = {{ koji_top_dir }}
cert = ~/.koji/client.pem
key = /home/{{ koji_admin_user }}/.koji/client.key
serverca = /home/{{ koji_admin_user }}/.koji/serverca.crt
authtype = ssl

View file

@ -0,0 +1,38 @@
#!/bin/bash
set -e
KOJI_CMD="sudo -u kojiadmin koji --config=/home/kojiadmin/.koji/config"
# Clean up previous attempts to ensure a clean slate
$KOJI_CMD remove-target "{{ koji_build_tag }}-build" || echo "Target {{ koji_build_tag }}-build did not exist"
$KOJI_CMD remove-tag "{{ koji_build_tag }}-build" || echo "Tag {{ koji_build_tag }}-build did not exist"
$KOJI_CMD remove-tag "{{ koji_build_tag }}" || echo "Tag {{ koji_build_tag }} did not exist"
# Tags
$KOJI_CMD add-tag "{{ koji_build_tag }}" || echo "Tag {{ koji_build_tag }} already exists"
$KOJI_CMD add-tag --parent "{{ koji_build_tag }}" --arches "x86_64" "{{ koji_build_tag }}-build" || echo "Tag {{ koji_build_tag }}-build already exists"
# Target
$KOJI_CMD add-target "{{ koji_build_tag }}-build" "{{ koji_build_tag }}-build" || echo "Target {{ koji_build_tag }}-build already exists"
# External Repos
$KOJI_CMD add-external-repo -t "{{ koji_build_tag }}-build" "centos-stream-10-baseos" "http://mirror.stream.centos.org/10-stream/BaseOS/x86_64/os/" || echo "External repo centos-stream-10-baseos already exists"
$KOJI_CMD add-external-repo -t "{{ koji_build_tag }}-build" "centos-stream-10-appstream" "http://mirror.stream.centos.org/10-stream/AppStream/x86_64/os/" || echo "External repo centos-stream-10-appstream already exists"
# Groups
$KOJI_CMD add-group "{{ koji_build_tag }}-build" "build" || echo "Group build already exists"
$KOJI_CMD add-group-pkg "{{ koji_build_tag }}-build" "build" "build-sys" || echo "Package build-sys already in group build"
$KOJI_CMD add-group-pkg "{{ koji_build_tag }}-build" "build" "python3-dnf" || echo "Package python3-dnf already in group build"
$KOJI_CMD add-group-pkg "{{ koji_build_tag }}-build" "build" "python3-dnf-plugins-core" || echo "Package python3-dnf-plugins-core already in group build"
# Hosts
{% for host in groups['kojibuilders'] %}
$KOJI_CMD add-host "{{ host }}" x86_64 || echo "Host {{ host }} already exists"
$KOJI_CMD add-host-to-channel "{{ host }}" createrepo || echo "Host {{ host }} already in channel createrepo"
$KOJI_CMD edit-host --capacity={{ kojid_max_jobs }} "{{ host }}" || echo "Could not edit host {{ host }}"
{% endfor %}
# Repo
$KOJI_CMD add-user kojira || echo "User kojira already exists"
$KOJI_CMD grant-permission repo kojira || echo "Permission repo already granted to kojira"
$KOJI_CMD regen-repo --nowait "{{ koji_build_tag }}-build"

View file

@ -0,0 +1,2 @@
[hub-policy:admin]
user = {{ koji_admin_user }}

View file

@ -0,0 +1,10 @@
[web]
SiteName = MxOS koji
KojiHubURL = https://{{ koji_hub_fqdn }}/kojihub
KojiFilesURL = https://{{ koji_hub_fqdn }}/kojifiles
WebAuthType = ssl
LoginTimeout = 72
Secret = {{ web_secret }}
LibPath = /usr/share/koji-web/lib
serverca = {{ koji_remote_ca_trust_path }}
LiteralFooter = True

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/koji-hub

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# vars file for roles/koji-hub

38
roles/kojid/README.md Normal file
View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,2 @@
---
kojid_work_dir: /var/lib/kojid

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- name: Restart kojid
ansible.builtin.service:
name: kojid
state: restarted

36
roles/kojid/meta/main.yml Normal file
View file

@ -0,0 +1,36 @@
# SPDX-License-Identifier: MIT-0
---
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,95 @@
---
- name: Install Koji-Builder packages and rpm-build
ansible.builtin.dnf:
name:
- koji-builder
- rpm-build
- rpmdevtools
- mock
- centos-stream-repos
- koji-builder-plugins
state: present
- name: Create kojid work directory
ansible.builtin.file:
path: "{{ kojid_work_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Ensure kojibuilder user exists and is in the mock group
ansible.builtin.user:
name: kojibuilder
groups: mock
state: present
- name: Ensure /etc/mock/koji has correct permissions
ansible.builtin.file:
path: /etc/mock/koji
state: directory
owner: root
group: mock
mode: "2775"
- name: Configure mock site defaults
ansible.builtin.template:
src: site-defaults.cfg.j2
dest: /etc/mock/site-defaults.cfg
mode: "0644"
- name: Configure kojid
ansible.builtin.template:
src: kojid.conf.j2
dest: /etc/kojid/kojid.conf
mode: "0644"
notify: Restart kojid
- name: Ensure /etc/pki/koji directory exists
ansible.builtin.file:
path: /etc/pki/koji
state: directory
owner: root
group: root
mode: "0755"
- name: Copy Koji certificates to the builder
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: "{{ item.mode }}"
loop:
- {src: "{{ koji_ca_name }}_cert.crt", dest: "{{ koji_remote_ca_trust_path }}", mode: "0644"}
- {src: "kojid.crt", dest: "{{ kojid_crt_path }}", mode: "0644"}
- {src: "kojid.key", dest: "{{ kojid_key_path }}", mode: "0600"}
- name: "Concatenate certificate and key into a PEM file"
ansible.builtin.shell:
cmd: "cat {{ kojid_crt_path }} {{ kojid_key_path }} > {{ kojid_pem_path }}"
creates: "{{ kojid_pem_path }}"
- name: Set ownership and permissions on kojid.pem
ansible.builtin.file:
path: "{{ kojid_pem_path }}"
owner: root
group: root
mode: "0600"
- name: Update CA trust
ansible.builtin.command: update-ca-trust
- name: Start and enable kojid service
ansible.builtin.service:
name: kojid
state: started
enabled: true
- name: Add koji hub to /etc/hosts
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ hostvars[groups['kojihub'][0]].ansible_default_ipv4.address }} {{ koji_hub_fqdn }}"
regexp: ".*{{ koji_hub_fqdn }}"
state: present

View file

@ -0,0 +1,35 @@
[kojid]
; jobs
maxjobs = {{ kojid_max_jobs }}
; paths
topdir = {{ koji_top_dir }}
workdir = {{ kojid_work_dir }}
mockdir = /var/lib/mock
; ID
user = {{ kojid_fqdn }}
mockuser = {{ kojid_mock_user }}
vendor = {{ kojid_vendor }}
packager = {{ kojid_packager }}
distribution = {{ kojid_distribution }}
; servers
server = https://{{ koji_hub_fqdn }}/kojihub
topurl = https://{{ koji_hub_fqdn }}/kojifiles
; SCM
allowed_scms = {{ kojid_allowed_scms }}
allowed_scms_use_config = {{ kojid_allowed_scms_use_config }}
allowed_scms_use_policy = {{ kojid_allowed_scms_use_policy }}
; mail
smtphost = {{ kojid_smtp_host }}
smtp_user = {{ kojid_smtp_user }}
smtp_pass = {{ kojid_smtp_pass }}
from_addr = {{ kojid_from_addr }}
; certs
cert = {{ kojid_pem_path }}
serverca = {{ koji_remote_ca_trust_path }}

View file

@ -0,0 +1,27 @@
config_opts['releasever'] = '10'
config_opts['yum.conf'] = """
[main]
gpgcheck=1
install_weak_deps=0
keepcache=1
reposdir=/dev/null
retries=20
strict=1
[baseos]
name=CentOS Stream 10 - BaseOS
baseurl=http://mirror.stream.centos.org/10-stream/BaseOS/x86_64/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
[appstream]
name=CentOS Stream 10 - AppStream
baseurl=http://mirror.stream.centos.org/10-stream/AppStream/x86_64/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
[crb]
name=CentOS Stream 10 - CRB
baseurl=http://mirror.stream.centos.org/10-stream/CRB/x86_64/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256
enabled=1
"""
config_opts['chroot_setup_cmd'] = 'install rpm-build rpmdevtools rpmlint'

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/kojid

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: MIT-0
---
# vars file for roles/kojid

38
roles/kojira/README.md Normal file
View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: MIT-0
---
# defaults file for roles/kojira

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- name: Restart kojira
ansible.builtin.service:
name: kojira
state: restarted

View file

@ -0,0 +1,36 @@
# SPDX-License-Identifier: MIT-0
---
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,37 @@
#SPDX-License-Identifier: MIT-0
---
- name: Install Koji Utils package (which includes kojira)
ansible.builtin.dnf:
name: ["koji-utils"]
state: present
- name: Configure kojira
ansible.builtin.template:
src: kojira.conf.j2
dest: "{{ koji_remote_kojira_conf_path }}"
mode: "0644"
- name: Copy Koji certificates for kojira
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: "{{ item.mode }}"
loop:
- { src: "{{ koji_ca_name }}_cert.crt", dest: "/etc/pki/koji/koji_ca_cert.crt", mode: "0644" }
- { src: "kojira.crt", dest: "/etc/pki/koji/kojira.crt", mode: "0644" }
- { src: "kojira.key", dest: "/etc/pki/koji/kojira.key", mode: "0600" }
- name: "Concatenate certificate and key into a PEM file"
ansible.builtin.shell:
cmd: "cat /etc/pki/koji/kojira.crt /etc/pki/koji/kojira.key > /etc/pki/koji/kojira.pem"
creates: "/etc/pki/koji/kojira.pem"
- name: Start and enable kojira service
ansible.builtin.service:
name: kojira
state: started
enabled: true

View file

@ -0,0 +1,4 @@
[kojira]
server = https://{{ koji_hub_fqdn }}/kojihub
cert = {{ kojira_cert_path }}
serverca = {{ koji_remote_ca_trust_path }}

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/kojira

View file

@ -0,0 +1,4 @@
# SPDX-License-Identifier: MIT-0
---
# vars file for roles/kojira

View file

@ -0,0 +1,5 @@
---
- name: Reload firewalld
ansible.builtin.service:
name: firewalld
state: reloaded

View file

@ -0,0 +1,54 @@
---
- name: Install Python and Flask
ansible.builtin.dnf:
name:
- python3
- python3-flask
state: present
- name: Create mock Sigul server directory
ansible.builtin.file:
path: /opt/mock-sigul-server
state: directory
mode: "0755"
- name: Create mock Sigul server Python script
ansible.builtin.copy:
content: |
from flask import Flask, request, jsonify
import logging
import os
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
@app.route('/sigul', methods=['POST'])
def sigul_endpoint():
app.logger.info(f"Received request: {request.json}")
# Simulate successful signing
return jsonify({"success": True, "signature": "mock_signature_data_from_sigul"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
dest: /opt/mock-sigul-server/app.py
mode: "0644"
- name: Create systemd service file for mock Sigul server
ansible.builtin.template:
src: mock-sigul-server.service.j2
dest: /etc/systemd/system/mock-sigul-server.service
mode: "0644"
- name: Start and enable mock Sigul server service
ansible.builtin.systemd:
name: mock-sigul-server
state: started
enabled: true
daemon_reload: true
- name: Open firewall for mock Sigul server (port 8080)
ansible.posix.firewalld:
port: 8080/tcp
permanent: true
state: enabled
notify: Reload firewalld

View file

@ -0,0 +1,13 @@
[Unit]
Description=Mock Sigul Server
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/opt/mock-sigul-server
ExecStart=/usr/bin/python3 /opt/mock-sigul-server/app.py
Restart=always
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# defaults file for roles/nfs-client

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# handlers file for roles/nfs-client

View file

@ -0,0 +1,36 @@
---
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,36 @@
#SPDX-License-Identifier: MIT-0
---
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,27 @@
#SPDX-License-Identifier: MIT-0
---
- name: Install NFS client packages
ansible.builtin.dnf:
name: nfs-utils
state: present
- name: Create mount point directory
ansible.builtin.file:
path: "{{ koji_top_dir }}"
state: directory
mode: "0755"
- name: Add kojifs0 to /etc/hosts
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ hostvars[groups['kojifs'][0]].ansible_default_ipv4.address }} {{ koji_nfs_host }}"
create: true
state: present
- name: Mount the Koji NFS share
ansible.posix.mount:
path: "{{ koji_top_dir }}"
src: "{{ koji_nfs_host }}:{{ koji_top_dir }}"
fstype: nfs
opts: "rw,sync"
state: mounted

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/nfs-client

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# vars file for roles/nfs-client

View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# defaults file for roles/nfs-server

View file

@ -0,0 +1,11 @@
#SPDX-License-Identifier: MIT-0
---
- name: Restart nfs-server
ansible.builtin.service:
name: nfs-server
state: restarted
- name: Reload firewalld
ansible.builtin.service:
name: firewalld
state: reloaded

View file

@ -0,0 +1,36 @@
---
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,49 @@
#SPDX-License-Identifier: MIT-0
---
- name: Install NFS server packages
ansible.builtin.dnf:
name: nfs-utils
state: present
- name: Create the Koji top directory to be exported
ansible.builtin.file:
path: "{{ koji_top_dir }}"
state: directory
owner: nobody
group: nobody
mode: "0755"
- name: Add Koji nodes to /etc/hosts on NFS server
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ hostvars[item].ansible_default_ipv4.address }} {{ item }}"
create: true
state: present
loop: "{{ groups['koji_nodes'] }}"
- name: Configure the NFS export for all Koji nodes
ansible.builtin.template:
src: exports.j2
dest: /etc/exports
owner: root
group: root
mode: "0644"
- name: Export all NFS filesystems
ansible.builtin.command: exportfs -ra
changed_when: true
- name: Start and enable NFS services
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop: ["rpcbind", "nfs-server"]
- name: Open firewall for NFS
ansible.posix.firewalld:
service: "{{ item }}"
permanent: true
state: enabled
loop: ["nfs", "rpc-bind", "mountd"]
notify: Reload firewalld

View file

@ -0,0 +1,3 @@
{% for host in groups['koji_nodes'] %}
{{ koji_top_dir }} {{ host }}(rw,sync,no_root_squash)
{% endfor %}

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/nfs-server

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# vars file for roles/nfs-server

View file

@ -0,0 +1,38 @@
Role Name
=========
A brief description of the role goes here.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- { role: username.rolename, x: 42 }
License
-------
BSD
Author Information
------------------
An optional section for the role authors to include contact information, or a website (HTML is not allowed).

View file

@ -0,0 +1,2 @@
---
koji_db_network: "192.168.122.0/24"

View file

@ -0,0 +1,10 @@
---
- name: Restart postgresql
ansible.builtin.service:
name: postgresql
state: restarted
- name: Reload firewalld
ansible.builtin.systemd:
name: firewalld
state: reloaded

View file

@ -0,0 +1,36 @@
---
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
# - MIT
# - GPL-2.0-or-later
# - GPL-3.0-only
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View file

@ -0,0 +1,128 @@
#SPDX-License-Identifier: MIT-0
---
- name: Install PostgreSQL packages
ansible.builtin.dnf:
name: ["postgresql-server", "python3-psycopg2"]
state: present
- name: Initialize the PostgreSQL database
ansible.builtin.command: postgresql-setup --initdb
args:
creates: /var/lib/pgsql/data/postgresql.conf
- name: Copy PostgreSQL server certificate
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/postgresql.crt"
dest: "/var/lib/pgsql/data/server.crt"
owner: postgres
group: postgres
mode: "0644"
notify: Restart postgresql
- name: Copy PostgreSQL server key
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/postgresql.key"
dest: "/var/lib/pgsql/data/server.key"
owner: postgres
group: postgres
mode: "0600"
notify: Restart postgresql
- name: Copy CA certificate to PostgreSQL data directory
ansible.builtin.copy:
src: "{{ koji_pki_dir }}/{{ koji_ca_name }}_cert.crt"
dest: "/var/lib/pgsql/data/ca.crt"
owner: postgres
group: postgres
mode: "0644"
notify: Restart postgresql
- name: Start and enable PostgreSQL service
ansible.builtin.service:
name: postgresql
state: started
enabled: true
- name: Configure PostgreSQL settings
community.postgresql.postgresql_set:
name: "{{ item.name }}"
value: "{{ item.value }}"
loop:
- { name: 'ssl_ca_file', value: 'ca.crt' }
- { name: 'ssl', value: 'on' }
- { name: 'ssl_cert_file', value: 'server.crt' }
- { name: 'ssl_key_file', value: 'server.key' }
- { name: 'max_connections', value: '200' }
- { name: 'listen_addresses', value: '*' }
become: true
become_user: postgres
notify: Restart postgresql
- name: Remove old pg_hba.conf entry for Koji hub (IPv4 network)
community.postgresql.postgresql_pg_hba:
dest: /var/lib/pgsql/data/pg_hba.conf
contype: hostssl
databases: "{{ koji_db_name }}"
users: "{{ koji_db_user }}"
address: "{{ koji_db_network }}"
method: scram-sha-256
state: absent
notify: Restart postgresql
- name: Configure pg_hba.conf to allow connection from the Koji hub (IPv4 address)
community.postgresql.postgresql_pg_hba:
dest: /var/lib/pgsql/data/pg_hba.conf
contype: hostssl
databases: "{{ koji_db_name }}"
users: "{{ koji_db_user }}"
address: "{{ hostvars[groups['kojihub'][0]].ansible_default_ipv4.address }}/32"
method: scram-sha-256
backup: true
notify: Restart postgresql
- name: Configure pg_hba.conf to allow IPv6 connection from the Koji hub
community.postgresql.postgresql_pg_hba:
dest: /var/lib/pgsql/data/pg_hba.conf
contype: hostssl
databases: "{{ koji_db_name }}"
users: "{{ koji_db_user }}"
address: "{{ hostvars[groups['kojihub'][0]].ansible_default_ipv6.address }}/128"
method: scram-sha-256
backup: true
notify: Restart postgresql
- name: Configure pg_hba.conf for local postgres user trust authentication
community.postgresql.postgresql_pg_hba:
dest: /var/lib/pgsql/data/pg_hba.conf
contype: local
databases: all
users: postgres
method: peer
backup: true
notify: Restart postgresql
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Create Koji database user
community.postgresql.postgresql_user:
name: "{{ koji_db_user }}"
password: "{{ koji_db_password }}"
become: true
become_user: postgres
- name: Create Koji database
community.postgresql.postgresql_db:
name: "{{ koji_db_name }}"
owner: "{{ koji_db_user }}"
become: true
become_user: postgres
- name: Open firewall for PostgreSQL
ansible.posix.firewalld:
port: 5432/tcp
permanent: true
state: enabled
notify: Reload firewalld

View file

@ -0,0 +1,44 @@
---
- name: Stop Koji Hub and Kojira services before database reset
ansible.builtin.service:
name: "{{ item }}"
state: stopped
loop:
- httpd
- kojira
delegate_to: "{{ groups['kojihub'][0] }}"
- name: Terminate all active connections to Koji database
community.postgresql.postgresql_query:
query: "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{{ koji_db_name }}';"
login_db: postgres
become: true
become_user: postgres
- name: Drop Koji database
community.postgresql.postgresql_db:
name: "{{ koji_db_name }}"
state: absent
become: true
become_user: postgres
- name: Drop Koji database user
community.postgresql.postgresql_user:
name: "{{ koji_db_user }}"
state: absent
become: true
become_user: postgres
- name: Create Koji database user
community.postgresql.postgresql_user:
name: "{{ koji_db_user }}"
password: "{{ koji_db_password }}"
become: true
become_user: postgres
- name: Create Koji database
community.postgresql.postgresql_db:
name: "{{ koji_db_name }}"
owner: "{{ koji_db_user }}"
become: true
become_user: postgres

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- roles/postgresql

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# vars file for roles/postgresql