From 1001e759579ee0c022a1efc8fc4e7a08a911f490 Mon Sep 17 00:00:00 2001
From: Lenka Segura <lsegura@redhat.com>
Date: Jan 24 2023 15:29:23 +0000
Subject: Create structure with operator-sdk init


---

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..62fd3e3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+bin
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..0b517f8
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,9 @@
+FROM quay.io/operator-framework/ansible-operator:v1.23.0
+
+COPY requirements.yml ${HOME}/requirements.yml
+RUN ansible-galaxy collection install -r ${HOME}/requirements.yml \
+ && chmod -R ug+rwx ${HOME}/.ansible
+
+COPY watches.yaml ${HOME}/watches.yaml
+COPY roles/ ${HOME}/roles/
+COPY playbooks/ ${HOME}/playbooks/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f24905f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,193 @@
+# VERSION defines the project version for the bundle.
+# Update this value when you upgrade the version of your project.
+# To re-generate a bundle for another specific version without changing the standard setup, you can:
+# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
+# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
+VERSION ?= 0.0.1
+
+# CHANNELS define the bundle channels used in the bundle.
+# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
+# To re-generate a bundle for other specific channels without changing the standard setup, you can:
+# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable)
+# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable")
+ifneq ($(origin CHANNELS), undefined)
+BUNDLE_CHANNELS := --channels=$(CHANNELS)
+endif
+
+# DEFAULT_CHANNEL defines the default channel used in the bundle.
+# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable")
+# To re-generate a bundle for any other default channel without changing the default setup, you can:
+# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable)
+# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable")
+ifneq ($(origin DEFAULT_CHANNEL), undefined)
+BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
+endif
+BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
+
+# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
+# This variable is used to construct full image tags for bundle and catalog images.
+#
+# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
+# fas2discourse.apps.fedoraproject.org/fas2discourse-bundle:$VERSION and fas2discourse.apps.fedoraproject.org/fas2discourse-catalog:$VERSION.
+IMAGE_TAG_BASE ?= fas2discourse.apps.fedoraproject.org/fas2discourse
+
+# BUNDLE_IMG defines the image:tag used for the bundle.
+# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
+BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)
+
+# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
+BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
+
+# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests
+# You can enable this value if you would like to use SHA Based Digests
+# To enable set flag to true
+USE_IMAGE_DIGESTS ?= false
+ifeq ($(USE_IMAGE_DIGESTS), true)
+	BUNDLE_GEN_FLAGS += --use-image-digests
+endif
+
+# Image URL to use all building/pushing image targets
+IMG ?= controller:latest
+
+.PHONY: all
+all: docker-build
+
+##@ General
+
+# The help target prints out all targets with their descriptions organized
+# beneath their categories. The categories are represented by '##@' and the
+# target descriptions by '##'. The awk commands is responsible for reading the
+# entire set of makefiles included in this invocation, looking for lines of the
+# file as xyz: ## something, and then pretty-format the target and help. Then,
+# if there's a line with ##@ something, that gets pretty-printed as a category.
+# More info on the usage of ANSI control characters for terminal formatting:
+# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
+# More info on the awk command:
+# http://linuxcommand.org/lc3_adv_awk.php
+
+.PHONY: help
+help: ## Display this help.
+	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+##@ Build
+
+.PHONY: run
+run: ansible-operator ## Run against the configured Kubernetes cluster in ~/.kube/config
+	ANSIBLE_ROLES_PATH="$(ANSIBLE_ROLES_PATH):$(shell pwd)/roles" $(ANSIBLE_OPERATOR) run
+
+.PHONY: docker-build
+docker-build: ## Build docker image with the manager.
+	docker build -t ${IMG} .
+
+.PHONY: docker-push
+docker-push: ## Push docker image with the manager.
+	docker push ${IMG}
+
+##@ Deployment
+
+.PHONY: install
+install: kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
+	$(KUSTOMIZE) build config/crd | kubectl apply -f -
+
+.PHONY: uninstall
+uninstall: kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config.
+	$(KUSTOMIZE) build config/crd | kubectl delete -f -
+
+.PHONY: deploy
+deploy: kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
+	cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
+	$(KUSTOMIZE) build config/default | kubectl apply -f -
+
+.PHONY: undeploy
+undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config.
+	$(KUSTOMIZE) build config/default | kubectl delete -f -
+
+OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
+ARCH := $(shell uname -m | sed 's/x86_64/amd64/')
+
+.PHONY: kustomize
+KUSTOMIZE = $(shell pwd)/bin/kustomize
+kustomize: ## Download kustomize locally if necessary.
+ifeq (,$(wildcard $(KUSTOMIZE)))
+ifeq (,$(shell which kustomize 2>/dev/null))
+	@{ \
+	set -e ;\
+	mkdir -p $(dir $(KUSTOMIZE)) ;\
+	curl -sSLo - https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v4.5.5/kustomize_v4.5.5_$(OS)_$(ARCH).tar.gz | \
+	tar xzf - -C bin/ ;\
+	}
+else
+KUSTOMIZE = $(shell which kustomize)
+endif
+endif
+
+.PHONY: ansible-operator
+ANSIBLE_OPERATOR = $(shell pwd)/bin/ansible-operator
+ansible-operator: ## Download ansible-operator locally if necessary, preferring the $(pwd)/bin path over global if both exist.
+ifeq (,$(wildcard $(ANSIBLE_OPERATOR)))
+ifeq (,$(shell which ansible-operator 2>/dev/null))
+	@{ \
+	set -e ;\
+	mkdir -p $(dir $(ANSIBLE_OPERATOR)) ;\
+	curl -sSLo $(ANSIBLE_OPERATOR) https://github.com/operator-framework/operator-sdk/releases/download/v1.23.0/ansible-operator_$(OS)_$(ARCH) ;\
+	chmod +x $(ANSIBLE_OPERATOR) ;\
+	}
+else
+ANSIBLE_OPERATOR = $(shell which ansible-operator)
+endif
+endif
+
+.PHONY: bundle
+bundle: kustomize ## Generate bundle manifests and metadata, then validate generated files.
+	operator-sdk generate kustomize manifests -q
+	cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
+	$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
+	operator-sdk bundle validate ./bundle
+
+.PHONY: bundle-build
+bundle-build: ## Build the bundle image.
+	docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .
+
+.PHONY: bundle-push
+bundle-push: ## Push the bundle image.
+	$(MAKE) docker-push IMG=$(BUNDLE_IMG)
+
+.PHONY: opm
+OPM = ./bin/opm
+opm: ## Download opm locally if necessary.
+ifeq (,$(wildcard $(OPM)))
+ifeq (,$(shell which opm 2>/dev/null))
+	@{ \
+	set -e ;\
+	mkdir -p $(dir $(OPM)) ;\
+	curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$(OS)-$(ARCH)-opm ;\
+	chmod +x $(OPM) ;\
+	}
+else
+OPM = $(shell which opm)
+endif
+endif
+
+# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0).
+# These images MUST exist in a registry and be pull-able.
+BUNDLE_IMGS ?= $(BUNDLE_IMG)
+
+# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0).
+CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION)
+
+# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image.
+ifneq ($(origin CATALOG_BASE_IMG), undefined)
+FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG)
+endif
+
+# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'.
+# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see:
+# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator
+.PHONY: catalog-build
+catalog-build: opm ## Build a catalog image.
+	$(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT)
+
+# Push the catalog image.
+.PHONY: catalog-push
+catalog-push: ## Push a catalog image.
+	$(MAKE) docker-push IMG=$(CATALOG_IMG)
diff --git a/PROJECT b/PROJECT
new file mode 100644
index 0000000..81d5b82
--- /dev/null
+++ b/PROJECT
@@ -0,0 +1,15 @@
+domain: fas2discourse.apps.fedoraproject.org
+layout:
+- ansible.sdk.operatorframework.io/v1
+plugins:
+  manifests.sdk.operatorframework.io/v2: {}
+  scorecard.sdk.operatorframework.io/v2: {}
+projectName: fas2discourse
+resources:
+- api:
+    crdVersion: v1
+    namespaced: true
+  domain: fas2discourse.apps.fedoraproject.org
+  kind: Fas2discourseConfig
+  version: v1alpha1
+version: "3"
diff --git a/config/crd/bases/fas2discourse.apps.fedoraproject.org_fas2discourseconfigs.yaml b/config/crd/bases/fas2discourse.apps.fedoraproject.org_fas2discourseconfigs.yaml
new file mode 100644
index 0000000..b4bb4cb
--- /dev/null
+++ b/config/crd/bases/fas2discourse.apps.fedoraproject.org_fas2discourseconfigs.yaml
@@ -0,0 +1,44 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: fas2discourseconfigs.fas2discourse.apps.fedoraproject.org
+spec:
+  group: fas2discourse.apps.fedoraproject.org
+  names:
+    kind: Fas2discourseConfig
+    listKind: Fas2discourseConfigList
+    plural: fas2discourseconfigs
+    singular: fas2discourseconfig
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: Fas2discourseConfig is the Schema for the fas2discourseconfigs 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 Fas2discourseConfig
+            type: object
+            x-kubernetes-preserve-unknown-fields: true
+          status:
+            description: Status defines the observed state of Fas2discourseConfig
+            type: object
+            x-kubernetes-preserve-unknown-fields: true
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
new file mode 100644
index 0000000..60aeeb8
--- /dev/null
+++ b/config/crd/kustomization.yaml
@@ -0,0 +1,6 @@
+# This kustomization.yaml is not intended to be run by itself,
+# since it depends on service name and namespace that are out of this kustomize package.
+# It should be run by config/default
+resources:
+- bases/fas2discourse.apps.fedoraproject.org_fas2discourseconfigs.yaml
+#+kubebuilder:scaffold:crdkustomizeresource
diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml
new file mode 100644
index 0000000..636d408
--- /dev/null
+++ b/config/default/kustomization.yaml
@@ -0,0 +1,32 @@
+# Adds namespace to all resources.
+namespace: fas2discourse-system
+
+# Value of this field is prepended to the
+# names of all resources, e.g. a deployment named
+# "wordpress" becomes "alices-wordpress".
+# Note that it should also match with the prefix (text before '-') of the namespace
+# field above.
+namePrefix: fas2discourse-
+
+# Labels to add to all resources and selectors.
+#labels:
+#- includeSelectors: true
+#  pairs:
+#    someName: someValue
+
+resources:
+- ../crd
+- ../rbac
+- ../manager
+# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
+#- ../prometheus
+
+patchesStrategicMerge:
+# Protect the /metrics endpoint by putting it behind auth.
+# If you want your controller-manager to expose the /metrics
+# endpoint w/o any authn/z, please comment the following line.
+- manager_auth_proxy_patch.yaml
+
+# Mount the controller config file for loading manager configurations
+# through a ComponentConfig type
+#- manager_config_patch.yaml
diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml
new file mode 100644
index 0000000..bde915e
--- /dev/null
+++ b/config/default/manager_auth_proxy_patch.yaml
@@ -0,0 +1,40 @@
+# This patch inject a sidecar container which is a HTTP proxy for the
+# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+      - name: kube-rbac-proxy
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+              - "ALL"
+        image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.0
+        args:
+        - "--secure-listen-address=0.0.0.0:8443"
+        - "--upstream=http://127.0.0.1:8080/"
+        - "--logtostderr=true"
+        - "--v=0"
+        ports:
+        - containerPort: 8443
+          protocol: TCP
+          name: https
+        resources:
+          limits:
+            cpu: 500m
+            memory: 128Mi
+          requests:
+            cpu: 5m
+            memory: 64Mi
+      - name: manager
+        args:
+        - "--health-probe-bind-address=:6789"
+        - "--metrics-bind-address=127.0.0.1:8080"
+        - "--leader-elect"
+        - "--leader-election-id=fas2discourse"
diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml
new file mode 100644
index 0000000..6c40015
--- /dev/null
+++ b/config/default/manager_config_patch.yaml
@@ -0,0 +1,20 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+      - name: manager
+        args:
+        - "--config=controller_manager_config.yaml"
+        volumeMounts:
+        - name: manager-config
+          mountPath: /controller_manager_config.yaml
+          subPath: controller_manager_config.yaml
+      volumes:
+      - name: manager-config
+        configMap:
+          name: manager-config
diff --git a/config/manager/controller_manager_config.yaml b/config/manager/controller_manager_config.yaml
new file mode 100644
index 0000000..6318062
--- /dev/null
+++ b/config/manager/controller_manager_config.yaml
@@ -0,0 +1,20 @@
+apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
+kind: ControllerManagerConfig
+health:
+  healthProbeBindAddress: :6789
+metrics:
+  bindAddress: 127.0.0.1:8080
+
+leaderElection:
+  leaderElect: true
+  resourceName: 811c9dc5.fas2discourse.apps.fedoraproject.org
+# leaderElectionReleaseOnCancel defines if the leader should step down volume
+# when the Manager ends. This requires the binary to immediately end when the
+# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
+# speeds up voluntary leader transitions as the new leader don't have to wait
+# LeaseDuration time first.
+# In the default scaffold provided, the program ends immediately after
+# the manager stops, so would be fine to enable this option. However,
+# if you are doing or is intended to do any operation such as perform cleanups
+# after the manager stops then its usage might be unsafe.
+# leaderElectionReleaseOnCancel: true
diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml
new file mode 100644
index 0000000..2bcd3ee
--- /dev/null
+++ b/config/manager/kustomization.yaml
@@ -0,0 +1,10 @@
+resources:
+- manager.yaml
+
+generatorOptions:
+  disableNameSuffixHash: true
+
+configMapGenerator:
+- name: manager-config
+  files:
+  - controller_manager_config.yaml
diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml
new file mode 100644
index 0000000..3e39884
--- /dev/null
+++ b/config/manager/manager.yaml
@@ -0,0 +1,72 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  labels:
+    control-plane: controller-manager
+  name: system
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+  labels:
+    control-plane: controller-manager
+spec:
+  selector:
+    matchLabels:
+      control-plane: controller-manager
+  replicas: 1
+  template:
+    metadata:
+      annotations:
+        kubectl.kubernetes.io/default-container: manager
+      labels:
+        control-plane: controller-manager
+    spec:
+      securityContext:
+        runAsNonRoot: true
+        # TODO(user): For common cases that do not require escalating privileges
+        # it is recommended to ensure that all your Pods/Containers are restrictive.
+        # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
+        # Please uncomment the following code if your project does NOT have to work on old Kubernetes
+        # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ).
+        # seccompProfile:
+        #   type: RuntimeDefault
+      containers:
+      - args:
+        - --leader-elect
+        - --leader-election-id=fas2discourse
+        image: controller:latest
+        name: manager
+        env:
+        - name: ANSIBLE_GATHERING
+          value: explicit
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+              - "ALL"
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 6789
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 6789
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        # TODO(user): Configure the resources accordingly based on the project requirements.
+        # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+        resources:
+          limits:
+            cpu: 500m
+            memory: 768Mi
+          requests:
+            cpu: 10m
+            memory: 256Mi
+      serviceAccountName: controller-manager
+      terminationGracePeriodSeconds: 10
diff --git a/config/manifests/kustomization.yaml b/config/manifests/kustomization.yaml
new file mode 100644
index 0000000..c94c833
--- /dev/null
+++ b/config/manifests/kustomization.yaml
@@ -0,0 +1,7 @@
+# These resources constitute the fully configured set of manifests
+# used to generate the 'manifests/' directory in a bundle.
+resources:
+- bases/fas2discourse.clusterserviceversion.yaml
+- ../default
+- ../samples
+- ../scorecard
diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml
new file mode 100644
index 0000000..ed13716
--- /dev/null
+++ b/config/prometheus/kustomization.yaml
@@ -0,0 +1,2 @@
+resources:
+- monitor.yaml
diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml
new file mode 100644
index 0000000..d19136a
--- /dev/null
+++ b/config/prometheus/monitor.yaml
@@ -0,0 +1,20 @@
+
+# Prometheus Monitor Service (Metrics)
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  labels:
+    control-plane: controller-manager
+  name: controller-manager-metrics-monitor
+  namespace: system
+spec:
+  endpoints:
+    - path: /metrics
+      port: https
+      scheme: https
+      bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+      tlsConfig:
+        insecureSkipVerify: true
+  selector:
+    matchLabels:
+      control-plane: controller-manager
diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml
new file mode 100644
index 0000000..51a75db
--- /dev/null
+++ b/config/rbac/auth_proxy_client_clusterrole.yaml
@@ -0,0 +1,9 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: metrics-reader
+rules:
+- nonResourceURLs:
+  - "/metrics"
+  verbs:
+  - get
diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml
new file mode 100644
index 0000000..80e1857
--- /dev/null
+++ b/config/rbac/auth_proxy_role.yaml
@@ -0,0 +1,17 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: proxy-role
+rules:
+- apiGroups:
+  - authentication.k8s.io
+  resources:
+  - tokenreviews
+  verbs:
+  - create
+- apiGroups:
+  - authorization.k8s.io
+  resources:
+  - subjectaccessreviews
+  verbs:
+  - create
diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml
new file mode 100644
index 0000000..ec7acc0
--- /dev/null
+++ b/config/rbac/auth_proxy_role_binding.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: proxy-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: proxy-role
+subjects:
+- kind: ServiceAccount
+  name: controller-manager
+  namespace: system
diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml
new file mode 100644
index 0000000..71f1797
--- /dev/null
+++ b/config/rbac/auth_proxy_service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    control-plane: controller-manager
+  name: controller-manager-metrics-service
+  namespace: system
+spec:
+  ports:
+  - name: https
+    port: 8443
+    protocol: TCP
+    targetPort: https
+  selector:
+    control-plane: controller-manager
diff --git a/config/rbac/fas2discourseconfig_editor_role.yaml b/config/rbac/fas2discourseconfig_editor_role.yaml
new file mode 100644
index 0000000..90b261c
--- /dev/null
+++ b/config/rbac/fas2discourseconfig_editor_role.yaml
@@ -0,0 +1,24 @@
+# permissions for end users to edit fas2discourseconfigs.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: fas2discourseconfig-editor-role
+rules:
+- apiGroups:
+  - fas2discourse.apps.fedoraproject.org
+  resources:
+  - fas2discourseconfigs
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - fas2discourse.apps.fedoraproject.org
+  resources:
+  - fas2discourseconfigs/status
+  verbs:
+  - get
diff --git a/config/rbac/fas2discourseconfig_viewer_role.yaml b/config/rbac/fas2discourseconfig_viewer_role.yaml
new file mode 100644
index 0000000..1486de9
--- /dev/null
+++ b/config/rbac/fas2discourseconfig_viewer_role.yaml
@@ -0,0 +1,20 @@
+# permissions for end users to view fas2discourseconfigs.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: fas2discourseconfig-viewer-role
+rules:
+- apiGroups:
+  - fas2discourse.apps.fedoraproject.org
+  resources:
+  - fas2discourseconfigs
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - fas2discourse.apps.fedoraproject.org
+  resources:
+  - fas2discourseconfigs/status
+  verbs:
+  - get
diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml
new file mode 100644
index 0000000..731832a
--- /dev/null
+++ b/config/rbac/kustomization.yaml
@@ -0,0 +1,18 @@
+resources:
+# All RBAC will be applied under this service account in
+# the deployment namespace. You may comment out this resource
+# if your manager will use a service account that exists at
+# runtime. Be sure to update RoleBinding and ClusterRoleBinding
+# subjects if changing service account names.
+- service_account.yaml
+- role.yaml
+- role_binding.yaml
+- leader_election_role.yaml
+- leader_election_role_binding.yaml
+# Comment the following 4 lines if you want to disable
+# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
+# which protects your /metrics endpoint.
+- auth_proxy_service.yaml
+- auth_proxy_role.yaml
+- auth_proxy_role_binding.yaml
+- auth_proxy_client_clusterrole.yaml
diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml
new file mode 100644
index 0000000..4190ec8
--- /dev/null
+++ b/config/rbac/leader_election_role.yaml
@@ -0,0 +1,37 @@
+# permissions to do leader election.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: leader-election-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml
new file mode 100644
index 0000000..1d1321e
--- /dev/null
+++ b/config/rbac/leader_election_role_binding.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: leader-election-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: leader-election-role
+subjects:
+- kind: ServiceAccount
+  name: controller-manager
+  namespace: system
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
new file mode 100644
index 0000000..ab8dc25
--- /dev/null
+++ b/config/rbac/role.yaml
@@ -0,0 +1,57 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: manager-role
+rules:
+  ##
+  ## Base operator rules
+  ##
+  - apiGroups:
+      - ""
+    resources:
+      - secrets
+      - pods
+      - pods/exec
+      - pods/log
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
+  - apiGroups:
+      - apps
+    resources:
+      - deployments
+      - daemonsets
+      - replicasets
+      - statefulsets
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
+  ##
+  ## Rules for fas2discourse.apps.fedoraproject.org/v1alpha1, Kind: Fas2discourseConfig
+  ##
+  - apiGroups:
+      - fas2discourse.apps.fedoraproject.org
+    resources:
+      - fas2discourseconfigs
+      - fas2discourseconfigs/status
+      - fas2discourseconfigs/finalizers
+    verbs:
+      - create
+      - delete
+      - get
+      - list
+      - patch
+      - update
+      - watch
+#+kubebuilder:scaffold:rules
diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml
new file mode 100644
index 0000000..2070ede
--- /dev/null
+++ b/config/rbac/role_binding.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: manager-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: manager-role
+subjects:
+- kind: ServiceAccount
+  name: controller-manager
+  namespace: system
diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml
new file mode 100644
index 0000000..7cd6025
--- /dev/null
+++ b/config/rbac/service_account.yaml
@@ -0,0 +1,5 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: controller-manager
+  namespace: system
diff --git a/config/samples/_v1alpha1_fas2discourseconfig.yaml b/config/samples/_v1alpha1_fas2discourseconfig.yaml
new file mode 100644
index 0000000..e03066e
--- /dev/null
+++ b/config/samples/_v1alpha1_fas2discourseconfig.yaml
@@ -0,0 +1,6 @@
+apiVersion: fas2discourse.apps.fedoraproject.org/v1alpha1
+kind: Fas2discourseConfig
+metadata:
+  name: fas2discourseconfig-sample
+spec:
+  # TODO(user): Add fields here
diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml
new file mode 100644
index 0000000..ae22707
--- /dev/null
+++ b/config/samples/kustomization.yaml
@@ -0,0 +1,4 @@
+## Append samples you want in your CSV to this file as resources ##
+resources:
+- _v1alpha1_fas2discourseconfig.yaml
+#+kubebuilder:scaffold:manifestskustomizesamples
diff --git a/config/scorecard/bases/config.yaml b/config/scorecard/bases/config.yaml
new file mode 100644
index 0000000..c770478
--- /dev/null
+++ b/config/scorecard/bases/config.yaml
@@ -0,0 +1,7 @@
+apiVersion: scorecard.operatorframework.io/v1alpha3
+kind: Configuration
+metadata:
+  name: config
+stages:
+- parallel: true
+  tests: []
diff --git a/config/scorecard/kustomization.yaml b/config/scorecard/kustomization.yaml
new file mode 100644
index 0000000..50cd2d0
--- /dev/null
+++ b/config/scorecard/kustomization.yaml
@@ -0,0 +1,16 @@
+resources:
+- bases/config.yaml
+patchesJson6902:
+- path: patches/basic.config.yaml
+  target:
+    group: scorecard.operatorframework.io
+    version: v1alpha3
+    kind: Configuration
+    name: config
+- path: patches/olm.config.yaml
+  target:
+    group: scorecard.operatorframework.io
+    version: v1alpha3
+    kind: Configuration
+    name: config
+#+kubebuilder:scaffold:patchesJson6902
diff --git a/config/scorecard/patches/basic.config.yaml b/config/scorecard/patches/basic.config.yaml
new file mode 100644
index 0000000..90f7ef7
--- /dev/null
+++ b/config/scorecard/patches/basic.config.yaml
@@ -0,0 +1,10 @@
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - basic-check-spec
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: basic
+      test: basic-check-spec-test
diff --git a/config/scorecard/patches/olm.config.yaml b/config/scorecard/patches/olm.config.yaml
new file mode 100644
index 0000000..b55840e
--- /dev/null
+++ b/config/scorecard/patches/olm.config.yaml
@@ -0,0 +1,50 @@
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - olm-bundle-validation
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: olm
+      test: olm-bundle-validation-test
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - olm-crds-have-validation
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: olm
+      test: olm-crds-have-validation-test
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - olm-crds-have-resources
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: olm
+      test: olm-crds-have-resources-test
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - olm-spec-descriptors
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: olm
+      test: olm-spec-descriptors-test
+- op: add
+  path: /stages/0/tests/-
+  value:
+    entrypoint:
+    - scorecard-test
+    - olm-status-descriptors
+    image: quay.io/operator-framework/scorecard-test:v1.23.0
+    labels:
+      suite: olm
+      test: olm-status-descriptors-test
diff --git a/config/testing/debug_logs_patch.yaml b/config/testing/debug_logs_patch.yaml
new file mode 100644
index 0000000..3fb3d55
--- /dev/null
+++ b/config/testing/debug_logs_patch.yaml
@@ -0,0 +1,14 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+        - name: manager
+          env:
+          - name: ANSIBLE_DEBUG_LOGS
+            value: "TRUE"
diff --git a/config/testing/kustomization.yaml b/config/testing/kustomization.yaml
new file mode 100644
index 0000000..4109162
--- /dev/null
+++ b/config/testing/kustomization.yaml
@@ -0,0 +1,23 @@
+# Adds namespace to all resources.
+namespace: osdk-test
+
+namePrefix: osdk-
+
+# Labels to add to all resources and selectors.
+#commonLabels:
+#  someName: someValue
+
+patchesStrategicMerge:
+- manager_image.yaml
+- debug_logs_patch.yaml
+- ../default/manager_auth_proxy_patch.yaml
+
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+- ../crd
+- ../rbac
+- ../manager
+images:
+- name: testing
+  newName: testing-operator
diff --git a/config/testing/manager_image.yaml b/config/testing/manager_image.yaml
new file mode 100644
index 0000000..e44f542
--- /dev/null
+++ b/config/testing/manager_image.yaml
@@ -0,0 +1,12 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+        - name: manager
+          image: testing
diff --git a/config/testing/pull_policy/Always.yaml b/config/testing/pull_policy/Always.yaml
new file mode 100644
index 0000000..6b0a8e2
--- /dev/null
+++ b/config/testing/pull_policy/Always.yaml
@@ -0,0 +1,12 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+        - name: manager
+          imagePullPolicy: Always
diff --git a/config/testing/pull_policy/IfNotPresent.yaml b/config/testing/pull_policy/IfNotPresent.yaml
new file mode 100644
index 0000000..2f52f49
--- /dev/null
+++ b/config/testing/pull_policy/IfNotPresent.yaml
@@ -0,0 +1,12 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+        - name: manager
+          imagePullPolicy: IfNotPresent
diff --git a/config/testing/pull_policy/Never.yaml b/config/testing/pull_policy/Never.yaml
new file mode 100644
index 0000000..86f13d8
--- /dev/null
+++ b/config/testing/pull_policy/Never.yaml
@@ -0,0 +1,12 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller-manager
+  namespace: system
+spec:
+  template:
+    spec:
+      containers:
+        - name: manager
+          imagePullPolicy: Never
diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml
new file mode 100644
index 0000000..9e65e37
--- /dev/null
+++ b/molecule/default/converge.yml
@@ -0,0 +1,18 @@
+---
+- name: Converge
+  hosts: localhost
+  connection: local
+  gather_facts: no
+  collections:
+    - kubernetes.core
+
+  tasks:
+    - name: Create Namespace
+      k8s:
+        api_version: v1
+        kind: Namespace
+        name: '{{ namespace }}'
+
+    - import_tasks: kustomize.yml
+      vars:
+        state: present
diff --git a/molecule/default/create.yml b/molecule/default/create.yml
new file mode 100644
index 0000000..1eeaf92
--- /dev/null
+++ b/molecule/default/create.yml
@@ -0,0 +1,6 @@
+---
+- name: Create
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  tasks: []
diff --git a/molecule/default/destroy.yml b/molecule/default/destroy.yml
new file mode 100644
index 0000000..9a41e7d
--- /dev/null
+++ b/molecule/default/destroy.yml
@@ -0,0 +1,24 @@
+---
+- name: Destroy
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  collections:
+    - kubernetes.core
+
+  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/molecule/default/kustomize.yml b/molecule/default/kustomize.yml
new file mode 100644
index 0000000..5c801d6
--- /dev/null
+++ b/molecule/default/kustomize.yml
@@ -0,0 +1,22 @@
+---
+- name: Build kustomize testing overlay
+  # load_restrictor must be set to none so we can load patch files from the default overlay
+  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: no
+  loop: '{{ resources.stdout | from_yaml_all | list }}'
+
+- name: Wait for resources to get to {{ state }}
+  k8s:
+    definition: '{{ item }}'
+    state: '{{ state }}'
+    wait: yes
+  loop: '{{ resources.stdout | from_yaml_all | list }}'
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
new file mode 100644
index 0000000..ea58004
--- /dev/null
+++ b/molecule/default/molecule.yml
@@ -0,0 +1,36 @@
+---
+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/molecule/default/prepare.yml b/molecule/default/prepare.yml
new file mode 100644
index 0000000..ed40370
--- /dev/null
+++ b/molecule/default/prepare.yml
@@ -0,0 +1,28 @@
+---
+- 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 --path 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/molecule/default/tasks/fas2discourseconfig_test.yml b/molecule/default/tasks/fas2discourseconfig_test.yml
new file mode 100644
index 0000000..1e31dff
--- /dev/null
+++ b/molecule/default/tasks/fas2discourseconfig_test.yml
@@ -0,0 +1,18 @@
+---
+- name: Create the fas2discourse.apps.fedoraproject.org/v1alpha1.Fas2discourseConfig
+  k8s:
+    state: present
+    namespace: '{{ namespace }}'
+    definition: "{{ lookup('template', '/'.join([samples_dir, cr_file])) | from_yaml }}"
+    wait: yes
+    wait_timeout: 300
+    wait_condition:
+      type: Successful
+      status: "True"
+  vars:
+    cr_file: '_v1alpha1_fas2discourseconfig.yaml'
+
+- name: Add assertions here
+  assert:
+    that: false
+    fail_msg: FIXME Add real assertions for your operator
diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml
new file mode 100644
index 0000000..15f3674
--- /dev/null
+++ b/molecule/default/verify.yml
@@ -0,0 +1,57 @@
+---
+- name: Verify
+  hosts: localhost
+  connection: local
+  gather_facts: no
+  collections:
+    - kubernetes.core
+
+  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 }}'
diff --git a/molecule/kind/converge.yml b/molecule/kind/converge.yml
new file mode 100644
index 0000000..8bd5700
--- /dev/null
+++ b/molecule/kind/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 kind cluster
+      command: kind load docker-image --name osdk-test '{{ operator_image }}'
+      register: result
+      changed_when: '"not yet present" in result.stdout'
+
+- import_playbook: ../default/converge.yml
diff --git a/molecule/kind/create.yml b/molecule/kind/create.yml
new file mode 100644
index 0000000..66a84a1
--- /dev/null
+++ b/molecule/kind/create.yml
@@ -0,0 +1,8 @@
+---
+- name: Create
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  tasks:
+    - name: Create test kind cluster
+      command: kind create cluster --name osdk-test --kubeconfig {{ kubeconfig }}
diff --git a/molecule/kind/destroy.yml b/molecule/kind/destroy.yml
new file mode 100644
index 0000000..304cca2
--- /dev/null
+++ b/molecule/kind/destroy.yml
@@ -0,0 +1,16 @@
+---
+- name: Destroy
+  hosts: localhost
+  connection: local
+  gather_facts: false
+  collections:
+    - kubernetes.core
+
+  tasks:
+    - name: Destroy test kind cluster
+      command: kind delete cluster --name osdk-test --kubeconfig {{ kubeconfig }}
+
+    - name: Unset pull policy
+      command: '{{ kustomize }} edit remove patch pull_policy/{{ operator_pull_policy }}.yaml'
+      args:
+        chdir: '{{ config_dir }}/testing'
diff --git a/molecule/kind/molecule.yml b/molecule/kind/molecule.yml
new file mode 100644
index 0000000..d4361f3
--- /dev/null
+++ b/molecule/kind/molecule.yml
@@ -0,0 +1,42 @@
+---
+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
+  playbooks:
+    prepare: ../default/prepare.yml
+    verify: ../default/verify.yml
+  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
+        project_dir: ${MOLECULE_PROJECT_DIRECTORY}
+        operator_image: testing-operator
+        operator_pull_policy: "Never"
+        kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}"
+        kustomize: ${KUSTOMIZE_PATH:-kustomize}
+  env:
+    K8S_AUTH_KUBECONFIG: ${MOLECULE_EPHEMERAL_DIRECTORY}/kubeconfig
+    KUBECONFIG: ${MOLECULE_EPHEMERAL_DIRECTORY}/kubeconfig
+verifier:
+  name: ansible
+  lint: |
+    set -e
+    ansible-lint
diff --git a/playbooks/.placeholder b/playbooks/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/playbooks/.placeholder
diff --git a/requirements.yml b/requirements.yml
new file mode 100644
index 0000000..b64a6f7
--- /dev/null
+++ b/requirements.yml
@@ -0,0 +1,10 @@
+---
+collections:
+  - name: community.kubernetes
+    version: "2.0.1"
+  - name: operator_sdk.util
+    version: "0.4.0"
+  - name: kubernetes.core
+    version: "2.3.1"
+  - name: cloud.common
+    version: "2.1.1"
diff --git a/roles/.placeholder b/roles/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/roles/.placeholder
diff --git a/roles/fas2discourseconfig/README.md b/roles/fas2discourseconfig/README.md
new file mode 100644
index 0000000..c37ca91
--- /dev/null
+++ b/roles/fas2discourseconfig/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/roles/fas2discourseconfig/defaults/main.yml b/roles/fas2discourseconfig/defaults/main.yml
new file mode 100644
index 0000000..0bc6b5c
--- /dev/null
+++ b/roles/fas2discourseconfig/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for Fas2discourseConfig
diff --git a/roles/fas2discourseconfig/files/.placeholder b/roles/fas2discourseconfig/files/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/roles/fas2discourseconfig/files/.placeholder
diff --git a/roles/fas2discourseconfig/handlers/main.yml b/roles/fas2discourseconfig/handlers/main.yml
new file mode 100644
index 0000000..a9b2b76
--- /dev/null
+++ b/roles/fas2discourseconfig/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for Fas2discourseConfig
diff --git a/roles/fas2discourseconfig/meta/main.yml b/roles/fas2discourseconfig/meta/main.yml
new file mode 100644
index 0000000..dfab20d
--- /dev/null
+++ b/roles/fas2discourseconfig/meta/main.yml
@@ -0,0 +1,64 @@
+---
+galaxy_info:
+  author: your name
+  description: your description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Some suggested licenses:
+  # - BSD (default)
+  # - MIT
+  # - GPLv2
+  # - GPLv3
+  # - Apache
+  # - CC-BY
+  license: license (GPLv2, CC-BY, etc)
+
+  min_ansible_version: 2.9
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  # Optionally specify the branch Galaxy will use when accessing the GitHub
+  # repo for this role. During role install, if no tags are available,
+  # Galaxy will use this branch. During import Galaxy will access files on
+  # this branch. If Travis integration is configured, only notifications for this
+  # branch will be accepted. Otherwise, in all cases, the repo's default branch
+  # (usually master) will be used.
+  #github_branch:
+
+  #
+  # Provide a list of supported platforms, and for each platform a list of versions.
+  # If you don't wish to enumerate all versions for a particular platform, use 'all'.
+  # To view available platforms and versions (or releases), visit:
+  # https://galaxy.ansible.com/api/v1/platforms/
+  #
+  # platforms:
+  # - name: Fedora
+  #   versions:
+  #   - all
+  #   - 25
+  # - name: SomePlatform
+  #   versions:
+  #   - all
+  #   - 1.0
+  #   - 7
+  #   - 99.99
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
+collections:
+- operator_sdk.util
+- kubernetes.core
diff --git a/roles/fas2discourseconfig/tasks/main.yml b/roles/fas2discourseconfig/tasks/main.yml
new file mode 100644
index 0000000..1a10545
--- /dev/null
+++ b/roles/fas2discourseconfig/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for Fas2discourseConfig
diff --git a/roles/fas2discourseconfig/templates/.placeholder b/roles/fas2discourseconfig/templates/.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/roles/fas2discourseconfig/templates/.placeholder
diff --git a/roles/fas2discourseconfig/vars/main.yml b/roles/fas2discourseconfig/vars/main.yml
new file mode 100644
index 0000000..f33f31c
--- /dev/null
+++ b/roles/fas2discourseconfig/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for Fas2discourseConfig
diff --git a/watches.yaml b/watches.yaml
new file mode 100644
index 0000000..7194a4a
--- /dev/null
+++ b/watches.yaml
@@ -0,0 +1,7 @@
+---
+# Use the 'create api' subcommand to add watches to this file.
+- version: v1alpha1
+  group: fas2discourse.apps.fedoraproject.org
+  kind: Fas2discourseConfig
+  role: fas2discourseconfig
+#+kubebuilder:scaffold:watch

