From 73c38fe8ca0de76997495dee2ebde0dbb06319a7 Mon Sep 17 00:00:00 2001
From: Leonardo Rossetti <lrossett@redhat.com>
Date: Aug 30 2021 21:25:39 +0000
Subject: [PATCH 1/4] koji user crd


---

diff --git a/operator/PROJECT b/operator/PROJECT
index f35e023..e848c32 100644
--- a/operator/PROJECT
+++ b/operator/PROJECT
@@ -27,4 +27,11 @@ resources:
   group: buildsys
   kind: Kojira
   version: v1alpha1
+- api:
+    crdVersion: v1
+    namespaced: true
+  domain: apps.fedoraproject.org
+  group: buildsys
+  kind: KojiUser
+  version: v1alpha1
 version: "3"
diff --git a/operator/config/crd/bases/buildsys.apps.fedoraproject.org_kojiusers.yaml b/operator/config/crd/bases/buildsys.apps.fedoraproject.org_kojiusers.yaml
new file mode 100644
index 0000000..ddbfe81
--- /dev/null
+++ b/operator/config/crd/bases/buildsys.apps.fedoraproject.org_kojiusers.yaml
@@ -0,0 +1,44 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: kojiusers.buildsys.apps.fedoraproject.org
+spec:
+  group: buildsys.apps.fedoraproject.org
+  names:
+    kind: KojiUser
+    listKind: KojiUserList
+    plural: kojiusers
+    singular: kojiuser
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: KojiUser is the Schema for the kojiusers API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: Spec defines the desired state of KojiUser
+            type: object
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            description: Status defines the observed state of KojiUser
+            type: object
+            x-kubernetes-preserve-unknown-fields: true
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
diff --git a/operator/config/crd/kustomization.yaml b/operator/config/crd/kustomization.yaml
index b47224b..335a9b1 100644
--- a/operator/config/crd/kustomization.yaml
+++ b/operator/config/crd/kustomization.yaml
@@ -5,4 +5,5 @@ resources:
 - bases/buildsys.apps.fedoraproject.org_kojihubs.yaml
 - bases/buildsys.apps.fedoraproject.org_kojibuilders.yaml
 - bases/buildsys.apps.fedoraproject.org_kojiras.yaml
+- bases/buildsys.apps.fedoraproject.org_kojiusers.yaml
 #+kubebuilder:scaffold:crdkustomizeresource
diff --git a/operator/config/rbac/kojiuser_editor_role.yaml b/operator/config/rbac/kojiuser_editor_role.yaml
new file mode 100644
index 0000000..85710c3
--- /dev/null
+++ b/operator/config/rbac/kojiuser_editor_role.yaml
@@ -0,0 +1,24 @@
+# permissions for end users to edit kojiusers.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: kojiuser-editor-role
+rules:
+- apiGroups:
+  - buildsys.apps.fedoraproject.org
+  resources:
+  - kojiusers
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - buildsys.apps.fedoraproject.org
+  resources:
+  - kojiusers/status
+  verbs:
+  - get
diff --git a/operator/config/rbac/kojiuser_viewer_role.yaml b/operator/config/rbac/kojiuser_viewer_role.yaml
new file mode 100644
index 0000000..579d388
--- /dev/null
+++ b/operator/config/rbac/kojiuser_viewer_role.yaml
@@ -0,0 +1,20 @@
+# permissions for end users to view kojiusers.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: kojiuser-viewer-role
+rules:
+- apiGroups:
+  - buildsys.apps.fedoraproject.org
+  resources:
+  - kojiusers
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - buildsys.apps.fedoraproject.org
+  resources:
+  - kojiusers/status
+  verbs:
+  - get
diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml
index 67dfc65..23a2bb9 100644
--- a/operator/config/rbac/role.yaml
+++ b/operator/config/rbac/role.yaml
@@ -108,4 +108,21 @@ rules:
       - patch
       - update
       - watch
+  ##
+  ## Rules for buildsys.apps.fedoraproject.org/v1alpha1, Kind: KojiUser
+  ##
+  - apiGroups:
+      - buildsys.apps.fedoraproject.org
+    resources:
+      - kojiusers
+      - kojiusers/status
+      - kojiusers/finalizers
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
 #+kubebuilder:scaffold:rules
