From cb8e7be7884f44915618247bdde85cc6e0a78f19 Mon Sep 17 00:00:00 2001
From: Leonardo Rossetti <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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 <lrossett@redhat.com>
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()

