From 80895d628af16f2b0808d721205487e2644f6715 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 30 Oct 2019 12:00:17 -0500 Subject: [PATCH] Initial commit. --- .travis.yml | 9 ++ README.md | 5 + build/Dockerfile | 6 + build/test-framework/Dockerfile | 13 ++ build/test-framework/ansible-test.sh | 7 + deploy/crds/tower_v1alpha1_tower_cr.yaml | 13 ++ deploy/crds/tower_v1alpha1_tower_crd.yaml | 19 +++ deploy/operator.yaml | 46 +++++++ deploy/role.yaml | 62 +++++++++ deploy/role_binding.yaml | 12 ++ deploy/service_account.yaml | 5 + main.yml | 4 + molecule/default/asserts.yml | 27 ++++ molecule/default/molecule.yml | 42 ++++++ molecule/default/playbook.yml | 10 ++ molecule/default/prepare.yml | 35 +++++ molecule/test-cluster/molecule.yml | 43 ++++++ molecule/test-cluster/playbook.yml | 33 +++++ molecule/test-local/molecule.yml | 55 ++++++++ molecule/test-local/playbook.yml | 126 ++++++++++++++++++ molecule/test-local/prepare.yml | 28 ++++ roles/tower/README.md | 32 +++++ roles/tower/defaults/main.yml | 2 + roles/tower/meta/main.yml | 19 +++ roles/tower/tasks/main.yml | 8 ++ .../templates/tower_postgres_secret.yaml.j2 | 8 ++ .../templates/tower_postgres_service.yaml.j2 | 14 ++ .../tower_postgres_statefulset.yaml.j2 | 50 +++++++ watches.yaml | 5 + 29 files changed, 738 insertions(+) create mode 100644 .travis.yml create mode 100644 README.md create mode 100644 build/Dockerfile create mode 100644 build/test-framework/Dockerfile create mode 100644 build/test-framework/ansible-test.sh create mode 100644 deploy/crds/tower_v1alpha1_tower_cr.yaml create mode 100644 deploy/crds/tower_v1alpha1_tower_crd.yaml create mode 100644 deploy/operator.yaml create mode 100644 deploy/role.yaml create mode 100644 deploy/role_binding.yaml create mode 100644 deploy/service_account.yaml create mode 100644 main.yml create mode 100644 molecule/default/asserts.yml create mode 100644 molecule/default/molecule.yml create mode 100644 molecule/default/playbook.yml create mode 100644 molecule/default/prepare.yml create mode 100644 molecule/test-cluster/molecule.yml create mode 100644 molecule/test-cluster/playbook.yml create mode 100644 molecule/test-local/molecule.yml create mode 100644 molecule/test-local/playbook.yml create mode 100644 molecule/test-local/prepare.yml create mode 100644 roles/tower/README.md create mode 100644 roles/tower/defaults/main.yml create mode 100644 roles/tower/meta/main.yml create mode 100644 roles/tower/tasks/main.yml create mode 100644 roles/tower/templates/tower_postgres_secret.yaml.j2 create mode 100644 roles/tower/templates/tower_postgres_service.yaml.j2 create mode 100644 roles/tower/templates/tower_postgres_statefulset.yaml.j2 create mode 100644 watches.yaml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..d17c695b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +sudo: required +services: docker +language: python + +install: + - pip3 install docker molecule openshift jmespath + +script: + - molecule test -s test-local diff --git a/README.md b/README.md new file mode 100644 index 00000000..9372a4be --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Tower Operator + +[![Build Status](https://travis-ci.com/geerlingguy/tower-operator.svg?branch=master)](https://travis-ci.com/geerlingguy/tower-operator) + +A Tower operator for Kubernetes built with Operator SDK. diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 00000000..84b4b7e1 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,6 @@ +FROM quay.io/operator-framework/ansible-operator:v0.10.0 + +COPY watches.yaml ${HOME}/watches.yaml + +COPY main.yml ${HOME}/main.yml +COPY roles/ ${HOME}/roles/ diff --git a/build/test-framework/Dockerfile b/build/test-framework/Dockerfile new file mode 100644 index 00000000..3620882b --- /dev/null +++ b/build/test-framework/Dockerfile @@ -0,0 +1,13 @@ +ARG BASEIMAGE +FROM ${BASEIMAGE} +USER 0 + +RUN yum install -y python-devel gcc libffi-devel +RUN pip install molecule==2.20.1 + +ARG NAMESPACEDMAN +ADD $NAMESPACEDMAN /namespaced.yaml +ADD build/test-framework/ansible-test.sh /ansible-test.sh +RUN chmod +x /ansible-test.sh +USER 1001 +ADD . /opt/ansible/project diff --git a/build/test-framework/ansible-test.sh b/build/test-framework/ansible-test.sh new file mode 100644 index 00000000..9719f260 --- /dev/null +++ b/build/test-framework/ansible-test.sh @@ -0,0 +1,7 @@ +#!/bin/sh +export WATCH_NAMESPACE=${TEST_NAMESPACE} +(/usr/local/bin/entrypoint)& +trap "kill $!" SIGINT SIGTERM EXIT + +cd ${HOME}/project +exec molecule test -s test-cluster diff --git a/deploy/crds/tower_v1alpha1_tower_cr.yaml b/deploy/crds/tower_v1alpha1_tower_cr.yaml new file mode 100644 index 00000000..9c3de1b0 --- /dev/null +++ b/deploy/crds/tower_v1alpha1_tower_cr.yaml @@ -0,0 +1,13 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: Tower +metadata: + name: example-tower + namespace: example-tower +spec: + tower_task_image: awx_task:1.0.0.8 + tower_web_image: awx_web:1.0.0.8 + tower_memcached_image: memcached:alpine + tower_rabbitmq_image: rabbitmq:3 + tower_postgres_pass: awxpass + tower_postgres_image: postgres:9.6 + tower_postgres_storage_request: 8Gi diff --git a/deploy/crds/tower_v1alpha1_tower_crd.yaml b/deploy/crds/tower_v1alpha1_tower_crd.yaml new file mode 100644 index 00000000..2775cae9 --- /dev/null +++ b/deploy/crds/tower_v1alpha1_tower_crd.yaml @@ -0,0 +1,19 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: towers.tower.ansible.com +spec: + group: tower.ansible.com + names: + kind: Tower + listKind: TowerList + plural: towers + singular: tower + scope: Namespaced + subresources: + status: {} + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/deploy/operator.yaml b/deploy/operator.yaml new file mode 100644 index 00000000..a91e430c --- /dev/null +++ b/deploy/operator.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tower-operator +spec: + replicas: 1 + selector: + matchLabels: + name: tower-operator + template: + metadata: + labels: + name: tower-operator + spec: + serviceAccountName: tower-operator + containers: + - name: ansible + command: + - /usr/local/bin/ao-logs + - /tmp/ansible-operator/runner + - stdout + image: "{{ operator_image }}" + imagePullPolicy: "{{ pull_policy|default('Always') }}" + volumeMounts: + - mountPath: /tmp/ansible-operator/runner + name: runner + readOnly: true + - name: operator + image: "{{ operator_image }}" + imagePullPolicy: "{{ pull_policy|default('Always') }}" + volumeMounts: + - mountPath: /tmp/ansible-operator/runner + name: runner + env: + # Watch all namespaces (cluster-scoped). + - name: WATCH_NAMESPACE + value: "" + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "tower-operator" + volumes: + - name: runner + emptyDir: {} diff --git a/deploy/role.yaml b/deploy/role.yaml new file mode 100644 index 00000000..bbdf6eca --- /dev/null +++ b/deploy/role.yaml @@ -0,0 +1,62 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: tower-operator +rules: +- apiGroups: + - "" + resources: + - pods + - services + - services/finalizers + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + verbs: + - '*' +- apiGroups: + - apps + - extensions + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create +- apiGroups: + - apps + resourceNames: + - tower-operator + resources: + - deployments/finalizers + verbs: + - update +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get +- apiGroups: + - tower.ansible.com + resources: + - '*' + verbs: + - '*' diff --git a/deploy/role_binding.yaml b/deploy/role_binding.yaml new file mode 100644 index 00000000..cced2726 --- /dev/null +++ b/deploy/role_binding.yaml @@ -0,0 +1,12 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: tower-operator +subjects: +- kind: ServiceAccount + name: tower-operator + namespace: default +roleRef: + kind: ClusterRole + name: tower-operator + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/service_account.yaml b/deploy/service_account.yaml new file mode 100644 index 00000000..ca8a0dc4 --- /dev/null +++ b/deploy/service_account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tower-operator + namespace: default diff --git a/main.yml b/main.yml new file mode 100644 index 00000000..f6ded4d3 --- /dev/null +++ b/main.yml @@ -0,0 +1,4 @@ +- hosts: localhost + gather_facts: no + roles: + - tower diff --git a/molecule/default/asserts.yml b/molecule/default/asserts.yml new file mode 100644 index 00000000..78ce1cd3 --- /dev/null +++ b/molecule/default/asserts.yml @@ -0,0 +1,27 @@ +--- +- name: Verify cluster resources + hosts: localhost + connection: local + + vars: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + + tasks: + - name: Get tower Pod data + k8s_facts: + kind: Pod + namespace: example-tower + label_selectors: + - app=tower + register: tower_pods + + - name: Verify there are two tower pods + assert: + that: '{{ (tower_pods.resources | length) == 2 }}' + +- name: Verify tower functionality + hosts: k8s + + vars: [] + + tasks: [] diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 00000000..1c21caa8 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,42 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint + enabled: False +platforms: +- name: kind-default + groups: + - k8s + image: bsycorp/kind:latest-1.14 + privileged: True + override_command: no + exposed_ports: + - 8443/tcp + - 10080/tcp + published_ports: + - 0.0.0.0:${TEST_CLUSTER_PORT:-9443}:8443/tcp + pre_build_image: yes +provisioner: + name: ansible + log: True + lint: + name: ansible-lint + enabled: False + inventory: + group_vars: + all: + operator_namespace: ${TEST_NAMESPACE:-default} + env: + K8S_AUTH_KUBECONFIG: /tmp/molecule/kind-default/kubeconfig + KUBECONFIG: /tmp/molecule/kind-default/kubeconfig + ANSIBLE_ROLES_PATH: ${MOLECULE_PROJECT_DIRECTORY}/roles + KIND_PORT: '${TEST_CLUSTER_PORT:-9443}' +scenario: + name: default +verifier: + name: testinfra + lint: + name: flake8 diff --git a/molecule/default/playbook.yml b/molecule/default/playbook.yml new file mode 100644 index 00000000..d926077f --- /dev/null +++ b/molecule/default/playbook.yml @@ -0,0 +1,10 @@ +--- +- name: Converge + hosts: localhost + connection: local + vars: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + roles: + - tower + +- import_playbook: '{{ playbook_dir }}/asserts.yml' diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml new file mode 100644 index 00000000..e7d24301 --- /dev/null +++ b/molecule/default/prepare.yml @@ -0,0 +1,35 @@ +--- +- name: Prepare + hosts: k8s + gather_facts: no + vars: + kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}" + tasks: + - name: delete the kubeconfig if present + file: + path: '{{ kubeconfig }}' + state: absent + delegate_to: localhost + + - name: Fetch the kubeconfig + fetch: + dest: '{{ kubeconfig }}' + flat: yes + src: /root/.kube/config + + - name: Change the kubeconfig port to the proper value + replace: + regexp: 8443 + replace: "{{ lookup('env', 'KIND_PORT') }}" + path: '{{ kubeconfig }}' + delegate_to: localhost + + - name: Wait for the Kubernetes API to become available (this could take a minute) + uri: + url: "http://localhost:10080/kubernetes-ready" + status_code: 200 + validate_certs: no + register: result + until: (result.status|default(-1)) == 200 + retries: 60 + delay: 5 diff --git a/molecule/test-cluster/molecule.yml b/molecule/test-cluster/molecule.yml new file mode 100644 index 00000000..c4d6b9f4 --- /dev/null +++ b/molecule/test-cluster/molecule.yml @@ -0,0 +1,43 @@ +--- +dependency: + name: galaxy +driver: + name: delegated + options: + managed: False + ansible_connection_options: {} +lint: + name: yamllint + enabled: False +platforms: +- name: test-cluster + groups: + - k8s +provisioner: + name: ansible + inventory: + group_vars: + all: + namespace: ${TEST_NAMESPACE:-default} + lint: + name: ansible-lint + enabled: False + env: + ANSIBLE_ROLES_PATH: ${MOLECULE_PROJECT_DIRECTORY}/roles +scenario: + name: test-cluster + test_sequence: + - lint + - destroy + - dependency + - syntax + - create + - prepare + - converge + - side_effect + - verify + - destroy +verifier: + name: testinfra + lint: + name: flake8 diff --git a/molecule/test-cluster/playbook.yml b/molecule/test-cluster/playbook.yml new file mode 100644 index 00000000..7100a472 --- /dev/null +++ b/molecule/test-cluster/playbook.yml @@ -0,0 +1,33 @@ +--- + +- name: Converge + hosts: localhost + connection: local + vars: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + deploy_dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/deploy" + image_name: tower.ansible.com/tower-operator:testing + custom_resource: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_cr.yaml'])) | from_yaml }}" + tasks: + - name: Create the tower.ansible.com/v1alpha1.Tower + k8s: + namespace: '{{ namespace }}' + definition: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_cr.yaml'])) }}" + + - name: Get the newly created Custom Resource + debug: + msg: "{{ lookup('k8s', group='tower.ansible.com', api_version='v1alpha1', kind='Tower', namespace=namespace, resource_name=custom_resource.metadata.name) }}" + + - name: Wait 60s for reconciliation to run + k8s_facts: + api_version: 'v1alpha1' + kind: 'Tower' + namespace: '{{ namespace }}' + name: '{{ custom_resource.metadata.name }}' + register: reconcile_cr + until: + - "'Successful' in (reconcile_cr | json_query('resources[].status.conditions[].reason'))" + delay: 6 + retries: 10 + +- import_playbook: '{{ playbook_dir }}/../default/asserts.yml' diff --git a/molecule/test-local/molecule.yml b/molecule/test-local/molecule.yml new file mode 100644 index 00000000..e4c57821 --- /dev/null +++ b/molecule/test-local/molecule.yml @@ -0,0 +1,55 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint + enabled: False +platforms: +- name: kind-test-local + groups: + - k8s + image: bsycorp/kind:latest-1.15 + privileged: True + override_command: no + exposed_ports: + - 8443/tcp + - 10080/tcp + published_ports: + - 0.0.0.0:${TEST_CLUSTER_PORT:-10443}:8443/tcp + pre_build_image: yes + volumes: + - ${MOLECULE_PROJECT_DIRECTORY}:/build:Z +provisioner: + name: ansible + log: True + lint: + name: ansible-lint + enabled: False + inventory: + group_vars: + all: + operator_namespace: ${TEST_NAMESPACE:-default} + env: + K8S_AUTH_KUBECONFIG: /tmp/molecule/kind-test-local/kubeconfig + KUBECONFIG: /tmp/molecule/kind-test-local/kubeconfig + ANSIBLE_ROLES_PATH: ${MOLECULE_PROJECT_DIRECTORY}/roles + KIND_PORT: '${TEST_CLUSTER_PORT:-10443}' +scenario: + name: test-local + test_sequence: + - lint + - destroy + - dependency + - syntax + - create + - prepare + - converge + - side_effect + - verify + - destroy +verifier: + name: testinfra + lint: + name: flake8 diff --git a/molecule/test-local/playbook.yml b/molecule/test-local/playbook.yml new file mode 100644 index 00000000..d77bf845 --- /dev/null +++ b/molecule/test-local/playbook.yml @@ -0,0 +1,126 @@ +--- +- name: Build Operator in Kubernetes docker container + hosts: k8s + + vars: + image_name: tower.ansible.com/tower-operator:testing + + tasks: + # using command so we don't need to install any dependencies + - name: Get existing image hash + command: docker images -q {{ image_name }} + register: prev_hash + changed_when: false + + - name: Build Operator Image + command: docker build -f /build/build/Dockerfile -t {{ image_name }} /build + register: build_cmd + changed_when: not prev_hash.stdout or (prev_hash.stdout and prev_hash.stdout not in ''.join(build_cmd.stdout_lines[-2:])) + +- name: Converge + hosts: localhost + connection: local + + vars: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + deploy_dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/deploy" + pull_policy: Never + operator_image: tower.ansible.com/tower-operator:testing + custom_resource: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_cr.yaml'])) | from_yaml }}" + + tasks: + - block: + - name: Delete the Operator Deployment + k8s: + state: absent + namespace: '{{ operator_namespace }}' + definition: "{{ lookup('template', '/'.join([deploy_dir, 'operator.yaml'])) }}" + register: delete_deployment + when: hostvars[groups.k8s.0].build_cmd.changed + + - name: Wait 30s for Operator Deployment to terminate + k8s_facts: + api_version: '{{ definition.apiVersion }}' + kind: '{{ definition.kind }}' + namespace: '{{ operator_namespace }}' + name: '{{ definition.metadata.name }}' + vars: + definition: "{{ lookup('template', '/'.join([deploy_dir, 'operator.yaml'])) | from_yaml }}" + register: deployment + until: not deployment.resources + delay: 3 + retries: 10 + when: delete_deployment.changed + + - name: Create the Operator Deployment + k8s: + namespace: '{{ operator_namespace }}' + definition: "{{ lookup('template', '/'.join([deploy_dir, 'operator.yaml'])) }}" + + - name: Ensure the Tower custom_resource namespace exists + k8s: + state: present + name: '{{ custom_resource.metadata.namespace }}' + kind: Namespace + api_version: v1 + + - name: Create the tower.ansible.com/v1alpha1.Tower + k8s: + state: present + namespace: '{{ custom_resource.metadata.namespace }}' + definition: '{{ custom_resource }}' + + - name: Wait 5m for reconciliation to run + k8s_facts: + api_version: '{{ custom_resource.apiVersion }}' + kind: '{{ custom_resource.kind }}' + namespace: '{{ custom_resource.metadata.namespace }}' + name: '{{ custom_resource.metadata.name }}' + register: cr + until: + - "'Successful' in (cr | json_query('resources[].status.conditions[].reason'))" + delay: 6 + retries: 50 + rescue: + - name: debug cr + ignore_errors: yes + failed_when: false + debug: + var: debug_cr + vars: + debug_cr: '{{ lookup("k8s", + kind=custom_resource.kind, + api_version=custom_resource.apiVersion, + namespace=custom_resource.metadata.namespace, + resource_name=custom_resource.metadata.name + )}}' + + - name: debug tower deployment + ignore_errors: yes + failed_when: false + debug: + var: deploy + vars: + deploy: '{{ lookup("k8s", + kind="Deployment", + api_version="apps/v1", + namespace=custom_resource.metadata.namespace, + label_selector="app=tower" + )}}' + + - name: get operator logs + ignore_errors: yes + failed_when: false + command: kubectl logs deployment/{{ definition.metadata.name }} -n {{ operator_namespace }} -c operator + environment: + KUBECONFIG: '{{ lookup("env", "KUBECONFIG") }}' + vars: + definition: "{{ lookup('template', '/'.join([deploy_dir, 'operator.yaml'])) | from_yaml }}" + register: log + + - debug: var=log.stdout_lines + + - fail: + msg: "Failed on action: converge" + +- import_playbook: '{{ playbook_dir }}/../default/asserts.yml' diff --git a/molecule/test-local/prepare.yml b/molecule/test-local/prepare.yml new file mode 100644 index 00000000..ad2419c1 --- /dev/null +++ b/molecule/test-local/prepare.yml @@ -0,0 +1,28 @@ +--- +- import_playbook: ../default/prepare.yml + +- name: Prepare operator resources + hosts: localhost + connection: local + vars: + ansible_python_interpreter: '{{ ansible_playbook_python }}' + deploy_dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/deploy" + tasks: + - name: Create Custom Resource Definition + k8s: + definition: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_crd.yaml'])) }}" + + - name: Ensure specified namespace is present + k8s: + api_version: v1 + kind: Namespace + name: '{{ operator_namespace }}' + + - name: Create RBAC resources + k8s: + definition: "{{ lookup('template', '/'.join([deploy_dir, item])) }}" + namespace: '{{ operator_namespace }}' + with_items: + - role.yaml + - role_binding.yaml + - service_account.yaml diff --git a/roles/tower/README.md b/roles/tower/README.md new file mode 100644 index 00000000..0157e1aa --- /dev/null +++ b/roles/tower/README.md @@ -0,0 +1,32 @@ +Tower +======= + +This role builds and maintains an Ansible Tower instance inside of Kubernetes. + +Requirements +------------ + +TODO. + +Role Variables +-------------- + +TODO. + +Dependencies +------------ + +N/A + +Example Playbook +---------------- + + - hosts: localhost + connection: local + roles: + - tower + +License +------- + +MIT / BSD diff --git a/roles/tower/defaults/main.yml b/roles/tower/defaults/main.yml new file mode 100644 index 00000000..bc62d44d --- /dev/null +++ b/roles/tower/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for tower diff --git a/roles/tower/meta/main.yml b/roles/tower/meta/main.yml new file mode 100644 index 00000000..5eed649f --- /dev/null +++ b/roles/tower/meta/main.yml @@ -0,0 +1,19 @@ +galaxy_info: + author: Jeff Geerling + description: Tower role for Tower Operator for Kubernetes. + company: Midwestern Mac, LLC + + license: MIT + + min_ansible_version: 2.8 + + galaxy_tags: + - tower + - awx + - ansible + - automation + - ci + - cd + - deployment + +dependencies: [] diff --git a/roles/tower/tasks/main.yml b/roles/tower/tasks/main.yml new file mode 100644 index 00000000..6fc5190d --- /dev/null +++ b/roles/tower/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- name: Ensure configured Tower Postgres resources exist in the cluster. + k8s: + definition: "{{ lookup('template', item) | from_yaml }}" + with_items: + - tower_postgres_secret.yaml.j2 + - tower_postgres_statefulset.yaml.j2 + - tower_postgres_service.yaml.j2 diff --git a/roles/tower/templates/tower_postgres_secret.yaml.j2 b/roles/tower/templates/tower_postgres_secret.yaml.j2 new file mode 100644 index 00000000..db876369 --- /dev/null +++ b/roles/tower/templates/tower_postgres_secret.yaml.j2 @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: '{{ meta.name }}-postgres-pass' + namespace: {{ meta.namespace }} +data: + password: {{ tower_postgres_pass | b64encode }} diff --git a/roles/tower/templates/tower_postgres_service.yaml.j2 b/roles/tower/templates/tower_postgres_service.yaml.j2 new file mode 100644 index 00000000..76df619a --- /dev/null +++ b/roles/tower/templates/tower_postgres_service.yaml.j2 @@ -0,0 +1,14 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: '{{ meta.name }}-postgres' + namespace: '{{ meta.namespace }}' + labels: + app: tower-postgres +spec: + ports: + - port: 5432 + clusterIP: None + selector: + app: tower-postgres diff --git a/roles/tower/templates/tower_postgres_statefulset.yaml.j2 b/roles/tower/templates/tower_postgres_statefulset.yaml.j2 new file mode 100644 index 00000000..7a8ce695 --- /dev/null +++ b/roles/tower/templates/tower_postgres_statefulset.yaml.j2 @@ -0,0 +1,50 @@ +--- +apiVersion: v1 +kind: StatefulSet +metadata: + name: '{{ meta.name }}-postgres' + namespace: '{{ meta.namespace }}' + labels: + app: tower-postgres +spec: + selector: + matchLabels: + app: tower-postgres + serviceName: '{{ meta.name }}' + replicas: 1 + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + app: tower-postgres + spec: + containers: + - image: '{{ mariadb_image }}' + name: postgres + env: + - name: POSTGRES_DB + value: awx + - name: POSTGRES_USER + value: awx + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: '{{ meta.name }}-postgres-pass' + key: password + ports: + - containerPort: 3306 + name: postgres + volumeMounts: + - name: postgres + mountPath: /var/lib/postgresql/data + subPath: data + volumeClaimTemplates: + - metadata: + name: postgres + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: '{{ tower_postgres_storage_request }}' diff --git a/watches.yaml b/watches.yaml new file mode 100644 index 00000000..cf3c8933 --- /dev/null +++ b/watches.yaml @@ -0,0 +1,5 @@ +--- +- version: v1alpha1 + group: tower.ansible.com + kind: Tower + playbook: /opt/ansible/main.yml