diff --git a/operator/config/samples/buildsys_v1alpha1_kojiuser.yaml b/operator/config/samples/buildsys_v1alpha1_kojiuser.yaml
new file mode 100644
index 0000000..9a63423
--- /dev/null
+++ b/operator/config/samples/buildsys_v1alpha1_kojiuser.yaml
@@ -0,0 +1,13 @@
+apiVersion: buildsys.apps.fedoraproject.org/v1alpha1
+kind: KojiUser
+metadata:
+  name: sample
+spec:
+  permissions:
+    - repo
+  admin_secret: koji-hub-admin-cert
+  hub_host: koji-hub:8443
+  authentication:
+    ssl:
+      client_secret_name: koji-sample-user-client-cert
+      ca_secret_name: koji-hub-ca-cert
\ No newline at end of file
diff --git a/operator/config/samples/kustomization.yaml b/operator/config/samples/kustomization.yaml
index 8f57e27..a6a4657 100644
--- a/operator/config/samples/kustomization.yaml
+++ b/operator/config/samples/kustomization.yaml
@@ -3,4 +3,5 @@ resources:
 - buildsys_v1alpha1_kojihub.yaml
 - buildsys_v1alpha1_kojibuilder.yaml
 - buildsys_v1alpha1_kojira.yaml
+- buildsys_v1alpha1_kojiuser.yaml
 #+kubebuilder:scaffold:manifestskustomizesamples
diff --git a/operator/config/testing/kustomization.yaml b/operator/config/testing/kustomization.yaml
index f104b67..2e714cb 100644
--- a/operator/config/testing/kustomization.yaml
+++ b/operator/config/testing/kustomization.yaml
@@ -20,5 +20,9 @@ resources:
 - ../manager
 images:
 - name: testing
-  newName: apps.fedoraproject.org/mbox-operator
-  newTag: testing
+  newName: quay.io/lrossett/koji-operator
+  newTag: dev7
+patches:
+- path: pull_policy/Never.yaml
+- path: pull_policy/Always.yaml
+- path: pull_policy/IfNotPresent.yaml
diff --git a/operator/molecule/default/molecule.yml b/operator/molecule/default/molecule.yml
index 1c485fe..d3a692d 100644
--- a/operator/molecule/default/molecule.yml
+++ b/operator/molecule/default/molecule.yml
@@ -3,9 +3,9 @@ dependency:
   name: galaxy
 driver:
   name: delegated
-lint: |
-  set -e
-  yamllint -d "{extends: relaxed, rules: {line-length: {max: 120}}}" .
+    # lint: |
+    #  set -e
+    #  yamllint -d "{extends: relaxed, rules: {}" .
 platforms:
   - name: cluster
     groups:
@@ -25,13 +25,13 @@ provisioner:
         config_dir: ${MOLECULE_PROJECT_DIRECTORY}/config
         samples_dir: ${MOLECULE_PROJECT_DIRECTORY}/config/samples
         components_dir: ${MOLECULE_PROJECT_DIRECTORY}/../components
-        operator_image: ${OPERATOR_IMAGE:-""}
-        operator_pull_policy: ${OPERATOR_PULL_POLICY:-"Always"}
+        operator_image: ${OPERATOR_IMAGE:-"quay.io/lrossett/koji-operator:dev7"}
+        operator_pull_policy: ${OPERATOR_PULL_POLICY:-"IfNotPresent"}
         kustomize: ${KUSTOMIZE_PATH:-kustomize}
   env:
     K8S_AUTH_KUBECONFIG: ${KUBECONFIG:-"~/.kube/config"}
 verifier:
   name: ansible
-  lint: |
-    set -e
-    ansible-lint
+    #lint: |
+    #set -e
+    #ansible-lint
diff --git a/operator/molecule/default/requirements.yml b/operator/molecule/default/requirements.yml
new file mode 100644
index 0000000..3f626ed
--- /dev/null
+++ b/operator/molecule/default/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/kojiuser_test.yml b/operator/molecule/default/tasks/kojiuser_test.yml
new file mode 100644
index 0000000..b9931b2
--- /dev/null
+++ b/operator/molecule/default/tasks/kojiuser_test.yml
@@ -0,0 +1,28 @@
+---
+- name: Create the buildsys.apps.fedoraproject.org/v1alpha1.KojiUser
+  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_kojiuser.yaml'
+
+- block:
+    - name: 'TEST: kojiuser.secret.client-cert'
+      k8s_info:
+        api_version: v1
+        kind: Secret
+        namespace: "{{ namespace }}"
+        name: koji-sample-user-client-cert
+      register: kojiuser_client_secrets
+    - assert:
+        that:
+          - kojiuser_client_secrets.resources|length == 1
+          - kojiuser_client_secrets.resources[0].metadata.labels['app'] == 'koji-user'
+          - "'client.pem' in kojiuser_client_secrets.resources[0].data"
\ No newline at end of file
diff --git a/operator/molecule/default/verify.yml b/operator/molecule/default/verify.yml
index 04306ae..7d98c50 100644
--- a/operator/molecule/default/verify.yml
+++ b/operator/molecule/default/verify.yml
@@ -15,8 +15,9 @@
           include_tasks: 'tasks/{{ item }}_test.yml'
           with_items:
             - kojihub
