From cb8e7be7884f44915618247bdde85cc6e0a78f19 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 26 2021 12:42:48 +0000 Subject: [PATCH 1/10] koji-builder role refactor --- diff --git a/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml b/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml index 4e22508..097a778 100644 --- a/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml +++ b/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml @@ -2,19 +2,17 @@ apiVersion: buildsys.apps.fedoraproject.org/v1alpha1 kind: KojiBuilder metadata: name: sample + annotations: + buildsys.apps.fedoraproject.org/hub: sample/default # $NAME/$NAMESPACE spec: image: quay.io/fedora/koji-builder:f34 type: repo - replicas: 1 - configmap: koji-builder-configmap - cacert_secret: koji-hub-ca-cert - client_cert_secret: koji-builder-client-cert - koji_hub_user: 'koji-builder.mbox.dev' - koji_hub_host: 'koji-hub' - koji_hub_port: 8443 max_jobs: 5 host_archs: + - noarch - x86_64 - host_name: mbbox.default + host_channels: + - default + - createrepo ssl_verify: false - shared_pvc: koji-hub-mnt-pvc + volume: true diff --git a/operator/config/samples/buildsys_v1alpha1_kojihub.yaml b/operator/config/samples/buildsys_v1alpha1_kojihub.yaml index 79bb69e..eca53e0 100644 --- a/operator/config/samples/buildsys_v1alpha1_kojihub.yaml +++ b/operator/config/samples/buildsys_v1alpha1_kojihub.yaml @@ -26,3 +26,4 @@ spec: web_client_username: kojiweb admin_client_cert: koji-hub-admin-cert admin_username: kojiadmin + svc_name: koji-hub diff --git a/operator/molecule/default/tasks/kojibuilder_test.yml b/operator/molecule/default/tasks/kojibuilder_test.yml index 6f2566e..15a6338 100644 --- a/operator/molecule/default/tasks/kojibuilder_test.yml +++ b/operator/molecule/default/tasks/kojibuilder_test.yml @@ -3,7 +3,23 @@ k8s: state: present namespace: '{{ namespace }}' - definition: "{{ lookup('template', '/'.join([samples_dir, cr_file])) | from_yaml }}" + definition: + apiVersion: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder + metadata: + name: sample + annotations: + buildsys.apps.fedoraproject.org/hub: sample/osdk-test + spec: + image: quay.io/fedora/koji-builder:f34 + type: repo + max_jobs: 5 + host_archs: + - x86_64 + host_channels: + - createrepo + ssl_verify: false + volume: true wait: yes wait_timeout: 300 wait_condition: @@ -19,7 +35,7 @@ api_version: v1 kind: ConfigMap namespace: "{{ namespace }}" - name: koji-builder-configmap + name: kojid-sample-conf register: koji_configmap - assert: that: @@ -33,7 +49,8 @@ api_version: v1 kind: Secret namespace: "{{ namespace }}" - name: koji-builder-client-cert + # name: koji-builder-client-cert + name: kojid-sample-client-cert register: kojibuilder_client_secrets - assert: that: diff --git a/operator/roles/koji-builder/defaults/main.yml b/operator/roles/koji-builder/defaults/main.yml index 2c75626..bb55399 100644 --- a/operator/roles/koji-builder/defaults/main.yml +++ b/operator/roles/koji-builder/defaults/main.yml @@ -1,24 +1,13 @@ --- # defaults file for koji-builder koji_builder_image: "{{ image|default('quay.io/fedora/koji-builder:latest') }}" -koji_builder_replicas: "{{ replicas|default(1) }}" -koji_builder_configmap: "{{ configmap|default('koji-builder-configmap') }}" -koji_builder_cacert_secret: "{{ cacert_secret|default('koji-builder-ca-cert') }}" -koji_builder_client_cert_secret: "{{ client_cert_secret|default('koji-builder-client-cert') }}" -koji_builder_hub_user: "{{ koji_hub_user|default('koji-builder.mbox.dev') }}" - -koji_builder_koji_hub_host: "{{ koji_hub_host|default('koji-hub') }}" -koji_builder_koji_hub_port: "{{ koji_hub_port|default(8443) }}" koji_builder_maxjobs: "{{ max_jobs|default(5) }}" -koji_builder_vendor: "{{ vendor|default('MBox') }}" - -koji_builder_admin_secret: "{{ admin_secret | default('koji-hub-admin-cert') }}" +koji_builder_vendor: "{{ vendor|default('Fedora') }}" koji_builder_host_archs: "{{ host_archs | default(['x86_64']) }}" koji_builder_host_channels: "{{ host_channels | default(['default', 'createrepo']) }}" -koji_builder_host_name: "{{ host_name | default('koji-hub:8443') }}" koji_builder_ssl_verify: "{{ ssl_verify | default(true) }}" -koji_builder_shared_pvc: "{{ shared_pvc | default('koji-hub-mnt-pvc') }}" +koji_builder_volume: "{{ volume | default(true) | bool }}" koji_builder_type: "{{ type | default('repo') }}" diff --git a/operator/roles/koji-builder/tasks/builders/repo.yml b/operator/roles/koji-builder/tasks/builders/repo.yml index d6dcd08..e9e6dbc 100644 --- a/operator/roles/koji-builder/tasks/builders/repo.yml +++ b/operator/roles/koji-builder/tasks/builders/repo.yml @@ -1,49 +1,39 @@ --- -- name: Retrieve CA secret +- name: Retrieve the full KojiBuilder object k8s_info: - api_version: v1 - kind: Secret - name: "{{ koji_builder_cacert_secret }}" + api_version: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder namespace: "{{ meta.namespace }}" - register: k8s_secrets + name: "{{ meta.name }}" + register: koji_builder_k8s -- name: Fail if CA secret is not found +- name: Fail if KojiBuilder resource couldn't be found fail: - msg: "Secret {{ koji_builder_cacert_secret }} not found." - when: k8s_secrets.resources|length == 0 + msg: "Failed to fetch kojibuilder {{ meta.name }} " + when: koji_builder_k8s.resources | length == 0 -- name: Copy CA certificate to temporary folder - copy: - content: "{{ k8s_secrets.resources[0].data.cert | b64decode }}" - dest: "{{ koji_dir_path }}/ca.pem" +- name: Set the koji_user_obj variable + set_fact: + koji_builder_obj: "{{ koji_builder_k8s.resources[0] }}" -- block: - - name: Download admin client certificate - k8s_info: - api_version: v1 - kind: Secret - namespace: "{{ meta.namespace }}" - name: "{{ koji_builder_admin_secret }}" - register: k8s_res - - fail: - msg: "Secret not found: {{ koji_builder_admin_secret }}" - when: k8s_res.resources|length == 0 - - set_fact: - koji_admin_secret: "{{ k8s_res.resources[0] | from_yaml }}" - - copy: - content: "{{ koji_admin_secret.data['client.pem'] | b64decode }}" - dest: "{{ koji_dir_path }}/admin.pem" +- name: Get the annotation value from the retrieved KojiBuilder resource + set_fact: + koji_builder_hub: "{{ koji_builder_obj.metadata.annotations['buildsys.apps.fedoraproject.org/hub'].split('/') }}" -- koji_host: - server: "{{ koji_builder_koji_hub_url }}/kojihub" - host: "{{ meta.name }}" - archs: "{{ koji_builder_host_archs }}" - channels: [ "createrepo" ] - ssl_auth: - cert: "{{ koji_dir_path }}/admin.pem" - serverca: "{{ koji_dir_path }}/ca.pem" - verify: "{{ koji_builder_ssl_verify }}" +- name: Set variables for both hub name and namespace + set_fact: + koji_builder_hub_name: "{{ koji_builder_hub.0 }}" + koji_builder_hub_namespace: "{{ koji_builder_hub.1 }}" +- name: Enable the builder + ktdreyer.koji_ansible.koji_host: + name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + arches: "{{ koji_builder_host_archs }}" + state: enabled + channels: + - createrepo + koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" + - block: - name: Apply koji-builder deployment template: diff --git a/operator/roles/koji-builder/tasks/cert.yml b/operator/roles/koji-builder/tasks/cert.yml deleted file mode 100644 index e009871..0000000 --- a/operator/roles/koji-builder/tasks/cert.yml +++ /dev/null @@ -1,8 +0,0 @@ -- koji_client_cert: - k8s_ca: "{{ meta.namespace }}/{{ koji_builder_cacert_secret }}" - k8s_cert: "{{ meta.namespace }}/{{ koji_builder_client_cert_secret }}" - k8s_meta: - labels: - app: koji-builder - username: "{{ meta.name }}" - force: false diff --git a/operator/roles/koji-builder/tasks/main.yml b/operator/roles/koji-builder/tasks/main.yml index f7ee336..9056b89 100644 --- a/operator/roles/koji-builder/tasks/main.yml +++ b/operator/roles/koji-builder/tasks/main.yml @@ -6,11 +6,30 @@ suffix: koji register: koji_dir -- set_fact: - koji_builder_koji_hub_url: "https://{{ koji_builder_koji_hub_host }}.{{ meta.namespace }}.svc:{{ koji_builder_koji_hub_port }}" +- koji_hub_info: + hub: "sample/osdk-test" + register: koji_builder_hub_info + +- name: Hub vars setup + set_fact: + koji_builder_koji_hub_url: "https://{{ koji_builder_hub_info['result']['svc'] }}" + koji_builder_cacert_secret: "{{ koji_builder_hub_info['result']['hub']['spec']['ca_cert_secret'] }}" koji_dir_path: "{{ koji_dir.path }}" + koji_builder_configmap: "kojid-{{ meta.name }}-conf" + koji_builder_client_cert_secret: "kojid-{{ meta.name }}-client-cert" + koji_builder_replicas: 1 + koji_builder_shared_pvc: "{{ koji_builder_hub_info['result']['hub']['spec']['mnt_pvc_name'] }}" + -- include_tasks: cert.yml +- name: Create koji-builder client certificate + koji_client_cert: + k8s_ca: "{{ meta.namespace }}/{{ koji_builder_hub_info['result']['hub']['spec']['ca_cert_secret'] }}" + k8s_cert: "{{ meta.namespace }}/{{ koji_builder_client_cert_secret }}" + k8s_meta: + labels: + app: koji-builder + username: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + force: false - block: - name: Ensure koji-builder configmap is updated diff --git a/operator/roles/koji-builder/templates/deployment.yml.j2 b/operator/roles/koji-builder/templates/deployment.yml.j2 index 7290867..9d61c62 100644 --- a/operator/roles/koji-builder/templates/deployment.yml.j2 +++ b/operator/roles/koji-builder/templates/deployment.yml.j2 @@ -1,7 +1,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: "{{ meta.name }}" + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" labels: app: koji-builder spec: @@ -35,8 +35,10 @@ spec: - name: client-cert-volume mountPath: /etc/certs/client readOnly: true +{% if koji_builder_volume %} - name: koji-builder-mnt mountPath: /mnt/koji +{% endif %} volumes: - name: config-volume configMap: @@ -47,6 +49,8 @@ spec: - name: client-cert-volume secret: secretName: "{{ koji_builder_client_cert_secret }}" +{% if koji_builder_volume %} - name: koji-builder-mnt persistentVolumeClaim: claimName: "{{ koji_builder_shared_pvc }}" +{% endif %} From d33752dcc1077e9803b9998f251d5e079e55ebb7 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 26 2021 12:43:44 +0000 Subject: [PATCH 2/10] koji-lib changes and koji_hub_fetch module --- diff --git a/operator/roles/koji-lib/action_plugins/koji_hub_info.py b/operator/roles/koji-lib/action_plugins/koji_hub_info.py new file mode 100644 index 0000000..ef499f0 --- /dev/null +++ b/operator/roles/koji-lib/action_plugins/koji_hub_info.py @@ -0,0 +1,113 @@ +from ansible.plugins.action import ActionBase + +class ActionModule(ActionBase): + + def _run_setup(self, task_vars=None): + """Runs the setup module""" + self._execute_module( + 'setup', + module_args=dict( + gather_subset='all', + gather_timeout=10 + ), + task_vars=task_vars + ) + + def _read_k8s_kojihub(self, name, namespace, task_vars=None): + """runs the k8s module to read a KojiHub resource""" + vg = 'buildsys.apps.fedoraproject.org/v1alpha1' + kind = 'KojiHub' + + res = self._execute_module( + 'kubernetes.core.k8s', + module_args=dict( + api_version=vg, + kind=kind, + namespace=namespace, + name=name), + task_vars=task_vars) + + if res.get('failed'): + return None + + if len(res.get('result', {}).get('spec', {})) == 0: + return None + + return res.get('result') + + def _read_hub_svc(self, name, namespace, task_vars=None): + """runs the k8s module to read a Service resource""" + res = self._execute_module( + 'kubernetes.core.k8s', + module_args=dict( + api_version='v1', + kind='Service', + namespace=namespace, + name=name), + task_vars=task_vars) + + if res.get('failed'): + return None + + if len(res.get('result', {}).get('spec', {})) == 0: + return None + + res = res.get('result') + if not res: + return None + + try: + ports = res.get('spec', {}).get('ports', []) + https_port = [p for p in ports if p.get('name') == 'https'][0]['port'] + except IndexError: + return None + + return f'{name}.{namespace}.svc.cluster.local:{https_port}' + + + def run(self, tmp=None, task_vars=None): + super(ActionModule, self).run(tmp, task_vars) + + # run setup module so facts are gathered + self._run_setup(task_vars) + + output = { + 'failed': False, + 'changed': False, + 'skipped': False, + 'msg': '', + 'result': {} + } + + # plugin params + module_args = self._task.args.copy() + param_hub = module_args.get('hub', '') + + try: + name, namespace = param_hub.split('/') + except ValueError: + output['failed'] = True + output['msg'] = f'Failed to parse hub reference: {param_hub}' + return output + + hub = self._read_k8s_kojihub(name, namespace, task_vars=task_vars) + if hub is None: + output['failed'] = True + output['message'] = f'Failed to read hub info: {param_hub}' + return output + + svc_name = hub['spec']['svc_name'] + svc = self._read_hub_svc(svc_name, namespace, task_vars=task_vars) + if svc is None: + output['failed'] = True + output['message'] = f'Failed to read svc info: {svc_name}' + return output + + output['changed'] = True + output['msg'] = 'KojiHub info retrieved' + output['result'] = { + 'hub': hub, + 'svc': svc + } + + return output diff --git a/operator/roles/koji-lib/library/koji_host.py b/operator/roles/koji-lib/library/koji_host.py deleted file mode 100644 index 07d77b2..0000000 --- a/operator/roles/koji-lib/library/koji_host.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python - -# This file is part of the mbbox project. -# Copyright (C) 2020 Red Hat, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -DOCUMENTATION = ''' ---- -module: koji_host - -short_description: Ansible module that ensures a koji host state in a remote koji-hub instance. - -description: - - This module ensures that a koji host is added in koji - - It requires a running koji-hub instance - -options: - host: - description: - - a qualified and unique koji hostname - required: true - archs: - description: - - a list of valid koji host architectures - default: [x86_64] - server: - description: - - the full koji-hub server url - required: true - state: - description: - - the koji desired state - default: present - choices: present, absent - ssl_auth: - description: - - a dictonary which contains the require ssl authentication info - ssl_auth.cert: - description: - - the client pem file path to use, this file must contain both key and certificate in PEM format - ssl_auth.serverca: - description: - - the certificate authority PEM file path used by both koji-hub server and koji-builder client pem file - ssl_auth.verify: - description: - - A boolean flag to tell koji-builder to validate the client pem file, should be set to false if using self-signed certificates. - default: true - -author: - - Red Hat, Inc. and others -''' - -EXAMPLES = ''' -- koji_host: - server: https://koji-hub:8443/kojihub - host: myhost - archs: [x86_64] - channels: [default, createrepo] - ssl_auth: - cert: /tmp/admin.pem - serverca:/tmp/ca.pem - verify: false -''' - -from optparse import Values - -from ansible.module_utils.basic import AnsibleModule -import koji -from koji_cli.lib import activate_session - - -def build(): - """ - Builds an AnsibleModule object instance - """ - spec = dict( - host=dict(type='str', required=True), - archs=dict(type='list', default=['x86_64']), - server=dict(type='str', required=True), - state=dict(type='str', default='present', choices=['present', 'absent']), - channels=dict(type='list'), - ssl_auth=dict(type='dict') - ) - return AnsibleModule( - argument_spec=spec, - supports_check_mode=True - ) - - -def ssl_config(module): - """ - Creates a ssl config dictionary to be used for ssl auth. - """ - ctx = module.params['ssl_auth'] - try: - return { - 'cert': ctx['cert'], - 'serverca': ctx['serverca'], - 'no_ssl_verify': ctx.get('verify', True), - 'authtype': 'ssl' - } - except KeyError as e: - module.fail_json(changed=False, - skipped=False, - failed=True, - error='Missing ssl_auth "%s" key.' % e.args[0]) - - -def main(): - """ - Main funtion that runs the module. - """ - module = build() - config = {'server': module.params['server']} - - archs = module.params['archs'] - channels = module.params['channels'] - host_name = module.params['host'] - - if 'ssl_auth' in module.params: - config.update(**ssl_config(module)) - else: - module.fail_json(changed=False, - skipped=False, - failed=True, - error='Missing authentication config') - - options = Values(config) - session_opts = koji.grab_session_options(options) - session = koji.ClientSession(options.server, session_opts) - - try: - session.ssl_login(options.cert, None, options.serverca) - except Exception as e: - module.fail_json(changed=False, - skipped=False, - failed=True, - error=str(e)) - - if not session.getHost(host_name): - try: - session.addHost(host_name, archs) - except Exception as e: - module.fail_json(changed=False, - skipped=False, - failed=True, - msg=str(e)) - - channel_errs = [] - added_channels = [] - for channel in channels: - try: - session.addHostToChannel(host_name, channel, create=True) - added_channels.append(channel) - except Exception as e: - if not str(e).endswith('is already subscribed to the %s channel' % channel): - channel_errs.append(str(e)) - - if len(channel_errs) > 0: - module.fail_json(changed=False, - skipped=False, - failed=True, - msg=dir(channel_errs[0]), - error='Add Channel Error: ' + str(channel_errs)) - - module.exit_json(changed=True, - skipped=False, - failed=False, result={'name': host_name, 'archs': archs, 'channels': added_channels}) - - -if __name__ == '__main__': - main() diff --git a/operator/roles/koji-lib/tests/main.yaml b/operator/roles/koji-lib/tests/main.yaml index 77f0a4d..5bcc198 100644 --- a/operator/roles/koji-lib/tests/main.yaml +++ b/operator/roles/koji-lib/tests/main.yaml @@ -59,3 +59,7 @@ username: builder force: false state: present + + - name: Retrieve koji info + koji_hub_info: + hub: sample/default From 8696e0067a173945eadd4f1b256aa55b0d68d8f5 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 26 2021 15:37:20 +0000 Subject: [PATCH 3/10] more koji-builder refactor --- diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt.yml b/operator/roles/koji-builder/tasks/builders/kubevirt.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/kubevirt.yml @@ -0,0 +1 @@ +--- diff --git a/operator/roles/koji-builder/tasks/builders/repo.yml b/operator/roles/koji-builder/tasks/builders/repo.yml index e9e6dbc..064572a 100644 --- a/operator/roles/koji-builder/tasks/builders/repo.yml +++ b/operator/roles/koji-builder/tasks/builders/repo.yml @@ -1,30 +1,4 @@ ---- -- name: Retrieve the full KojiBuilder object - k8s_info: - api_version: buildsys.apps.fedoraproject.org/v1alpha1 - kind: KojiBuilder - namespace: "{{ meta.namespace }}" - name: "{{ meta.name }}" - register: koji_builder_k8s - -- name: Fail if KojiBuilder resource couldn't be found - fail: - msg: "Failed to fetch kojibuilder {{ meta.name }} " - when: koji_builder_k8s.resources | length == 0 - -- name: Set the koji_user_obj variable - set_fact: - koji_builder_obj: "{{ koji_builder_k8s.resources[0] }}" - -- name: Get the annotation value from the retrieved KojiBuilder resource - set_fact: - koji_builder_hub: "{{ koji_builder_obj.metadata.annotations['buildsys.apps.fedoraproject.org/hub'].split('/') }}" - -- name: Set variables for both hub name and namespace - set_fact: - koji_builder_hub_name: "{{ koji_builder_hub.0 }}" - koji_builder_hub_namespace: "{{ koji_builder_hub.1 }}" - +--- - name: Enable the builder ktdreyer.koji_ansible.koji_host: name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" diff --git a/operator/roles/koji-builder/tasks/main.yml b/operator/roles/koji-builder/tasks/main.yml index 9056b89..01f015c 100644 --- a/operator/roles/koji-builder/tasks/main.yml +++ b/operator/roles/koji-builder/tasks/main.yml @@ -6,11 +6,24 @@ suffix: koji register: koji_dir +- name: Retrieve the full KojiBuilder object + k8s_info: + api_version: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder + namespace: "{{ meta.namespace }}" + name: "{{ meta.name }}" + register: koji_builder_k8s + +- name: Fail if KojiBuilder resource couldn't be found + fail: + msg: "Failed to fetch kojibuilder {{ meta.name }} " + when: koji_builder_k8s.resources | length == 0 + - koji_hub_info: hub: "sample/osdk-test" register: koji_builder_hub_info -- name: Hub vars setup +- name: Play variables setup set_fact: koji_builder_koji_hub_url: "https://{{ koji_builder_hub_info['result']['svc'] }}" koji_builder_cacert_secret: "{{ koji_builder_hub_info['result']['hub']['spec']['ca_cert_secret'] }}" @@ -19,8 +32,17 @@ koji_builder_client_cert_secret: "kojid-{{ meta.name }}-client-cert" koji_builder_replicas: 1 koji_builder_shared_pvc: "{{ koji_builder_hub_info['result']['hub']['spec']['mnt_pvc_name'] }}" + koji_builder_obj: "{{ koji_builder_k8s.resources[0] }}" +- name: Get the annotation value from the retrieved KojiBuilder resource + set_fact: + koji_builder_hub: "{{ koji_builder_obj.metadata.annotations['buildsys.apps.fedoraproject.org/hub'].split('/') }}" +- name: Set variables for both hub name and namespace + set_fact: + koji_builder_hub_name: "{{ koji_builder_hub.0 }}" + koji_builder_hub_namespace: "{{ koji_builder_hub.1 }}" + - name: Create koji-builder client certificate koji_client_cert: k8s_ca: "{{ meta.namespace }}/{{ koji_builder_hub_info['result']['hub']['spec']['ca_cert_secret'] }}" @@ -45,6 +67,9 @@ - include_tasks: builders/repo.yml when: "koji_builder_type == 'repo'" +- include_tasks: builders/kubevirt.yml + when: "koji_builder_type == 'kubevirt'" + - name: Remove temporary koji directory file: path: "{{ koji_dir_path }}" From 268489af6ffc646eb5e0049c5b8a25d203b6e7c8 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 27 2021 11:11:37 +0000 Subject: [PATCH 4/10] removing default.keep folder --- diff --git a/operator/molecule/default.keep/converge.yml b/operator/molecule/default.keep/converge.yml deleted file mode 100644 index 0633db9..0000000 --- a/operator/molecule/default.keep/converge.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- name: Converge - hosts: localhost - connection: local - gather_facts: no - collections: - - community.kubernetes - - tasks: - - name: Create Namespace - k8s: - api_version: v1 - kind: Namespace - name: '{{ namespace }}' - - - import_tasks: kustomize.yml - vars: - state: present diff --git a/operator/molecule/default.keep/create.yml b/operator/molecule/default.keep/create.yml deleted file mode 100644 index 1eeaf92..0000000 --- a/operator/molecule/default.keep/create.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Create - hosts: localhost - connection: local - gather_facts: false - tasks: [] diff --git a/operator/molecule/default.keep/destroy.yml b/operator/molecule/default.keep/destroy.yml deleted file mode 100644 index af55e4f..0000000 --- a/operator/molecule/default.keep/destroy.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -- name: Destroy - hosts: localhost - connection: local - gather_facts: false - collections: - - community.kubernetes - - tasks: - - import_tasks: kustomize.yml - vars: - state: absent - - - name: Destroy Namespace - k8s: - api_version: v1 - kind: Namespace - name: '{{ namespace }}' - state: absent - - - name: Unset pull policy - command: '{{ kustomize }} edit remove patch pull_policy/{{ operator_pull_policy }}.yaml' - args: - chdir: '{{ config_dir }}/testing' diff --git a/operator/molecule/default.keep/kustomize.yml b/operator/molecule/default.keep/kustomize.yml deleted file mode 100644 index d5e0650..0000000 --- a/operator/molecule/default.keep/kustomize.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -- name: Build kustomize testing overlay - # load_restrictor must be set to none so we can load patch files from the default overlay - # updated to use "--load-restrictor LoadRestrictionsNone" for kustomize 4+ - command: '{{ kustomize }} build --load-restrictor LoadRestrictionsNone .' - args: - chdir: '{{ config_dir }}/testing' - register: resources - changed_when: false - -- name: Set resources to {{ state }} - k8s: - definition: '{{ item }}' - state: '{{ state }}' - wait: yes - loop: '{{ resources.stdout | from_yaml_all | list }}' diff --git a/operator/molecule/default.keep/molecule.yml b/operator/molecule/default.keep/molecule.yml deleted file mode 100644 index ea58004..0000000 --- a/operator/molecule/default.keep/molecule.yml +++ /dev/null @@ -1,36 +0,0 @@ ---- -dependency: - name: galaxy -driver: - name: delegated -lint: | - set -e - yamllint -d "{extends: relaxed, rules: {line-length: {max: 120}}}" . -platforms: - - name: cluster - groups: - - k8s -provisioner: - name: ansible - lint: | - set -e - ansible-lint - inventory: - group_vars: - all: - namespace: ${TEST_OPERATOR_NAMESPACE:-osdk-test} - host_vars: - localhost: - ansible_python_interpreter: '{{ ansible_playbook_python }}' - config_dir: ${MOLECULE_PROJECT_DIRECTORY}/config - samples_dir: ${MOLECULE_PROJECT_DIRECTORY}/config/samples - operator_image: ${OPERATOR_IMAGE:-""} - operator_pull_policy: ${OPERATOR_PULL_POLICY:-"Always"} - kustomize: ${KUSTOMIZE_PATH:-kustomize} - env: - K8S_AUTH_KUBECONFIG: ${KUBECONFIG:-"~/.kube/config"} -verifier: - name: ansible - lint: | - set -e - ansible-lint diff --git a/operator/molecule/default.keep/prepare.yml b/operator/molecule/default.keep/prepare.yml deleted file mode 100644 index 7d9f3f1..0000000 --- a/operator/molecule/default.keep/prepare.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -- name: Prepare - hosts: localhost - connection: local - gather_facts: false - - tasks: - - name: Ensure operator image is set - fail: - msg: | - You must specify the OPERATOR_IMAGE environment variable in order to run the - 'default' scenario - when: not operator_image - - - name: Set testing image - command: '{{ kustomize }} edit set image testing={{ operator_image }}' - args: - chdir: '{{ config_dir }}/testing' - - - name: Set pull policy - command: '{{ kustomize }} edit add patch pull_policy/{{ operator_pull_policy }}.yaml' - args: - chdir: '{{ config_dir }}/testing' - - - name: Set testing namespace - command: '{{ kustomize }} edit set namespace {{ namespace }}' - args: - chdir: '{{ config_dir }}/testing' diff --git a/operator/molecule/default.keep/tasks/kojibuilder_test.yml b/operator/molecule/default.keep/tasks/kojibuilder_test.yml deleted file mode 100644 index ccf78e7..0000000 --- a/operator/molecule/default.keep/tasks/kojibuilder_test.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -- name: Create the buildsys.apps.fedoraproject.org/v1alpha1.KojiBuilder - k8s: - state: present - namespace: '{{ namespace }}' - definition: "{{ lookup('template', '/'.join([samples_dir, cr_file])) | from_yaml }}" - wait: yes - wait_timeout: 300 - wait_condition: - type: Running - reason: Successful - status: "True" - vars: - cr_file: 'buildsys_v1alpha1_kojibuilder.yaml' - -- name: Add assertions here - assert: - that: false - fail_msg: FIXME Add real assertions for your operator diff --git a/operator/molecule/default.keep/tasks/kojihub_test.yml b/operator/molecule/default.keep/tasks/kojihub_test.yml deleted file mode 100644 index 5ecaaca..0000000 --- a/operator/molecule/default.keep/tasks/kojihub_test.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -- name: Create the buildsys.apps.fedoraproject.org/v1alpha1.KojiHub - k8s: - state: present - namespace: '{{ namespace }}' - definition: "{{ lookup('template', '/'.join([samples_dir, cr_file])) | from_yaml }}" - wait: yes - wait_timeout: 300 - wait_condition: - type: Running - reason: Successful - status: "True" - vars: - cr_file: 'buildsys_v1alpha1_kojihub.yaml' - -- name: Add assertions here - assert: - that: false - fail_msg: FIXME Add real assertions for your operator diff --git a/operator/molecule/default.keep/tasks/kojira_test.yml b/operator/molecule/default.keep/tasks/kojira_test.yml deleted file mode 100644 index 0e4ff4f..0000000 --- a/operator/molecule/default.keep/tasks/kojira_test.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -- name: Create the buildsys.apps.fedoraproject.org/v1alpha1.Kojira - k8s: - state: present - namespace: '{{ namespace }}' - definition: "{{ lookup('template', '/'.join([samples_dir, cr_file])) | from_yaml }}" - wait: yes - wait_timeout: 300 - wait_condition: - type: Running - reason: Successful - status: "True" - vars: - cr_file: 'buildsys_v1alpha1_kojira.yaml' - -- name: Add assertions here - assert: - that: false - fail_msg: FIXME Add real assertions for your operator diff --git a/operator/molecule/default.keep/verify.yml b/operator/molecule/default.keep/verify.yml deleted file mode 100644 index cc28aac..0000000 --- a/operator/molecule/default.keep/verify.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- -- name: Verify - hosts: localhost - connection: local - gather_facts: no - collections: - - community.kubernetes - - vars: - ctrl_label: control-plane=controller-manager - - tasks: - - block: - - name: Import all test files from tasks/ - include_tasks: '{{ item }}' - with_fileglob: - - tasks/*_test.yml - rescue: - - name: Retrieve relevant resources - k8s_info: - api_version: '{{ item.api_version }}' - kind: '{{ item.kind }}' - namespace: '{{ namespace }}' - loop: - - api_version: v1 - kind: Pod - - api_version: apps/v1 - kind: Deployment - - api_version: v1 - kind: Secret - - api_version: v1 - kind: ConfigMap - register: debug_resources - - - name: Retrieve Pod logs - k8s_log: - name: '{{ item.metadata.name }}' - namespace: '{{ namespace }}' - container: manager - loop: "{{ q('k8s', api_version='v1', kind='Pod', namespace=namespace, label_selector=ctrl_label) }}" - register: debug_logs - - - name: Output gathered resources - debug: - var: debug_resources - - - name: Output gathered logs - debug: - var: item.log_lines - loop: '{{ debug_logs.results }}' - - - name: Re-emit failure - vars: - failed_task: - result: '{{ ansible_failed_result }}' - fail: - msg: '{{ failed_task }}' From a3221db2f933986a0b9d94831f978993baf1dee0 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 27 2021 11:32:51 +0000 Subject: [PATCH 5/10] host_varname becomes varname --- diff --git a/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml b/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml index 097a778..25c76da 100644 --- a/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml +++ b/operator/config/samples/buildsys_v1alpha1_kojibuilder.yaml @@ -8,10 +8,10 @@ spec: image: quay.io/fedora/koji-builder:f34 type: repo max_jobs: 5 - host_archs: + archs: - noarch - x86_64 - host_channels: + channels: - default - createrepo ssl_verify: false diff --git a/operator/molecule/default/tasks/kojibuilder_test.yml b/operator/molecule/default/tasks/kojibuilder_test.yml index 15a6338..2a14bc6 100644 --- a/operator/molecule/default/tasks/kojibuilder_test.yml +++ b/operator/molecule/default/tasks/kojibuilder_test.yml @@ -14,9 +14,9 @@ image: quay.io/fedora/koji-builder:f34 type: repo max_jobs: 5 - host_archs: + archs: - x86_64 - host_channels: + channels: - createrepo ssl_verify: false volume: true diff --git a/operator/roles/koji-builder/defaults/main.yml b/operator/roles/koji-builder/defaults/main.yml index bb55399..e31eae5 100644 --- a/operator/roles/koji-builder/defaults/main.yml +++ b/operator/roles/koji-builder/defaults/main.yml @@ -5,8 +5,8 @@ koji_builder_image: "{{ image|default('quay.io/fedora/koji-builder:latest') }}" koji_builder_maxjobs: "{{ max_jobs|default(5) }}" koji_builder_vendor: "{{ vendor|default('Fedora') }}" -koji_builder_host_archs: "{{ host_archs | default(['x86_64']) }}" -koji_builder_host_channels: "{{ host_channels | default(['default', 'createrepo']) }}" +koji_builder_archs: "{{ archs | default(['x86_64']) }}" +koji_builder_channels: "{{ channels | default(['default', 'createrepo']) }}" koji_builder_ssl_verify: "{{ ssl_verify | default(true) }}" koji_builder_volume: "{{ volume | default(true) | bool }}" diff --git a/operator/roles/koji-builder/tasks/builders/repo.yml b/operator/roles/koji-builder/tasks/builders/repo.yml index 064572a..60d4c56 100644 --- a/operator/roles/koji-builder/tasks/builders/repo.yml +++ b/operator/roles/koji-builder/tasks/builders/repo.yml @@ -2,7 +2,7 @@ - name: Enable the builder ktdreyer.koji_ansible.koji_host: name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" - arches: "{{ koji_builder_host_archs }}" + arches: "{{ koji_builder_archs }}" state: enabled channels: - createrepo From 2f247134d0188f2ad0a1f1fecb30225985783df4 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 27 2021 18:31:42 +0000 Subject: [PATCH 6/10] structure change --- diff --git a/operator/roles/koji-builder/tasks/builders/repo.yml b/operator/roles/koji-builder/tasks/builders/repo.yml deleted file mode 100644 index 60d4c56..0000000 --- a/operator/roles/koji-builder/tasks/builders/repo.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- name: Enable the builder - ktdreyer.koji_ansible.koji_host: - name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" - arches: "{{ koji_builder_archs }}" - state: enabled - channels: - - createrepo - koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" - -- block: - - name: Apply koji-builder deployment - template: - src: deployment.yml.j2 - dest: "{{ koji_dir_path}}/deployment.yml" - - k8s: - state: present - src: "{{ koji_dir_path}}/deployment.yml" - wait: true - namespace: "{{ meta.namespace }}" diff --git a/operator/roles/koji-builder/tasks/builders/repo/create.yml b/operator/roles/koji-builder/tasks/builders/repo/create.yml new file mode 100644 index 0000000..60d4c56 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/repo/create.yml @@ -0,0 +1,20 @@ +--- +- name: Enable the builder + ktdreyer.koji_ansible.koji_host: + name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + arches: "{{ koji_builder_archs }}" + state: enabled + channels: + - createrepo + koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" + +- block: + - name: Apply koji-builder deployment + template: + src: deployment.yml.j2 + dest: "{{ koji_dir_path}}/deployment.yml" + - k8s: + state: present + src: "{{ koji_dir_path}}/deployment.yml" + wait: true + namespace: "{{ meta.namespace }}" diff --git a/operator/roles/koji-builder/tasks/builders/repo/destroy.yml b/operator/roles/koji-builder/tasks/builders/repo/destroy.yml new file mode 100644 index 0000000..4b2a025 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/repo/destroy.yml @@ -0,0 +1,23 @@ +--- +- name: Disable the builder + ktdreyer.koji_ansible.koji_host: + name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + arches: "{{ koji_builder_archs }}" + state: disabled + channels: + - createrepo + koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" + +- block: + - name: Delete koji-builder deployment + template: + src: deployment.yml.j2 + dest: "{{ koji_dir_path}}/deployment.yml" + - k8s: + defintion: + api_version: v1 + kind: Deployment + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + state: absent + wait: true diff --git a/operator/roles/koji-builder/tasks/builders/repo/main.yml b/operator/roles/koji-builder/tasks/builders/repo/main.yml new file mode 100644 index 0000000..3a87fec --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/repo/main.yml @@ -0,0 +1,8 @@ +--- +- include_tasks: create.yml + when: state is not defined + +- include_tasks: destroy.yml + when: + - state is defined + - state == 'absent' diff --git a/operator/roles/koji-builder/tasks/main.yml b/operator/roles/koji-builder/tasks/main.yml index 01f015c..b89c9eb 100644 --- a/operator/roles/koji-builder/tasks/main.yml +++ b/operator/roles/koji-builder/tasks/main.yml @@ -64,10 +64,16 @@ wait: true namespace: "{{ meta.namespace }}" -- include_tasks: builders/repo.yml +- fail: + msg: "Invalid KojiBuilder type: {{ koji_builder_type }}" + when: + - "koji_builder_type != 'repo'" + - "koji_builder_type != 'kubevirt'" + +- include_tasks: builders/repo/main.yml when: "koji_builder_type == 'repo'" -- include_tasks: builders/kubevirt.yml +- include_tasks: builders/kubevirt/main.yml when: "koji_builder_type == 'kubevirt'" - name: Remove temporary koji directory From e62a2d3bc87dd7919c5bf3157414b2625e71be9f Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 27 2021 18:32:06 +0000 Subject: [PATCH 7/10] koji-builder finalizer for deletion --- diff --git a/operator/watches.yaml b/operator/watches.yaml index 78306d2..740f5c7 100644 --- a/operator/watches.yaml +++ b/operator/watches.yaml @@ -13,6 +13,10 @@ role: koji-builder vars: meta: '{{ ansible_operator_meta }}' + finalizer: + name: buildsys.apps.fedoraproject.org/finalizer + vars: + state: absent - version: v1alpha1 group: buildsys.apps.fedoraproject.org From 36d5f4ffaf331e92f2aa0bba5b5f403c207c119d Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 28 2021 11:53:46 +0000 Subject: [PATCH 8/10] repo builder changes --- diff --git a/operator/roles/koji-builder/tasks/builders/repo/create.yml b/operator/roles/koji-builder/tasks/builders/repo/create.yml index 60d4c56..7334c30 100644 --- a/operator/roles/koji-builder/tasks/builders/repo/create.yml +++ b/operator/roles/koji-builder/tasks/builders/repo/create.yml @@ -2,7 +2,8 @@ - name: Enable the builder ktdreyer.koji_ansible.koji_host: name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" - arches: "{{ koji_builder_archs }}" + arches: + - noarch state: enabled channels: - createrepo @@ -11,7 +12,7 @@ - block: - name: Apply koji-builder deployment template: - src: deployment.yml.j2 + src: repo/deployment.yml.j2 dest: "{{ koji_dir_path}}/deployment.yml" - k8s: state: present diff --git a/operator/roles/koji-builder/tasks/builders/repo/destroy.yml b/operator/roles/koji-builder/tasks/builders/repo/destroy.yml index 4b2a025..aee315b 100644 --- a/operator/roles/koji-builder/tasks/builders/repo/destroy.yml +++ b/operator/roles/koji-builder/tasks/builders/repo/destroy.yml @@ -8,16 +8,11 @@ - createrepo koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" -- block: - - name: Delete koji-builder deployment - template: - src: deployment.yml.j2 - dest: "{{ koji_dir_path}}/deployment.yml" - - k8s: - defintion: - api_version: v1 - kind: Deployment - namespace: "{{ meta.namespace }}" - name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" - state: absent - wait: true +- name: Delete koji-builder deployment + k8s: + api_version: v1 + kind: Deployment + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + state: absent + wait: true diff --git a/operator/roles/koji-builder/templates/deployment.yml.j2 b/operator/roles/koji-builder/templates/deployment.yml.j2 deleted file mode 100644 index 9d61c62..0000000 --- a/operator/roles/koji-builder/templates/deployment.yml.j2 +++ /dev/null @@ -1,56 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" - labels: - app: koji-builder -spec: - replicas: {{ koji_builder_replicas|int }} - selector: - matchLabels: - app: koji-builder - template: - metadata: - labels: - app: koji-builder - spec: - containers: - - name: builder - image: {{ koji_builder_image }} - resources: {} - livenessProbe: - exec: - command: - - pgrep - - kojid - initialDelaySeconds: 5 - periodSeconds: 15 - volumeMounts: - - name: config-volume - mountPath: /etc/kojid - readOnly: true - - name: cacert-volume - mountPath: /etc/certs/ca - readOnly: true - - name: client-cert-volume - mountPath: /etc/certs/client - readOnly: true -{% if koji_builder_volume %} - - name: koji-builder-mnt - mountPath: /mnt/koji -{% endif %} - volumes: - - name: config-volume - configMap: - name: "{{ koji_builder_configmap }}" - - name: cacert-volume - secret: - secretName: "{{ koji_builder_cacert_secret }}" - - name: client-cert-volume - secret: - secretName: "{{ koji_builder_client_cert_secret }}" -{% if koji_builder_volume %} - - name: koji-builder-mnt - persistentVolumeClaim: - claimName: "{{ koji_builder_shared_pvc }}" -{% endif %} diff --git a/operator/roles/koji-builder/templates/repo/deployment.yml.j2 b/operator/roles/koji-builder/templates/repo/deployment.yml.j2 new file mode 100644 index 0000000..9d61c62 --- /dev/null +++ b/operator/roles/koji-builder/templates/repo/deployment.yml.j2 @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + labels: + app: koji-builder +spec: + replicas: {{ koji_builder_replicas|int }} + selector: + matchLabels: + app: koji-builder + template: + metadata: + labels: + app: koji-builder + spec: + containers: + - name: builder + image: {{ koji_builder_image }} + resources: {} + livenessProbe: + exec: + command: + - pgrep + - kojid + initialDelaySeconds: 5 + periodSeconds: 15 + volumeMounts: + - name: config-volume + mountPath: /etc/kojid + readOnly: true + - name: cacert-volume + mountPath: /etc/certs/ca + readOnly: true + - name: client-cert-volume + mountPath: /etc/certs/client + readOnly: true +{% if koji_builder_volume %} + - name: koji-builder-mnt + mountPath: /mnt/koji +{% endif %} + volumes: + - name: config-volume + configMap: + name: "{{ koji_builder_configmap }}" + - name: cacert-volume + secret: + secretName: "{{ koji_builder_cacert_secret }}" + - name: client-cert-volume + secret: + secretName: "{{ koji_builder_client_cert_secret }}" +{% if koji_builder_volume %} + - name: koji-builder-mnt + persistentVolumeClaim: + claimName: "{{ koji_builder_shared_pvc }}" +{% endif %} From 6d3109fe854dd154971642e1492b962b6a6674b3 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Oct 06 2021 14:30:07 +0000 Subject: [PATCH 9/10] kubevirt type of build --- diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index 23a2bb9..ddae2eb 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -10,12 +10,6 @@ rules: # TODO: remove openshift resources from base definition \ # and add it with kustomize whe needed. - apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - '*' - - apiGroups: - networking.k8s.io resources: - ingresses @@ -125,4 +119,21 @@ rules: - patch - update - watch + ## + ## Rules for kubevirt.io/v1alpha3, Kind: VirtualMachineInstance + ## + - apiGroups: + - kubevirt.io + resources: + - virtualmachines + - virtualmachines/status + - virtualmachines/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch #+kubebuilder:scaffold:rules diff --git a/operator/config/rbac/vmi_editor_role.yaml b/operator/config/rbac/vmi_editor_role.yaml new file mode 100644 index 0000000..a1dcb52 --- /dev/null +++ b/operator/config/rbac/vmi_editor_role.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: vmi-editor-role +rules: +- apiGroups: + - kubevirt.io/v1alpha3 + resources: + - virtualmachineinstances + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - kubevirt.io/v1alpha3 + resources: + - virtualmachineinstances/status + verbs: + - get diff --git a/operator/config/rbac/vmi_viewer_role.yaml b/operator/config/rbac/vmi_viewer_role.yaml new file mode 100644 index 0000000..e1b35fb --- /dev/null +++ b/operator/config/rbac/vmi_viewer_role.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: vmi-viewer-role +rules: +- apiGroups: + - kubevirt.io/v1alpha3 + resources: + - virtualmachineinstances + verbs: + - get + - list + - watch +- apiGroups: + - kubevirt.io/v1alpha3 + resources: + - virtualmachineinstances/status + verbs: + - get diff --git a/operator/config/samples/buildsys_v1alpha1_kojibuilder-kubevirt.yaml b/operator/config/samples/buildsys_v1alpha1_kojibuilder-kubevirt.yaml new file mode 100644 index 0000000..24631e2 --- /dev/null +++ b/operator/config/samples/buildsys_v1alpha1_kojibuilder-kubevirt.yaml @@ -0,0 +1,20 @@ +apiVersion: buildsys.apps.fedoraproject.org/v1alpha1 +kind: KojiBuilder +metadata: + name: sample + annotations: + buildsys.apps.fedoraproject.org/hub: sample/default # $NAME/$NAMESPACE +spec: + image: quay.io/fedora/koji-builder-kubevirt:f34 + type: kubevirt + max_jobs: 5 + archs: + - noarch + - x86_64 + channels: + - default + ssl_verify: false + volume: true + koji_builder_cpu: 1000Mi + koji_builder_memory: 1000M + diff --git a/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml b/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml new file mode 100644 index 0000000..caaeb29 --- /dev/null +++ b/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml @@ -0,0 +1,114 @@ +--- +- name: Create the buildsys.apps.fedoraproject.org/v1alpha1.KojiBuilder (kubevirt) + k8s: + state: present + namespace: '{{ namespace }}' + definition: + apiVersion: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder + metadata: + name: sample-virt + annotations: + buildsys.apps.fedoraproject.org/hub: sample/osdk-test + spec: + image: kubevirt/fedora-cloud-container-disk-demo:latest + type: kubevirt + max_jobs: 5 + archs: + - x86_64 + channels: + - default + ssl_verify: false + volume: false + wait: yes + wait_timeout: 300 + wait_condition: + type: Running + reason: Successful + status: "True" + +- block: + - name: 'TEST: kojibuilder.configmap' + k8s_info: + api_version: v1 + kind: ConfigMap + namespace: "{{ namespace }}" + name: kojid-sample-virt-conf + register: koji_configmap + - assert: + that: + - koji_configmap.resources|length == 1 + - koji_configmap.resources[0].metadata.labels['app'] == 'koji-builder' + - "'kojid.conf' in koji_configmap.resources[0].data" + +- block: + - name: 'TEST: kojibuilder.secret.client-cert' + k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ namespace }}" + name: kojid-sample-virt-client-cert + register: kojibuilder_client_secrets + - assert: + that: + - kojibuilder_client_secrets.resources|length == 1 + - kojibuilder_client_secrets.resources[0].metadata.labels['app'] == 'koji-builder' + - "'client.pem' in kojibuilder_client_secrets.resources[0].data" +- block: + - name: 'TEST: kojibuilder.secret.ssh-key' + k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ namespace }}" + name: "kojid-sample-virt-default-ssh-key" + register: kojibuilder_ssh_secrets + - assert: + that: + - kojibuilder_ssh_secrets.resources|length == 1 + - kojibuilder_ssh_secrets.resources[0].metadata.labels['app'] == 'koji-builder' + - kojibuilder_ssh_secrets.resources[0].metadata.labels['ctx'] == 'ssh-key' + - kojibuilder_ssh_secrets.resources[0].metadata.labels['kojid'] == 'sample-virt' + - "'id_rsa' in kojibuilder_ssh_secrets.resources[0].data" + - "'id_rsa.pub' in kojibuilder_ssh_secrets.resources[0].data" +- block: + - name: 'TEST: kojibuilder.secret.ssh-pub-keys' + k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ namespace }}" + name: kojid-sample-virt-ssh-pub-keys + register: kojibuilder_ssh_pub_secrets + - assert: + that: + - kojibuilder_ssh_pub_secrets.resources|length == 1 + - kojibuilder_ssh_pub_secrets.resources[0].metadata.labels['app'] == 'koji-builder' + - kojibuilder_ssh_pub_secrets.resources[0].metadata.labels['ctx'] == 'ssh-key-pub' + - kojibuilder_ssh_pub_secrets.resources[0].metadata.labels['kojid'] == 'sample-virt' + - "'id_rsa' not in kojibuilder_ssh_pub_secrets.resources[0].data" + - "'id_rsa.pub' not in kojibuilder_ssh_pub_secrets.resources[0].data" + - "'key1' in kojibuilder_ssh_pub_secrets.resources[0].data" +- block: + - name: 'TEST: kojibuilder.configmap.cloudinit' + k8s_info: + api_version: v1 + kind: Secret + namespace: "{{ namespace }}" + name: kojid-sample-virt-cloudinit-conf + register: kojibuilder_cloudinit_secret + - debug: var=kojibuilder_cloudinit_secret + - assert: + that: + - kojibuilder_cloudinit_secret.resources|length == 1 + - "kojibuilder_cloudinit_secret.resources[0].metadata.labels['app'] == 'kojid-sample-virt-kubevirt'" + - "'userData' in kojibuilder_cloudinit_secret.resources[0].data" + +- block: + - name: 'TEST: kojibuilder.deletion' + k8s: + state: absent + api_version: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder + namespace: "{{ namespace }}" + name: sample-virt + wait: true + wait_timeout: 300 diff --git a/operator/molecule/default/tasks/kojibuilder_test.yml b/operator/molecule/default/tasks/kojibuilder_test.yml index 2a14bc6..9edc871 100644 --- a/operator/molecule/default/tasks/kojibuilder_test.yml +++ b/operator/molecule/default/tasks/kojibuilder_test.yml @@ -71,3 +71,15 @@ that: - pods.resources|length == 1 - pods.resources[0].metadata.labels['app'] == 'koji-builder' + +- block: + - name: 'TEST: kojibuilder.deletion' + k8s: + state: absent + api_version: buildsys.apps.fedoraproject.org/v1alpha1 + kind: KojiBuilder + namespace: "{{ namespace }}" + name: sample + wait: yes + wait_timeout: 300 + diff --git a/operator/molecule/default/verify.yml b/operator/molecule/default/verify.yml index 6decf47..2bd062a 100644 --- a/operator/molecule/default/verify.yml +++ b/operator/molecule/default/verify.yml @@ -15,9 +15,13 @@ include_tasks: 'tasks/{{ item }}_test.yml' with_items: - kojihub - - kojibuilder - - kojira - - kojiuser + #- kojibuilder + #- kojira + #- kojiuser + + - name: Run kubevirt based builder + include_tasks: tasks/kojibuilder_kubevirt_test.yml + when: "minikube_driver == 'kvm2'" rescue: - name: Retrieve relevant resources k8s_info: diff --git a/operator/molecule/minikube/create.yml b/operator/molecule/minikube/create.yml index 277cfc8..1ebc433 100644 --- a/operator/molecule/minikube/create.yml +++ b/operator/molecule/minikube/create.yml @@ -6,3 +6,21 @@ tasks: - name: Start minikube command: minikube start --driver={{ minikube_driver }} + + - block: + - name: Enable kubevirt + command: minikube addons enable kubevirt + - k8s_info: + api_version: kubevirt.io/v1 + kind: KubeVirt + namespace: kubevirt + name: kubevirt + register: out + retries: 300 + delay: 3 + until: + - "'resources' in out" + - "out.resources | length > 0" + - "'status' in out.resources[0]" + - "out.resources[0].status.phase == 'Deployed'" + when: "minikube_driver == 'kvm2'" diff --git a/operator/molecule/minikube/prepare.yml b/operator/molecule/minikube/prepare.yml new file mode 100644 index 0000000..c8e3c05 --- /dev/null +++ b/operator/molecule/minikube/prepare.yml @@ -0,0 +1,22 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Enable kubevirt + command: minikube addons enable kubevirt + when: "minikube_driver == 'kvm2'" + + - name: Wait for kubevirt readiness + k8s_info: + api_version: kubevirt.io/v1 + kind: KubeVirt + namespace: kubevirt + name: kubevirt + wait: true + wait_condition: + type: Available + reason: AllComponentsReady + status: "True" + diff --git a/operator/requirements.yml b/operator/requirements.yml index 06fe6d2..46de6ce 100644 --- a/operator/requirements.yml +++ b/operator/requirements.yml @@ -6,3 +6,5 @@ collections: version: "0.2.0" - name: ktdreyer.koji_ansible version: "0.0.404" + - name: community.crypto + version: "1.9.3" diff --git a/operator/roles/koji-builder/defaults/main.yml b/operator/roles/koji-builder/defaults/main.yml index e31eae5..edd35cc 100644 --- a/operator/roles/koji-builder/defaults/main.yml +++ b/operator/roles/koji-builder/defaults/main.yml @@ -11,3 +11,7 @@ koji_builder_ssl_verify: "{{ ssl_verify | default(true) }}" koji_builder_volume: "{{ volume | default(true) | bool }}" koji_builder_type: "{{ type | default('repo') }}" + +koji_builder_cpu: 1 +koji_builder_memory: 1000M +koji_builder_running: "{{ running | default(true) | bool }}" diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt.yml b/operator/roles/koji-builder/tasks/builders/kubevirt.yml deleted file mode 100644 index ed97d53..0000000 --- a/operator/roles/koji-builder/tasks/builders/kubevirt.yml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml b/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml new file mode 100644 index 0000000..6c52fd1 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml @@ -0,0 +1,117 @@ +--- +- name: Enable the builder + ktdreyer.koji_ansible.koji_host: + name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + arches: "{{ koji_builder_archs }}" + state: enabled + channels: "{{ koji_builder_channels }}" + koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" + +- name: Check if ssh key is already present + kubernetes.core.k8s_info: + kind: Secret + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-ssh-pub-keys" + register: k8s_out + +- name: Set k8s_secret var + set_fact: + k8s_secret: "{{ k8s_out.resources | length > 0 }}" + +- name: create temporary cert directory + tempfile: + state: directory + prefix: kojid + suffix: kubevirt + register: cert_dir + +- name: Create ssh private key + community.crypto.openssh_keypair: + path: "{{ cert_dir.path }}/key.pem" + size: 4096 + register: koji_builer_ssh_key + when: not k8s_secret + +- name: Create default ssh secret + k8s: + definition: + apiVersion: v1 + kind: Secret + metadata: + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-default-ssh-key" + labels: + app: koji-builder + ctx: ssh-key + kojid: "{{ meta.name }}" + data: + id_rsa: "{{ lookup('file', koji_builer_ssh_key.filename) | b64encode }}" + id_rsa.pub: "{{ koji_builer_ssh_key.public_key | b64encode }}" + when: not k8s_secret + +- name: Create public ssh secret + k8s: + definition: + apiVersion: v1 + kind: Secret + metadata: + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-ssh-pub-keys" + labels: + app: koji-builder + ctx: ssh-key-pub + kojid: "{{ meta.name }}" + data: + key1: "{{ koji_builer_ssh_key.public_key | b64encode }}" + when: not k8s_secret + +- name: Expose kubevirt ssh service + kubernetes.core.k8s: + definition: "{{ lookup('template', 'kubevirt/service.yaml.j2') | from_yaml }}" + wait: true + state: present + +- name: Create cloudinit config + kubernetes.core.k8s: + definition: "{{ lookup('template', 'kubevirt/cloud-init.yaml.j2') | from_yaml }}" + wait: true + state: present + +- name: Create mock pvc + kubernetes.core.k8s: + definition: "{{ lookup('template', 'kubevirt/pvc.yaml.j2') | from_yaml }}" + wait: true + state: present + +- name: + template: + src: kubevirt/vmi.yaml.j2 + dest: "{{ koji_dir_path}}/vmi.yaml" + +- name: Apply k8s vmi resource + k8s: + state: present + src: "{{ koji_dir_path}}/vmi.yaml" + wait: true + +- name: Wait for vm readiness + k8s_info: + api_version: kubevirt.io/v1alpha3 + kind: VirtualMachine + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + register: res + retries: 300 + delay: 3 + until: + - "res.resources | length == 1" + - "'created' in res.resources[0].status" + - "'ready' in res.resources[0].status" + - "res.resources[0].status.created == True" + - "res.resources[0].status.ready == True" + when: koji_builder_running == True + +- name: Cleanup + file: + path: "{{ cert_dir.path }}" + state: absent diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt/destroy.yml b/operator/roles/koji-builder/tasks/builders/kubevirt/destroy.yml new file mode 100644 index 0000000..1de5649 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/kubevirt/destroy.yml @@ -0,0 +1,17 @@ +--- +- name: Disable the builder + ktdreyer.koji_ansible.koji_host: + name: "{{ meta.name }}.{{ meta.namespace }}.{{ koji_builder_type }}" + arches: "{{ koji_builder_archs }}" + state: disabled + channels: "{{ koji_builder_channels }}" + koji: "{{ koji_builder_hub_name }}-{{ koji_builder_hub_namespace }}" + + #- name: Delete koji-builder deployment + # k8s: + # api_version: kubevirt.io/v1alpha3 + # kind: VirtualMachineInstance + # namespace: "{{ meta.namespace }}" + # name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + # state: absent + # wait: true diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt/main.yml b/operator/roles/koji-builder/tasks/builders/kubevirt/main.yml new file mode 100644 index 0000000..ea70183 --- /dev/null +++ b/operator/roles/koji-builder/tasks/builders/kubevirt/main.yml @@ -0,0 +1,7 @@ +- include_tasks: create.yml + when: state is not defined + +- include_tasks: destroy.yml + when: + - state is defined + - state == 'absent' diff --git a/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 new file mode 100644 index 0000000..3240ff4 --- /dev/null +++ b/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "kojid-{{ meta.name }}-cloudinit-conf" + namespace: "{{ meta.namespace }}" + labels: + app: "kojid-{{ meta.name }}-{{ koji_builder_type }}" +stringData: + userData: |- + #cloud-config + ssh_pwauth: False + bootcmd: + # kojid.conf setup + - "mkdir -p /mnt/kojid/conf" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK240D | cut -f1 -d' ') /mnt/kojid/conf" + # client-cert setup + - "mkdir -p /mnt/kojid/certs/client" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK250D | cut -f1 -d' ') /mnt/kojid/certs/client" + # ca-cert setup + - "mkdir -p /mnt/kojid/certs/ca" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK260D | cut -f1 -d' ') /mnt/kojid/certs/ca" + # /var/lib/mock dir setup + - "mkdir -p /var/lib/mock" + - "chgrp -R mock /var/lib/mock" + - "mkfs.ext4 /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ')" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ') /var/lib/mock" diff --git a/operator/roles/koji-builder/templates/kubevirt/pvc.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/pvc.yaml.j2 new file mode 100644 index 0000000..b80ff54 --- /dev/null +++ b/operator/roles/koji-builder/templates/kubevirt/pvc.yaml.j2 @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: kojid-{{ meta.name }}-{{ koji_builder_type }}-mock + labels: + app: kojid-{{ meta.name }}-{{ koji_builder_type }} + namespace: {{ meta.namespace }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 50Gi diff --git a/operator/roles/koji-builder/templates/kubevirt/service.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/service.yaml.j2 new file mode 100644 index 0000000..ca51da0 --- /dev/null +++ b/operator/roles/koji-builder/templates/kubevirt/service.yaml.j2 @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: kojid-{{ meta.name }}-ssh + namespace: {{ meta.namespace }} +spec: + ports: + - port: 22 + protocol: TCP + targetPort: 22 + selector: + kubevirt.io/domain: {{ meta.name }} + kubevirt.io/size: small diff --git a/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 new file mode 100644 index 0000000..88a7715 --- /dev/null +++ b/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 @@ -0,0 +1,72 @@ +apiVersion: kubevirt.io/v1alpha3 +# kind: VirtualMachineInstance +kind: VirtualMachine +metadata: + name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + labels: + app: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + namespace: {{ meta.namespace }} +spec: + running: {{ koji_builder_running }} + template: + metadata: + labels: + kubevirt.io/size: small + kubevirt.io/domain: "kojid-{{ meta.name }}-{{ koji_builder_type }}" + spec: + terminationGracePeriodSeconds: 30 + accessCredentials: + - sshPublicKey: + source: + secret: + secretName: "kojid-{{ meta.name }}-ssh-pub-keys" + propagationMethod: + configDrive: {} + domain: + resources: + requests: + memory: "{{ koji_builder_memory }}" + devices: + interfaces: + - name: default + masquerade: {} + disks: + - name: containerdisk + disk: + bus: virtio + - name: cloudinitdisk + disk: + bus: virtio + - name: mockdisk + serial: CVLY623300HK230D + disk: {} + - name: kojid + serial: CVLY623300HK240D + - name: client-cert + serial: CVLY623300HK250D + - name: ca-cert + serial: CVLY623300HK260D + networks: + - name: default + pod: {} + volumes: + - name: containerdisk + containerDisk: + image: "{{ koji_builder_image }}" + - name: cloudinitdisk + cloudInitConfigDrive: + secretRef: + name: "kojid-{{ meta.name }}-cloudinit-conf" + - name: mockdisk + persistentVolumeClaim: + claimName: kojid-{{ meta.name }}-{{ koji_builder_type }}-mock + - name: kojid + configMap: + name: "{{ koji_builder_configmap }}" + - name: client-cert + secret: + secretName: "{{ koji_builder_client_cert_secret }}" + - name: ca-cert + secret: + secretName: "{{ koji_builder_cacert_secret }}" + From bed292101d3cca7e48f9ca3210660f72de99aad0 Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Oct 19 2021 18:32:58 +0000 Subject: [PATCH 10/10] kubevirt vmi resource --- diff --git a/images/koji-builder-kubevirt/Dockerfile b/images/koji-builder-kubevirt/Dockerfile new file mode 100644 index 0000000..8047d5e --- /dev/null +++ b/images/koji-builder-kubevirt/Dockerfile @@ -0,0 +1,5 @@ +FROM scratch + +ARG IMAGE=https://download.fedoraproject.org/pub/fedora/linux/releases/34/Cloud/x86_64/images/Fedora-Cloud-Base-34-1.2.x86_64.qcow2 + +ADD ${IMAGE} /disk/ diff --git a/operator/Dockerfile b/operator/Dockerfile index 9fa0408..7d3f4a1 100644 --- a/operator/Dockerfile +++ b/operator/Dockerfile @@ -1,9 +1,9 @@ FROM quay.io/operator-framework/ansible-operator:v1.7.2 USER root -RUN dnf install -y gcc libpq libpq-devel python38-devel krb5-devel wget python38-psycopg2 -#TODO: find a better way to install koji and its schema.sql file -RUN pip3.8 install koji==1.25.1 +RUN dnf install -y git gcc libpq libpq-devel python38-devel krb5-devel wget python38-psycopg2 +#TODO: find a better way to install both koji and cloud-init and its schema.sql file +RUN pip3.8 install koji==1.25.1 git+https://github.com/canonical/cloud-init.git@20.4.1 COPY hack/schema.sql /usr/share/doc/koji/docs/schema.sql RUN chmod 644 /usr/share/doc/koji/docs/schema.sql USER ${USER_ID} diff --git a/operator/molecule/cluster/converge.yml b/operator/molecule/cluster/converge.yml new file mode 100644 index 0000000..1652a6a --- /dev/null +++ b/operator/molecule/cluster/converge.yml @@ -0,0 +1,24 @@ +--- +- name: Converge + hosts: localhost + connection: local + gather_facts: no + + tasks: + - name: Build operator image + docker_image: + build: + path: '{{ project_dir }}' + pull: no + name: '{{ operator_image }}' + tag: latest + push: no + source: build + force_source: yes + + - name: Load image into minikube + command: minikube image load {{ operator_image }} --overwrite=true + + + +- import_playbook: ../default/converge.yml diff --git a/operator/molecule/cluster/create.yml b/operator/molecule/cluster/create.yml new file mode 100644 index 0000000..1f88a28 --- /dev/null +++ b/operator/molecule/cluster/create.yml @@ -0,0 +1,14 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Ensure namespace exists + k8s: + api_version: v1 + kind: Namespace + name: "{{ namespace }}" + state: present + wait: true + diff --git a/operator/molecule/cluster/destroy.yml b/operator/molecule/cluster/destroy.yml new file mode 100644 index 0000000..8ee5b41 --- /dev/null +++ b/operator/molecule/cluster/destroy.yml @@ -0,0 +1,21 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + collections: + - community.kubernetes + + tasks: + - name: Destroy namespace + k8s: + api_version: v1 + kind: Namespace + name: "{{ namespace }}" + state: absent + wait: true + + - name: Unset pull policy + command: '{{ kustomize }} edit remove patch pull_policy/{{ operator_pull_policy }}.yaml' + args: + chdir: '{{ config_dir }}/testing' diff --git a/operator/molecule/cluster/molecule.yml b/operator/molecule/cluster/molecule.yml new file mode 100644 index 0000000..08dacd7 --- /dev/null +++ b/operator/molecule/cluster/molecule.yml @@ -0,0 +1,54 @@ +--- +dependency: + name: galaxy + options: + requirements-file: requirements.yml +driver: + name: delegated +lint: | + set -e + yamllint -d "{extends: relaxed, rules: {line-length: {max: 120}}}" . +platforms: + - name: cluster + groups: + - k8s +provisioner: + name: ansible + playbooks: + verify: ../default/verify.yml + prepare: ../default/prepare.yml + lint: | + set -e + ansible-lint + inventory: + group_vars: + all: + namespace: ${TEST_OPERATOR_NAMESPACE:-osdk-test} + operator_image: buildsys.apps.fedoraproject.org/koji-operator:testing + operator_pull_policy: "Never" + host_vars: + localhost: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + config_dir: ${MOLECULE_PROJECT_DIRECTORY}/config + samples_dir: ${MOLECULE_PROJECT_DIRECTORY}/config/samples + components_dir: ${MOLECULE_PROJECT_DIRECTORY}/../components + project_dir: ${MOLECULE_PROJECT_DIRECTORY} + operator_pull_policy: "Never" + kustomize: ${KUSTOMIZE_PATH:-kustomize} +scenario: + name: cluster + test_sequence: + # - lint + - destroy + - dependency + - syntax + - create + - prepare + - converge + - verify + - destroy +verifier: + name: ansible + lint: | + set -e + ansible-lint diff --git a/operator/molecule/cluster/prepare.yml b/operator/molecule/cluster/prepare.yml new file mode 100644 index 0000000..c8e3c05 --- /dev/null +++ b/operator/molecule/cluster/prepare.yml @@ -0,0 +1,22 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Enable kubevirt + command: minikube addons enable kubevirt + when: "minikube_driver == 'kvm2'" + + - name: Wait for kubevirt readiness + k8s_info: + api_version: kubevirt.io/v1 + kind: KubeVirt + namespace: kubevirt + name: kubevirt + wait: true + wait_condition: + type: Available + reason: AllComponentsReady + status: "True" + diff --git a/operator/molecule/cluster/requirements.yml b/operator/molecule/cluster/requirements.yml new file mode 100644 index 0000000..3f626ed --- /dev/null +++ b/operator/molecule/cluster/requirements.yml @@ -0,0 +1,6 @@ +--- +collections: + - name: community.kubernetes + version: "1.2.1" + - name: operator_sdk.util + version: "0.2.0" diff --git a/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml b/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml index caaeb29..207a135 100644 --- a/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml +++ b/operator/molecule/default/tasks/kojibuilder_kubevirt_test.yml @@ -11,7 +11,7 @@ annotations: buildsys.apps.fedoraproject.org/hub: sample/osdk-test spec: - image: kubevirt/fedora-cloud-container-disk-demo:latest + image: quay.io/fedora-kube-sig/koji-builder-kubevirt:raw type: kubevirt max_jobs: 5 archs: @@ -20,6 +20,7 @@ - default ssl_verify: false volume: false + running: true wait: yes wait_timeout: 300 wait_condition: @@ -27,6 +28,9 @@ reason: Successful status: "True" +- name: Pause until you can verify updates to an application were successful + pause: + - block: - name: 'TEST: kojibuilder.configmap' k8s_info: @@ -103,6 +107,21 @@ - "'userData' in kojibuilder_cloudinit_secret.resources[0].data" - block: + - name: 'TEST: kojibuilder.configmap.kojid-default-setup' + k8s_info: + api_version: v1 + kind: ConfigMap + namespace: "{{ namespace }}" + name: kojid-default-setup + register: kojibuilder_setup_cm + - debug: var=kojibuilder_setup_cm + - assert: + that: + - kojibuilder_setup_cm.resources|length == 1 + - "'setup.sh' in kojibuilder_setup_cm.resources[0].data" + - "'kojid.service' in kojibuilder_setup_cm.resources[0].data" + +- block: - name: 'TEST: kojibuilder.deletion' k8s: state: absent diff --git a/operator/molecule/default/verify.yml b/operator/molecule/default/verify.yml index 2bd062a..f1c22b5 100644 --- a/operator/molecule/default/verify.yml +++ b/operator/molecule/default/verify.yml @@ -15,9 +15,9 @@ include_tasks: 'tasks/{{ item }}_test.yml' with_items: - kojihub - #- kojibuilder - #- kojira - #- kojiuser + - kojibuilder + - kojira + - kojiuser - name: Run kubevirt based builder include_tasks: tasks/kojibuilder_kubevirt_test.yml diff --git a/operator/molecule/minikube/create.yml b/operator/molecule/minikube/create.yml index 1ebc433..405f654 100644 --- a/operator/molecule/minikube/create.yml +++ b/operator/molecule/minikube/create.yml @@ -4,23 +4,29 @@ connection: local gather_facts: false tasks: - - name: Start minikube - command: minikube start --driver={{ minikube_driver }} - - block: - - name: Enable kubevirt - command: minikube addons enable kubevirt - - k8s_info: - api_version: kubevirt.io/v1 - kind: KubeVirt - namespace: kubevirt - name: kubevirt - register: out - retries: 300 - delay: 3 - until: - - "'resources' in out" - - "out.resources | length > 0" - - "'status' in out.resources[0]" - - "out.resources[0].status.phase == 'Deployed'" - when: "minikube_driver == 'kvm2'" + - name: Start minikube + command: minikube start --driver={{ minikube_driver }} + + - name: Sleep for 10 seconds and continue with play + wait_for: + timeout: 10 + + - block: + - name: Enable kubevirt + command: minikube addons enable kubevirt + - k8s_info: + api_version: kubevirt.io/v1 + kind: KubeVirt + namespace: kubevirt + name: kubevirt + register: out + retries: 300 + delay: 3 + until: + - "'resources' in out" + - "out.resources | length > 0" + - "'status' in out.resources[0]" + - "out.resources[0].status.phase == 'Deployed'" + when: "minikube_driver == 'kvm2'" + when: minikube_skip == 'N' diff --git a/operator/molecule/minikube/destroy.yml b/operator/molecule/minikube/destroy.yml index 271e462..cafd68c 100644 --- a/operator/molecule/minikube/destroy.yml +++ b/operator/molecule/minikube/destroy.yml @@ -9,6 +9,7 @@ tasks: - name: Destroy minikube command: minikube delete + when: minikube_skip == 'N' - name: Unset pull policy command: '{{ kustomize }} edit remove patch pull_policy/{{ operator_pull_policy }}.yaml' diff --git a/operator/molecule/minikube/molecule.yml b/operator/molecule/minikube/molecule.yml index 2b34fa5..28af8cd 100644 --- a/operator/molecule/minikube/molecule.yml +++ b/operator/molecule/minikube/molecule.yml @@ -36,6 +36,7 @@ provisioner: operator_pull_policy: "Never" kustomize: ${KUSTOMIZE_PATH:-kustomize} minikube_driver: ${MINIKUBE_DRIVER:-kvm2} + minikube_skip: ${MINIKUBE_SKIP:-N} scenario: name: minikube test_sequence: diff --git a/operator/roles/koji-builder/defaults/main.yml b/operator/roles/koji-builder/defaults/main.yml index edd35cc..9a6d7eb 100644 --- a/operator/roles/koji-builder/defaults/main.yml +++ b/operator/roles/koji-builder/defaults/main.yml @@ -12,6 +12,6 @@ koji_builder_ssl_verify: "{{ ssl_verify | default(true) }}" koji_builder_volume: "{{ volume | default(true) | bool }}" koji_builder_type: "{{ type | default('repo') }}" -koji_builder_cpu: 1 -koji_builder_memory: 1000M +koji_builder_cpu: "{{ cpu | default(1) | int }}" +koji_builder_memory: "{{ memory | default('1000M') }}" koji_builder_running: "{{ running | default(true) | bool }}" diff --git a/operator/roles/koji-builder/files/cloud-init-config.yaml b/operator/roles/koji-builder/files/cloud-init-config.yaml new file mode 100644 index 0000000..80c8d75 --- /dev/null +++ b/operator/roles/koji-builder/files/cloud-init-config.yaml @@ -0,0 +1,26 @@ +#cloud-config +ssh_pwauth: False +password: koji +chpasswd: + expire: False + list: |- + root:koji +bootcmd: + # kojid.conf setup + - mkdir -p /mnt/kojid + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK240D | cut -f1 -d' ') /mnt/kojid" + # client-cert setup + - mkdir -p /mnt/client-cert + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK250D | cut -f1 -d' ') /mnt/client-cert" + # ca-cert setup + - mkdir -p /mnt/ca-cert + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK260D | cut -f1 -d' ') /mnt/ca-cert" + # /var/lib/mock dir setup + - "mkdir -p /var/lib/mock" + - "chgrp -R mock /var/lib/mock" + - "mkfs.ext4 /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ')" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ') /var/lib/mock" + # mockcfg + - "mkdir -p /mnt/mockcfg" + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK270D | cut -f1 -d' ') /mnt/mockcfg" + diff --git a/operator/roles/koji-builder/files/cloud-init-script.sh b/operator/roles/koji-builder/files/cloud-init-script.sh new file mode 100644 index 0000000..1c651ca --- /dev/null +++ b/operator/roles/koji-builder/files/cloud-init-script.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# packages +dnf install -y --setopt='fastestmirror=True' koji-builder + +#kojid setup +mkdir /mnt/kojid +rm -f /etc/kojid/kojid.conf +ln -sf /mnt/kojid/kojid.conf /etc/kojid/kojid.conf + +# mock setup +mkdir /mnt/mockcfg +rm -f /etc/mock/site-defaults.cfg +ln -sf /mnt/mockfg/site-defaults.cfg /etc/mock/site-defaults.cfg +usermod -aG mock kojibuilder + +# cert setup +mkdir -p /etc/certs/ca /etc/certs/client +chown -R kojibuilder /etc/certs +ln -sf /mnt/ca-cert/cert /etc/certs/ca/cert +ln -sf /mnt/client-cert/client.pem /etc/certs/client/client.pem +ln -sf /mnt/ca-cert/cert /etc/pki/ca-trust/source/anchors/ca.pem +ln -sf /mnt/client-cert/client.pem /etc/pki/ca-trust/source/anchors/client.pem +update-ca-trust + +# kojid system enable +systemctl enable kojid +systemctl start kojid diff --git a/operator/roles/koji-builder/files/mock-site-defaults.cfg b/operator/roles/koji-builder/files/mock-site-defaults.cfg new file mode 100644 index 0000000..5f3d1f3 --- /dev/null +++ b/operator/roles/koji-builder/files/mock-site-defaults.cfg @@ -0,0 +1,11 @@ +config_opts['plugin_conf']['package_state_enable'] = False +config_opts['plugin_conf']['ccache_enable'] = False +config_opts['dnf_common_opts'] = ['--setopt=install_weak_deps=0'] +config_opts['macros']['%bugurl'] = 'https://bugz.fedoraproject.org/%name' +config_opts['nosync'] = True +config_opts['nosync_force'] = True +config_opts['environment']['LANG'] = 'C.UTF-8' +config_opts['use_bootstrap'] = True +config_opts['yum_install_command'] += " -x devtoolset*" +config_opts['dnf_warning'] = False + diff --git a/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml b/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml index 6c52fd1..6bb0a1f 100644 --- a/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml +++ b/operator/roles/koji-builder/tasks/builders/kubevirt/create.yml @@ -70,12 +70,14 @@ definition: "{{ lookup('template', 'kubevirt/service.yaml.j2') | from_yaml }}" wait: true state: present - -- name: Create cloudinit config - kubernetes.core.k8s: - definition: "{{ lookup('template', 'kubevirt/cloud-init.yaml.j2') | from_yaml }}" - wait: true - state: present + + #- name: Create cloudinit config + # kubernetes.core.k8s: + # definition: "{{ lookup('template', 'kubevirt/cloud-init.yaml.j2') | from_yaml }}" + # wait: true + # state: present + # vars: + # cinit_kojid_contents: "{{ k8s_kojid_cm.resources[0].data['kojid.conf'] }}" - name: Create mock pvc kubernetes.core.k8s: @@ -83,34 +85,60 @@ wait: true state: present -- name: - template: - src: kubevirt/vmi.yaml.j2 - dest: "{{ koji_dir_path}}/vmi.yaml" + #- name: Ensure default setup script is present + # kubernetes.core.k8s: + # definition: "{{ lookup('template', 'kubevirt/default-setup-configmap.yaml.j2') | from_yaml }}" + # wait: true + # state: present + +- name: Generate cloud-init mult part file data + koji_cloudinit_userdata: + user_config: "{{ role_path }}/files/cloud-init-config.yaml" + user_script: "{{ role_path }}/files/cloud-init-script.sh" + register: koji_builder_cloud_init_user_data + +- name: Create cloud-init configuration secret + k8s: + state: present + wait: true + definition: + apiVersion: v1 + kind: Secret + metadata: + annotations: + cloud-init-config: "{{ lookup('file', 'cloud-init-config.yaml') }}" + cloud-init-script: "{{ lookup('file', 'cloud-init-script.sh') }}" + namespace: "{{ meta.namespace }}" + name: "kojid-{{ meta.name }}-cloud-init" + data: + userData: "{{ koji_builder_cloud_init_user_data.data | b64encode }}" -- name: Apply k8s vmi resource +- name: Create mock config file k8s: state: present - src: "{{ koji_dir_path}}/vmi.yaml" wait: true + definition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: kojid-mock-default + namespace: "{{ meta.namespace }}" + labels: + app: koji-builder-vm + data: + site-defaults.cfg: "{{ lookup('file', 'mock-site-defaults.cfg') }}" -- name: Wait for vm readiness - k8s_info: - api_version: kubevirt.io/v1alpha3 - kind: VirtualMachine - namespace: "{{ meta.namespace }}" - name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" - register: res - retries: 300 - delay: 3 - until: - - "res.resources | length == 1" - - "'created' in res.resources[0].status" - - "'ready' in res.resources[0].status" - - "res.resources[0].status.created == True" - - "res.resources[0].status.ready == True" - when: koji_builder_running == True +- block: + - name: + template: + src: kubevirt/vmi.yaml.j2 + dest: "{{ koji_dir_path}}/vmi.yaml" + - name: Apply k8s vmi resource + k8s: + state: present + src: "{{ koji_dir_path}}/vmi.yaml" + - name: Cleanup file: path: "{{ cert_dir.path }}" diff --git a/operator/roles/koji-builder/templates/configmap.yml.j2 b/operator/roles/koji-builder/templates/configmap.yml.j2 index 5972866..fedad7f 100644 --- a/operator/roles/koji-builder/templates/configmap.yml.j2 +++ b/operator/roles/koji-builder/templates/configmap.yml.j2 @@ -21,4 +21,3 @@ data: ; Configuration authentication serverca = /etc/certs/ca/cert cert=/etc/certs/client/client.pem - diff --git a/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 index 3240ff4..277f2cc 100644 --- a/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 +++ b/operator/roles/koji-builder/templates/kubevirt/cloud-init.yaml.j2 @@ -9,18 +9,28 @@ stringData: userData: |- #cloud-config ssh_pwauth: False + password: koji + chpasswd: + expire: False + list: |- + root:koji bootcmd: # kojid.conf setup - - "mkdir -p /mnt/kojid/conf" - - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK240D | cut -f1 -d' ') /mnt/kojid/conf" + - mkdir -p /etc/kojid + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK240D | cut -f1 -d' ') /etc/kojid" # client-cert setup - - "mkdir -p /mnt/kojid/certs/client" - - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK250D | cut -f1 -d' ') /mnt/kojid/certs/client" + - mkdir -p /etc/certs/client + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK250D | cut -f1 -d' ') /etc/certs/client" # ca-cert setup - - "mkdir -p /mnt/kojid/certs/ca" - - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK260D | cut -f1 -d' ') /mnt/kojid/certs/ca" + - mkdir -p /etc/certs/ca + - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK260D | cut -f1 -d' ') /etc/certs/ca" # /var/lib/mock dir setup - "mkdir -p /var/lib/mock" - "chgrp -R mock /var/lib/mock" - "mkfs.ext4 /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ')" - "mount /dev/$(lsblk --nodeps -no name,serial | grep CVLY623300HK230D | cut -f1 -d' ') /var/lib/mock" + # general setup + - usermod -aG mock kojibuilder + # - cp /mnt/kojid/conf/site-defaults.cfg /etc/mock/site-defaults.cfg + - cp /etc/certs/ca/crt /etc/pki/ca-trust/source/anchors/ + - update-ca-trust diff --git a/operator/roles/koji-builder/templates/kubevirt/default-setup-configmap.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/default-setup-configmap.yaml.j2 new file mode 100644 index 0000000..96b5a26 --- /dev/null +++ b/operator/roles/koji-builder/templates/kubevirt/default-setup-configmap.yaml.j2 @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kojid-default-setup + namespace: "{{ meta.namespace }}" + labels: + app: kojid +data: + setup.sh: |- + #!/bin/bash + + # packages + dnf install -y koji-builder + + # mock setup + usermod -aG mock kojibuilder + # cp /mnt/kojid/conf/site-defaults.cfg /etc/mock/site-defaults.cfg + + # kojid setup + cp /mnt/kojid/conf/kojid.conf /etc/kojid/kojid.conf + chmod 644 /etc/kojid/kojid.conf + + # cert setup + mkdir -p /etc/certs + cp /mnt/kojid/certs/ca/cert /etc/certs/ca.pem + cp /mnt/kojid/certs/client/client.pem /etc/certs/client.pem + chown -R kojibuilder /etc/certs + cp /etc/certs/* /etc/pki/ca-trust/source/anchors/ + update-ca-trust diff --git a/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 b/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 index 88a7715..b00b0ce 100644 --- a/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 +++ b/operator/roles/koji-builder/templates/kubevirt/vmi.yaml.j2 @@ -1,5 +1,4 @@ apiVersion: kubevirt.io/v1alpha3 -# kind: VirtualMachineInstance kind: VirtualMachine metadata: name: "kojid-{{ meta.name }}-{{ koji_builder_type }}" @@ -46,6 +45,8 @@ spec: serial: CVLY623300HK250D - name: ca-cert serial: CVLY623300HK260D + - name: mockcfg + serial: CVLY623300HK270D networks: - name: default pod: {} @@ -56,13 +57,16 @@ spec: - name: cloudinitdisk cloudInitConfigDrive: secretRef: - name: "kojid-{{ meta.name }}-cloudinit-conf" + name: "kojid-{{ meta.name }}-cloud-init" - name: mockdisk persistentVolumeClaim: claimName: kojid-{{ meta.name }}-{{ koji_builder_type }}-mock - name: kojid configMap: name: "{{ koji_builder_configmap }}" + - name: mockcfg + configMap: + name: kojid-mock-default - name: client-cert secret: secretName: "{{ koji_builder_client_cert_secret }}" diff --git a/operator/roles/koji-lib/library/koji_cloudinit_userdata.py b/operator/roles/koji-lib/library/koji_cloudinit_userdata.py new file mode 100644 index 0000000..4ff01f6 --- /dev/null +++ b/operator/roles/koji-lib/library/koji_cloudinit_userdata.py @@ -0,0 +1,46 @@ +from ansible.module_utils.basic import AnsibleModule + + +def main(): + output = { + 'changed': False, + 'failed': False, + 'skipped': False, + 'msg': '', + 'data': '' + } + + module_args = dict( + user_config=dict(type='str', required=True), + user_script=dict(type='str', required=True) + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + user_config = module.params['user_config'] + user_script = module.params['user_script'] + + res = module.run_command([ + 'cloud-init', + 'devel', 'make-mime', + '-a', f'{user_config}:cloud-config', + '-a', f'{user_script}:x-shellscript' + ]) + + if res[0] != 0: + output['failed'] = True + output['msg'] = 'cloud-init failed to run' + output['data'] = res[1] + module.fail_json(**output) + + output['changed'] = True + output['msg'] = 'Multi part file content generated' + output['data'] = res[1] + module.exit_json(**output) + + +if __name__ == '__main__': + main()