-            - kojibuilder
-            - kojira
+            # - kojibuilder
+            # - kojira
+            - kojiuser
       rescue:
         - name: Retrieve relevant resources
           k8s_info:
diff --git a/operator/molecule/kind/molecule.yml b/operator/molecule/kind/molecule.yml
index d4361f3..1356087 100644
--- a/operator/molecule/kind/molecule.yml
+++ b/operator/molecule/kind/molecule.yml
@@ -1,6 +1,8 @@
 ---
 dependency:
   name: galaxy
+  options:
+    requirements-file: requirements.yml
 driver:
   name: delegated
 lint: |
@@ -27,6 +29,7 @@ provisioner:
         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_image: testing-operator
         operator_pull_policy: "Never"
@@ -35,6 +38,18 @@ provisioner:
   env:
     K8S_AUTH_KUBECONFIG: ${MOLECULE_EPHEMERAL_DIRECTORY}/kubeconfig
     KUBECONFIG: ${MOLECULE_EPHEMERAL_DIRECTORY}/kubeconfig
+scenario:
+  name: kind
+  test_sequence:
+    # - lint
+    - destroy
+    - dependency
+    - syntax
+    - create
+    - prepare
+    - converge
+    - verify
+    - destroy
 verifier:
   name: ansible
   lint: |
diff --git a/operator/molecule/kind/requirements.yml b/operator/molecule/kind/requirements.yml
new file mode 100644
index 0000000..3f626ed
--- /dev/null
+++ b/operator/molecule/kind/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/requirements.yml b/operator/molecule/requirements.yml
new file mode 100644
index 0000000..3f626ed
--- /dev/null
+++ b/operator/molecule/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/roles/koji-lib/library/koji_user.py b/operator/roles/koji-lib/library/koji_user.py
index cc74100..2387dca 100644
--- a/operator/roles/koji-lib/library/koji_user.py
+++ b/operator/roles/koji-lib/library/koji_user.py
@@ -169,7 +169,8 @@ def main():
 
   module.exit_json(changed=True,
     skipped=False,
-    failed=False, result={'username': username, 'perms': session.getUserPerms(user['id'])})
+    failed=False, 
+    result={'username': username, 'perms': session.getUserPerms(user['id'])})
 
 
 if __name__ == '__main__':
diff --git a/operator/roles/kojiuser/README.md b/operator/roles/kojiuser/README.md
new file mode 100644
index 0000000..c37ca91
--- /dev/null
+++ b/operator/roles/kojiuser/README.md
@@ -0,0 +1,43 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance,
+if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in 
+defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables 
+that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set
+for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for
+users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/operator/roles/kojiuser/defaults/main.yml b/operator/roles/kojiuser/defaults/main.yml
new file mode 100644
index 0000000..e7bb418
--- /dev/null
+++ b/operator/roles/kojiuser/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+# defaults file for KojiUser
+koji_user_hub_host: "{{ hub_host | default('koji-hub:8443') }}"
+koji_user_admin_secret: "{{ admin_secret | default('koji-user-admin') }}"
+koji_user_permissions: "{{ permissions | default([]) }}"
+koji_user_authentication: "{{ authentication | default({'ssl': {'client_secret_name': 'koji-sample-user-client-cert', 'ca_secret_name': 'koji-hub-ca-cert'}}) }}"
\ No newline at end of file
diff --git a/operator/roles/kojiuser/files/.placeholder b/operator/roles/kojiuser/files/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/operator/roles/kojiuser/files/.placeholder
diff --git a/operator/roles/kojiuser/handlers/main.yml b/operator/roles/kojiuser/handlers/main.yml
new file mode 100644
index 0000000..afd8dba
--- /dev/null
+++ b/operator/roles/kojiuser/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for KojiUser
diff --git a/operator/roles/kojiuser/meta/main.yml b/operator/roles/kojiuser/meta/main.yml
new file mode 100644
index 0000000..a2634aa
--- /dev/null
+++ b/operator/roles/kojiuser/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+  - role: koji-lib
diff --git a/operator/roles/kojiuser/tasks/main.yml b/operator/roles/kojiuser/tasks/main.yml
new file mode 100644
index 0000000..0e98f22
--- /dev/null
+++ b/operator/roles/kojiuser/tasks/main.yml
@@ -0,0 +1,109 @@
+---
+# tasks file for KojiUser
+- name: create temporary cert directory
+  tempfile:
+    state: directory
+    prefix: kojiuser
+    suffix: cert
+  register: cert_dir
+
+- name: create temporary koji directory
+  tempfile:
+    state: directory
+    prefix: kojiuser
+    suffix: koji
+  register: koji_dir
+
+- name: Check for koji-user client secret existence 
+  k8s_info:
+    api_version: v1
+    kind: Secret
+    name: "{{ koji_user_authentication.ssl.client_secret_name }}"
+    namespace: "{{ meta.namespace }}"
+  register: clientcert_query
+
+- name: Retrieve ca secret
+  block:
+    - k8s_info:
+        api_version: v1
+        kind: Secret
+        name: "{{ koji_user_authentication.ssl.ca_secret_name }}"
+        namespace: "{{ meta.namespace }}"
+      register: k8s_secrets
+    - fail:
+        msg: "Secret {{ koji_user_authentication.ssl.client_secret_name }} not found."
+      when: k8s_secrets.resources|length == 0
+    - set_fact:
+        ca: "{{ k8s_secrets.resources[0] }}"
+    - copy:
+        content: "{{ ca.data.cert | b64decode }}"
+        dest: "{{ cert_dir.path }}/ca_cert.pem"
+    - copy:
+        content: "{{ ca.data.key | b64decode }}"
+        dest: "{{ cert_dir.path }}/ca_key.pem"
+      when: clientcert_query.resources|length == 0
+    - copy:
+        content: "{{ ca.data.cert | b64decode }}"
+        dest: "{{ koji_dir.path }}/ca.pem"
+
+- name: Client certificate creation
+  block:
+    - openssl_privatekey:
+        path: "{{ cert_dir.path }}/client_key.pem"
+        size: 4096
+    - openssl_csr:
+        path: "{{ cert_dir.path }}/client_req.pem"
+        privatekey_path: "{{ cert_dir.path }}/client_key.pem"
+        common_name: "{{ meta.name }}"
+    - openssl_certificate:
+        path: "{{ cert_dir.path }}/client_cert.pem"
+        csr_path: "{{ cert_dir.path }}/client_req.pem"
+        ownca_path: "{{ cert_dir.path }}/ca_cert.pem"
+        ownca_privatekey_path: "{{ cert_dir.path }}/ca_key.pem"
+        provider: ownca
+  when: clientcert_query.resources|length == 0
+
+- name: Kubernetes client certificate secret creation
+  block:
+    - k8s:
+        definition:
+          apiVersion: v1
+          kind: Secret
+          metadata:
+            name: "{{ koji_user_authentication.ssl.client_secret_name }}"
+            namespace: "{{ meta.namespace }}"
+            labels:
+              app: koji-user
+          data:
+            client.pem: "{{ (lookup('file', cert_dir.path + '/client_key.pem') + '\n' + lookup('file', cert_dir.path + '/client_cert.pem')) | b64encode }}"
+  when: clientcert_query.resources|length == 0
+
+- block:
+    - name: setup koji user
+      k8s_info:
+        api_version: v1
+        kind: Secret
+        namespace: "{{ meta.namespace }}"
+        name: "{{ koji_user_admin_secret }}"
+      register: k8s_res
+    - fail:
+        msg: "Secret not found: {{ koji_user_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"
+    - koji_user:
+        server: "https://{{ koji_user_hub_host }}/kojihub"
+        username: "{{ meta.name }}"
+        permissions: "{{ koji_user_permissions }}"
+        ssl_auth:
+          cert: "{{ koji_dir.path }}/admin.pem"
+          serverca: "{{ koji_dir.path }}/ca.pem"
+          verify: false
+
+- name: cleanup
+  file:
+    path: "{{ cert_dir.path }}"
+    state: absent
\ No newline at end of file
diff --git a/operator/roles/kojiuser/templates/.placeholder b/operator/roles/kojiuser/templates/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/operator/roles/kojiuser/templates/.placeholder
diff --git a/operator/roles/kojiuser/vars/main.yml b/operator/roles/kojiuser/vars/main.yml
new file mode 100644
index 0000000..41994c4
--- /dev/null
+++ b/operator/roles/kojiuser/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for KojiUser
diff --git a/operator/watches.yaml b/operator/watches.yaml
index d24e37e..820c4c8 100644
--- a/operator/watches.yaml
+++ b/operator/watches.yaml
@@ -20,4 +20,10 @@
   role: kojira
   vars:
     meta: '{{ ansible_operator_meta }}'
-#+kubebuilder:scaffold:watch
\ No newline at end of file
+- version: v1alpha1
+  group: buildsys.apps.fedoraproject.org
+  kind: KojiUser
+  role: kojiuser
+  vars:
+    meta: '{{ ansible_operator_meta }}'
+#+kubebuilder:scaffold:watch

From 0aebe6008724c312a3c7110ce0638fe0d7acce01 Mon Sep 17 00:00:00 2001
From: Leonardo Rossetti <lrossett@redhat.com>
Date: Aug 31 2021 11:35:09 +0000
Subject: [PATCH 2/4] yadding minikube tests


---

diff --git a/operator/config/testing/kustomization.yaml b/operator/config/testing/kustomization.yaml
index 2e714cb..953fdef 100644
--- a/operator/config/testing/kustomization.yaml
+++ b/operator/config/testing/kustomization.yaml
@@ -20,9 +20,7 @@ resources:
 - ../manager
 images:
 - name: testing
-  newName: quay.io/lrossett/koji-operator
-  newTag: dev7
+  newName: buildsys.apps.fedoraproject.org/koji-operator
+  newTag: testing
 patches:
 - path: pull_policy/Never.yaml
-- path: pull_policy/Always.yaml
-- path: pull_policy/IfNotPresent.yaml
diff --git a/operator/molecule/default/molecule.yml b/operator/molecule/default/molecule.yml
index d3a692d..df6f813 100644
--- a/operator/molecule/default/molecule.yml
+++ b/operator/molecule/default/molecule.yml
@@ -25,7 +25,7 @@ provisioner:
         config_dir: ${MOLECULE_PROJECT_DIRECTORY}/config
         samples_dir: ${MOLECULE_PROJECT_DIRECTORY}/config/samples
         components_dir: ${MOLECULE_PROJECT_DIRECTORY}/../components
-        operator_image: ${OPERATOR_IMAGE:-"quay.io/lrossett/koji-operator:dev7"}
+        operator_image: ${OPERATOR_IMAGE:-"quay.io/fedora/koji-operator:latest"}
         operator_pull_policy: ${OPERATOR_PULL_POLICY:-"IfNotPresent"}
         kustomize: ${KUSTOMIZE_PATH:-kustomize}
   env:
diff --git a/operator/molecule/default/verify.yml b/operator/molecule/default/verify.yml
index 7d98c50..6decf47 100644
--- a/operator/molecule/default/verify.yml
+++ b/operator/molecule/default/verify.yml
@@ -15,8 +15,8 @@
           include_tasks: 'tasks/{{ item }}_test.yml'
           with_items:
             - kojihub
-            # - kojibuilder
-            # - kojira
+            - kojibuilder
+            - kojira
             - kojiuser
       rescue:
         - name: Retrieve relevant resources
diff --git a/operator/molecule/minikube/converge.yml b/operator/molecule/minikube/converge.yml
new file mode 100644
index 0000000..1652a6a
--- /dev/null
+++ b/operator/molecule/minikube/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/minikube/create.yml b/operator/molecule/minikube/create.yml
new file mode 100644
index 0000000..d5b3e17
--- /dev/null
+++ b/operator/molecule/minikube/create.yml
@@ -0,0 +1,8 @@
+---
+- name: Create
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  tasks:
+    - name: Start minikube
+      command: minikube start --driver=kvm2
diff --git a/operator/molecule/minikube/destroy.yml b/operator/molecule/minikube/destroy.yml
new file mode 100644
index 0000000..271e462
--- /dev/null
+++ b/operator/molecule/minikube/destroy.yml
@@ -0,0 +1,16 @@
+---
+- name: Destroy
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  collections:
+    - community.kubernetes
+
+  tasks:
+    - name: Destroy minikube
+      command: minikube delete
+
+    - 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/minikube/molecule.yml b/operator/molecule/minikube/molecule.yml
new file mode 100644
index 0000000..a8fc5b5
--- /dev/null
+++ b/operator/molecule/minikube/molecule.yml
@@ -0,0 +1,55 @@
+---
+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}
+        minikube_drriver: kvm2
+scenario:
+  name: minikube
+  test_sequence:
+    # - lint
+    - destroy
+    - dependency
+    - syntax
+    - create
+    - prepare
+    - converge
+    - verify
+    - destroy
+verifier:
+  name: ansible
+  lint: |
+    set -e
+    ansible-lint
diff --git a/operator/molecule/minikube/requirements.yml b/operator/molecule/minikube/requirements.yml
new file mode 100644
index 0000000..3f626ed
--- /dev/null
+++ b/operator/molecule/minikube/requirements.yml
@@ -0,0 +1,6 @@
+---
+collections:
+  - name: community.kubernetes
+    version: "1.2.1"
+  - name: operator_sdk.util
+    version: "0.2.0"

From 3188c8d84d41f39e2167cef7791eb3de05ab3255 Mon Sep 17 00:00:00 2001
From: Leonardo Rossetti <lrossett@redhat.com>
Date: Aug 31 2021 14:53:48 +0000
Subject: [PATCH 3/4] koji user sql test


---

diff --git a/operator/molecule/default/tasks/kojiuser_test.yml b/operator/molecule/default/tasks/kojiuser_test.yml
index b9931b2..b88c91d 100644
--- a/operator/molecule/default/tasks/kojiuser_test.yml
+++ b/operator/molecule/default/tasks/kojiuser_test.yml
@@ -25,4 +25,15 @@
         that:
           - kojiuser_client_secrets.resources|length == 1
           - kojiuser_client_secrets.resources[0].metadata.labels['app'] == 'koji-user'
-          - "'client.pem' in kojiuser_client_secrets.resources[0].data"
\ No newline at end of file
+          - "'client.pem' in kojiuser_client_secrets.resources[0].data"
+
+- block:
+    - name: 'TEST: kojiuser.database'
+      command: "kubectl get po --selector='app=postgres' -o jsonpath='{.items[0].metadata.name}'  -n {{ namespace }}"
+      register: k8s_pod
+    - command: "kubectl exec -it {{ k8s_pod.stdout  }} -n {{ namespace }} -- psql --username koji koji -c 'SELECT name FROM users;'"
+      register: psql_users
+    - assert:
+        that:
+          - "'sample' in psql_users.stdout"
+

From 9ae45fbca7969d79f59c04f429ae6c07e780df01 Mon Sep 17 00:00:00 2001
From: Steve Loranz <steveloranz@users.noreply.github.com>
Date: Sep 02 2021 15:46:37 +0000
Subject: [PATCH 4/4] use variable substitution for selecting driver


Set environment variable MINIKUBE_DRIVER to what is appropriate for your platform / environment.

---

diff --git a/operator/molecule/minikube/create.yml b/operator/molecule/minikube/create.yml
index d5b3e17..277cfc8 100644
--- a/operator/molecule/minikube/create.yml
+++ b/operator/molecule/minikube/create.yml
@@ -5,4 +5,4 @@
   gather_facts: false
   tasks:
     - name: Start minikube
-      command: minikube start --driver=kvm2
+      command: minikube start --driver={{ minikube_driver }}
diff --git a/operator/molecule/minikube/molecule.yml b/operator/molecule/minikube/molecule.yml
index a8fc5b5..2b34fa5 100644
--- a/operator/molecule/minikube/molecule.yml
+++ b/operator/molecule/minikube/molecule.yml
@@ -35,7 +35,7 @@ provisioner:
         project_dir: ${MOLECULE_PROJECT_DIRECTORY}
         operator_pull_policy: "Never"
         kustomize: ${KUSTOMIZE_PATH:-kustomize}
-        minikube_drriver: kvm2
+        minikube_driver: ${MINIKUBE_DRIVER:-kvm2}
 scenario:
   name: minikube
   test_sequence:

