diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/README.md b/README.md index f1a45b27..1f6b722d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Then you can create instances of Tower, for example: ``` --- - apiVersion: tower.ansible.com/v1alpha1 + apiVersion: tower.ansible.com/v1beta1 kind: Tower metadata: name: tower @@ -177,7 +177,7 @@ After it is built, test it on a local cluster: minikube addons enable ingress kubectl apply -f deploy/tower-operator.yaml kubectl create namespace example-tower - kubectl apply -f deploy/crds/tower_v1alpha1_tower_cr_awx.yaml + kubectl apply -f deploy/crds/tower_v1beta1_tower_cr_awx.yaml minikube delete diff --git a/build/chain-operator-files.yml b/build/chain-operator-files.yml index 74348a0a..ab6d7661 100644 --- a/build/chain-operator-files.yml +++ b/build/chain-operator-files.yml @@ -27,7 +27,7 @@ marker_end: "" insertafter: "EOF" with_file: - - "../deploy/crds/tower_v1alpha1_tower_crd.yaml" + - "../deploy/crds/tower_v1beta1_tower_crd.yaml" - "../deploy/role.yaml" - "../deploy/role_binding.yaml" - "../deploy/service_account.yaml" diff --git a/deploy/crds/tower_v1alpha1_tower_crd.yaml b/deploy/crds/tower_v1alpha1_tower_crd.yaml deleted file mode 100644 index a9801b26..00000000 --- a/deploy/crds/tower_v1alpha1_tower_crd.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -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/crds/tower_v1alpha1_tower_cr_awx.yaml b/deploy/crds/tower_v1beta1_tower_cr_awx.yaml similarity index 87% rename from deploy/crds/tower_v1alpha1_tower_cr_awx.yaml rename to deploy/crds/tower_v1beta1_tower_cr_awx.yaml index 9c21484e..13f9b05a 100644 --- a/deploy/crds/tower_v1alpha1_tower_cr_awx.yaml +++ b/deploy/crds/tower_v1beta1_tower_cr_awx.yaml @@ -1,15 +1,17 @@ --- -apiVersion: tower.ansible.com/v1alpha1 +apiVersion: tower.ansible.com/v1beta1 kind: Tower metadata: name: example-tower namespace: example-tower spec: + deployment_type: awx tower_ingress_type: ingress tower_task_privileged: false tower_hostname: example-tower.test tower_secret_key: aabbcc + tower_broadcast_websocket_secret: changeme tower_admin_user: test tower_admin_email: test@example.com diff --git a/deploy/crds/tower_v1beta1_tower_cr_molecule.yaml b/deploy/crds/tower_v1beta1_tower_cr_molecule.yaml new file mode 100644 index 00000000..987ff2d3 --- /dev/null +++ b/deploy/crds/tower_v1beta1_tower_cr_molecule.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: tower.ansible.com/v1beta1 +kind: Tower +metadata: + name: example-tower + namespace: example-tower +spec: + deployment_type: awx + tower_ingress_type: ingress + tower_task_privileged: false + + tower_hostname: example-tower.test + tower_secret_key: aabbcc + tower_broadcast_websocket_secret: changeme + + tower_admin_user: test + tower_admin_email: test@example.com + tower_admin_password: changeme + + tower_task_image: ansible/awx_task:11.2.0 + tower_web_image: ansible/awx_web:11.2.0 + + tower_task_mem_request: 128M + tower_task_cpu_request: 500m + + tower_web_mem_request: 128M + tower_web_cpu_request: 500m + + tower_create_preload_data: true + + tower_memcached_image: memcached:alpine + + tower_redis_image: redis:latest + + tower_postgres_pass: awxpass + tower_postgres_image: postgres:10 + tower_postgres_storage_request: 8Gi + tower_postgres_storage_class: '' diff --git a/deploy/crds/tower_v1alpha1_tower_cr_tower.yaml b/deploy/crds/tower_v1beta1_tower_cr_tower.yaml similarity index 85% rename from deploy/crds/tower_v1alpha1_tower_cr_tower.yaml rename to deploy/crds/tower_v1beta1_tower_cr_tower.yaml index 9149854f..33d877a4 100644 --- a/deploy/crds/tower_v1alpha1_tower_cr_tower.yaml +++ b/deploy/crds/tower_v1beta1_tower_cr_tower.yaml @@ -1,15 +1,17 @@ --- -apiVersion: tower.ansible.com/v1alpha1 +apiVersion: tower.ansible.com/v1beta1 kind: Tower metadata: name: example-tower namespace: example-tower spec: - tower_ingress_type: ingress + deployment_type: tower + tower_ingress_type: route tower_task_privileged: false tower_hostname: example-tower.test tower_secret_key: aabbcc + tower_broadcast_websocket_secret: changeme tower_admin_user: test tower_admin_email: test@example.com diff --git a/deploy/crds/tower_v1beta1_tower_crd.yaml b/deploy/crds/tower_v1beta1_tower_crd.yaml new file mode 100644 index 00000000..e24157de --- /dev/null +++ b/deploy/crds/tower_v1beta1_tower_crd.yaml @@ -0,0 +1,33 @@ +--- +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: v1beta1 + versions: + - name: v1beta1 + served: true + storage: true + validation: + openAPIV3Schema: + description: Schema validation for the Tower CRD + type: object + properties: + spec: + type: object + properties: + deployment_type: + type: string + pattern: "^(tower|awx)(-)?.*$" + required: + - deployment_type diff --git a/deploy/tower-operator.yaml b/deploy/tower-operator.yaml index 393efaf2..c27d8f1b 100644 --- a/deploy/tower-operator.yaml +++ b/deploy/tower-operator.yaml @@ -113,14 +113,14 @@ spec: - /usr/local/bin/ao-logs - /tmp/ansible-operator/runner - stdout - image: "geerlingguy/tower-operator:0.3.0" + image: "ansible/tower-operator:0.4.0" imagePullPolicy: "Always" volumeMounts: - mountPath: /tmp/ansible-operator/runner name: runner readOnly: true - name: operator - image: "geerlingguy/tower-operator:0.3.0" + image: "ansible/tower-operator:0.4.0" imagePullPolicy: "Always" volumeMounts: - mountPath: /tmp/ansible-operator/runner @@ -154,8 +154,8 @@ spec: scope: Namespaced subresources: status: {} - version: v1alpha1 + version: v1beta1 versions: - - name: v1alpha1 + - name: v1beta1 served: true storage: true diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index 63a617be..375272af 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -10,7 +10,7 @@ tasks: - name: Create Custom Resource Definition k8s: - definition: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_crd.yaml'])) }}" + definition: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1beta1_tower_crd.yaml'])) }}" - name: Ensure specified namespace is present k8s: diff --git a/molecule/test-local/converge.yml b/molecule/test-local/converge.yml index 017840fb..56e9930c 100644 --- a/molecule/test-local/converge.yml +++ b/molecule/test-local/converge.yml @@ -26,7 +26,7 @@ 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_awx.yaml'])) | from_yaml }}" + custom_resource: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1beta1_tower_cr_molecule.yaml'])) | from_yaml }}" tasks: @@ -66,7 +66,7 @@ kind: Namespace api_version: v1 - - name: Create the tower.ansible.com/v1alpha1.Tower + - name: Create the Tower Custom Resource k8s: state: present namespace: '{{ custom_resource.metadata.namespace }}' diff --git a/molecule/test-minikube/converge.yml b/molecule/test-minikube/converge.yml index a9736dde..fe9c38b7 100644 --- a/molecule/test-minikube/converge.yml +++ b/molecule/test-minikube/converge.yml @@ -35,7 +35,7 @@ pull_policy: Never operator_image: tower.ansible.com/tower-operator:testing # Change this to _awx to test AWX, _tower to test Tower. - custom_resource: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1alpha1_tower_cr_awx.yaml'])) | from_yaml }}" + custom_resource: "{{ lookup('file', '/'.join([deploy_dir, 'crds/tower_v1beta1_tower_cr_awx.yaml'])) | from_yaml }}" tasks: - block: @@ -73,7 +73,7 @@ kind: Namespace api_version: v1 - - name: Create the tower.ansible.com/v1alpha1.Tower + - name: Create the Tower Custom Resource k8s: state: present namespace: '{{ custom_resource.metadata.namespace }}' diff --git a/roles/tower/defaults/main.yml b/roles/tower/defaults/main.yml index a21548c8..e75ccaff 100644 --- a/roles/tower/defaults/main.yml +++ b/roles/tower/defaults/main.yml @@ -9,6 +9,8 @@ tower_admin_user: test tower_admin_email: test@example.com tower_admin_password: changeme +tower_broadcast_websocket_secret: changeme + # Use these image versions for Ansible Tower. tower_task_image: registry.redhat.io/ansible-tower-37/ansible-tower-rhel7:3.7.0 tower_web_image: registry.redhat.io/ansible-tower-37/ansible-tower-rhel7:3.7.0 @@ -19,7 +21,7 @@ tower_web_image: registry.redhat.io/ansible-tower-37/ansible-tower-rhel7:3.7.0 tower_create_preload_data: true -tower_task_replicas: "1" +tower_replicas: "1" tower_task_mem_request: 1Gi tower_task_cpu_request: 500m @@ -37,3 +39,7 @@ tower_postgres_storage_request: 8Gi tower_postgres_storage_class: '' tower_postgres_data_path: '/var/lib/postgresql/data/pgdata' + +tower_postgres_port: 5432 + +ca_trust_bundle: "/etc/pki/tls/certs/ca-bundle.crt" diff --git a/roles/tower/tasks/initialize.yml b/roles/tower/tasks/initialize.yml index 0658ae5d..8f064fc6 100644 --- a/roles/tower/tasks/initialize.yml +++ b/roles/tower/tasks/initialize.yml @@ -1,7 +1,7 @@ --- - name: Check if there are any Tower super users defined. shell: >- - kubectl exec -n {{ meta.namespace }} {{ tower_pod_name }} -- bash -c + kubectl exec -n {{ meta.namespace }} -c {{ meta.name }}-task {{ tower_pod_name }} -- bash -c "echo 'from django.contrib.auth.models import User; nsu = User.objects.filter(is_superuser=True).count(); exit(0 if nsu > 0 else 1)' @@ -12,7 +12,7 @@ - name: Create Tower super user via Django if it doesn't exist. shell: >- - kubectl exec -n {{ meta.namespace }} {{ tower_pod_name }} -- bash -c + kubectl exec -n {{ meta.namespace }} -c {{ meta.name }}-task {{ tower_pod_name }} -- bash -c "echo \"from django.contrib.auth.models import User; User.objects.create_superuser('{{ tower_admin_user }}', '{{ tower_admin_email }}', '{{ tower_admin_password }}')\" | awx-manage shell" @@ -21,7 +21,7 @@ - name: Create preload data if necessary. # noqa 305 shell: >- - kubectl exec -n {{ meta.namespace }} {{ tower_pod_name }} -- bash -c + kubectl exec -n {{ meta.namespace }} -c {{ meta.name }}-task {{ tower_pod_name }} -- bash -c "awx-manage create_preload_data" register: cdo changed_when: "'added' in cdo.stdout" diff --git a/roles/tower/tasks/main.yml b/roles/tower/tasks/main.yml index 086b4771..b2909741 100644 --- a/roles/tower/tasks/main.yml +++ b/roles/tower/tasks/main.yml @@ -1,15 +1,18 @@ --- +- name: Include deployment type vars + include_vars: "{{ deployment_type }}.yml" + - name: Ensure configured Tower resources exist in the cluster. k8s: + apply: yes definition: "{{ lookup('template', item) | from_yaml_all | list }}" register: k8s_defs_result with_items: - - tower_memcached.yaml.j2 - tower_postgres.yaml.j2 - tower_config.yaml.j2 - - tower_redis.yaml.j2 - - tower_web.yaml.j2 - - tower_task.yaml.j2 + - launch_awx.yaml.j2 + - supervisor.yaml.j2 + - tower.yaml.j2 - name: Get the Tower pod information. k8s_info: @@ -33,7 +36,7 @@ - name: Check if database is populated (auth_user table exists). shell: >- - kubectl exec -n {{ meta.namespace }} {{ tower_pod_name }} -- bash -c + kubectl exec -n {{ meta.namespace }} -c {{ meta.name }}-task {{ tower_pod_name }} -- bash -c "echo 'from django.db import connection; tbl = \"auth_user\" in connection.introspection.table_names(); exit(0 if tbl else 1)' @@ -45,23 +48,23 @@ - name: Migrate the database if the K8s resources were updated. # noqa 305 shell: >- - kubectl exec -n {{ meta.namespace }} {{ tower_pod_name }} -- bash -c + kubectl exec -n {{ meta.namespace }} -c {{ meta.name }}-task {{ tower_pod_name }} -- bash -c "awx-manage migrate --noinput" register: migrate_result when: (k8s_defs_result is changed) or (database_check is defined and database_check.rc != 0) - include_tasks: initialize.yml -- name: Scale the tower_task deployment to 0 replicas after migration. +- name: Scale the tower deployment to 0 replicas after migration. k8s: - definition: "{{ lookup('template', 'tower_task.yaml.j2') | from_yaml_all | list }}" + definition: "{{ lookup('template', 'tower.yaml.j2') | from_yaml_all | list }}" vars: - tower_task_replicas: "0" + tower_replicas: "0" when: migrate_result and migrate_result.changed -- name: Scale the tower_task deployment back to 1 replica after migration. +- name: Scale the tower deployment back to 1 replica after migration. k8s: - definition: "{{ lookup('template', 'tower_task.yaml.j2') | from_yaml_all | list }}" + definition: "{{ lookup('template', 'tower.yaml.j2') | from_yaml_all | list }}" vars: - tower_task_replicas: "1" + tower_replicas: "1" when: migrate_result and migrate_result.changed diff --git a/roles/tower/templates/credentials.py.j2 b/roles/tower/templates/credentials.py.j2 new file mode 100644 index 00000000..abb074d0 --- /dev/null +++ b/roles/tower/templates/credentials.py.j2 @@ -0,0 +1,16 @@ +DATABASES = { + 'default': { + 'ATOMIC_REQUESTS': True, + 'ENGINE': 'awx.main.db.profiled_pg', + 'NAME': "awx", + 'USER': "awx", + 'PASSWORD': "{{ tower_postgres_pass }}", + 'HOST': '{{ meta.name }}-postgres', + 'PORT': "{{ tower_postgres_port }}", + 'OPTIONS': { 'sslmode': '{{ pg_sslmode|default("prefer") }}', + 'sslrootcert': '{{ ca_trust_bundle }}', + }, + } +} + +BROADCAST_WEBSOCKET_SECRET = "{{ tower_broadcast_websocket_secret | b64encode }}" diff --git a/roles/tower/templates/environment.sh.j2 b/roles/tower/templates/environment.sh.j2 new file mode 100644 index 00000000..420c99bd --- /dev/null +++ b/roles/tower/templates/environment.sh.j2 @@ -0,0 +1,5 @@ +DATABASE_USER=awx +DATABASE_NAME=awx +DATABASE_HOST={{ meta.name }}-postgres +DATABASE_PORT={{ tower_postgres_port }} +DATABASE_PASSWORD={{ tower_postgres_pass }} diff --git a/roles/tower/templates/launch_awx.yaml.j2 b/roles/tower/templates/launch_awx.yaml.j2 new file mode 100644 index 00000000..07d1e7d0 --- /dev/null +++ b/roles/tower/templates/launch_awx.yaml.j2 @@ -0,0 +1,59 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ meta.name }}-launch-awx + namespace: {{ meta.namespace }} + labels: + app: tower +data: + launch-awx-task: | + #!/usr/bin/env bash + if [ `id -u` -ge 500 ]; then + echo "awx:x:`id -u`:`id -g`:,,,:/var/lib/awx:/bin/bash" >> /tmp/passwd + cat /tmp/passwd > /etc/passwd + rm /tmp/passwd + fi + + source /etc/tower/conf.d/environment.sh + + ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m wait_for -a "host=$DATABASE_HOST port=$DATABASE_PORT" all + ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m wait_for -a "path=/var/run/redis/redis.sock" all + + if [ -z "$AWX_SKIP_MIGRATIONS" ]; then + awx-manage migrate --noinput + fi + + if [ ! -z "$AWX_ADMIN_USER" ]&&[ ! -z "$AWX_ADMIN_PASSWORD" ]; then + echo "from django.contrib.auth.models import User; User.objects.create_superuser('$AWX_ADMIN_USER', 'root@localhost', '$AWX_ADMIN_PASSWORD')" | awx-manage shell + awx-manage create_preload_data + else + echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'root@localhost', 'password')" | awx-manage shell + awx-manage create_preload_data + fi + echo 'from django.conf import settings; x = settings.AWX_TASK_ENV; x["HOME"] = "/var/lib/awx"; settings.AWX_TASK_ENV = x' | awx-manage shell + awx-manage provision_instance --hostname=$(hostname) + awx-manage register_queue --queuename=tower --instance_percent=100 + + unset $(cut -d = -f -1 /etc/tower/conf.d/environment.sh) + + supervisord -c /supervisor_task.conf + + launch-awx-web: | + #!/usr/bin/env bash + if [ `id -u` -ge 500 ]; then + echo "awx:x:`id -u`:`id -g`:,,,:/var/lib/awx:/bin/bash" >> /tmp/passwd + cat /tmp/passwd > /etc/passwd + rm /tmp/passwd + fi + + source /etc/tower/conf.d/environment.sh + + ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m wait_for -a "host=$DATABASE_HOST port=$DATABASE_PORT" all + ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m wait_for -a "path=/var/run/redis/redis.sock" all + + awx-manage collectstatic --noinput --clear + + unset $(cut -d = -f -1 /etc/tower/conf.d/environment.sh) + + supervisord -c /supervisor.conf diff --git a/roles/tower/templates/supervisor.yaml.j2 b/roles/tower/templates/supervisor.yaml.j2 new file mode 100644 index 00000000..740515d4 --- /dev/null +++ b/roles/tower/templates/supervisor.yaml.j2 @@ -0,0 +1,145 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ meta.name }}-supervisor-config + namespace: {{ meta.namespace }} + labels: + app: tower +data: + supervisor-web-config: | + [supervisord] + nodaemon = True + umask = 022 + + [program:nginx] + command = nginx -g "daemon off;" + autostart = true + autorestart = true + stopwaitsecs = 5 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [program:uwsgi] + command = {{ uwsgi_bash }} '/var/lib/awx/venv/awx/bin/uwsgi --socket 127.0.0.1:8050 --module=awx.wsgi:application --vacuum --processes=5 --harakiri=120 --no-orphans --master --max-requests=1000 --master-fifo=/var/lib/awx/awxfifo --lazy-apps -b 32768' + directory = /var/lib/awx + autostart = true + autorestart = true + stopwaitsecs = 15 + stopsignal = INT + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [program:daphne] + command = {{ uwsgi_bash }} '/var/lib/awx/venv/awx/bin/daphne -b 127.0.0.1 -p 8051 awx.asgi:channel_layer' + directory = /var/lib/awx + autostart = true + autorestart = true + stopwaitsecs = 5 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [program:wsbroadcast] + command = awx-manage run_wsbroadcast + directory = /var/lib/awx + autostart = true + autorestart = true + stopwaitsecs = 5 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [program:awx-rsyslogd] + command = rsyslogd -n -i /var/run/awx-rsyslog/rsyslog.pid -f /var/lib/awx/rsyslog/rsyslog.conf + autostart = true + autorestart = true + stopwaitsecs = 5 + stopsignal=TERM + stopasgroup=true + killasgroup=true + redirect_stderr=true + stdout_logfile=/dev/stderr + stdout_logfile_maxbytes=0 + + [group:tower-processes] + programs=nginx,uwsgi,daphne,wsbroadcast,awx-rsyslogd + priority=5 + + # TODO: Exit Handler + + [eventlistener:awx-config-watcher] + command=/usr/bin/config-watcher + stderr_logfile=/dev/stdout + stderr_logfile_maxbytes=0 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + events=TICK_60 + priority=0 + + [unix_http_server] + file=/var/run/supervisor/supervisor.web.sock + + [supervisorctl] + serverurl=unix:///var/run/supervisor/supervisor.web.sock ; use a unix:// URL for a unix socket + + [rpcinterface:supervisor] + supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + + supervisor-task-config: | + [supervisord] + nodaemon = True + umask = 022 + + [program:dispatcher] + command = awx-manage run_dispatcher + directory = /var/lib/awx + environment = LANGUAGE="en_US.UTF-8",LANG="en_US.UTF-8",LC_ALL="en_US.UTF-8",LC_CTYPE="en_US.UTF-8" + autostart = true + autorestart = true + stopwaitsecs = 5 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [program:callback-receiver] + command = awx-manage run_callback_receiver + directory = /var/lib/awx + autostart = true + autorestart = true + stopwaitsecs = 5 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + stderr_logfile=/dev/stderr + stderr_logfile_maxbytes=0 + + [group:tower-processes] + programs=dispatcher,callback-receiver + priority=5 + + # TODO: Exit Handler + + [eventlistener:awx-config-watcher] + command=/usr/bin/config-watcher + stderr_logfile=/dev/stdout + stderr_logfile_maxbytes=0 + stdout_logfile=/dev/stdout + stdout_logfile_maxbytes=0 + events=TICK_60 + priority=0 + + [unix_http_server] + file=/tmp/supervisor.sock + + [supervisorctl] + serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket + + [rpcinterface:supervisor] + supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface diff --git a/roles/tower/templates/tower.yaml.j2 b/roles/tower/templates/tower.yaml.j2 new file mode 100644 index 00000000..2a8aaa94 --- /dev/null +++ b/roles/tower/templates/tower.yaml.j2 @@ -0,0 +1,284 @@ +# Tower Secret. +--- +apiVersion: v1 +kind: Secret +metadata: + name: '{{ meta.name }}-secrets' + namespace: '{{ meta.namespace }}' +data: + secret_key: '{{ tower_secret_key | b64encode }}' + credentials_py: "{{ lookup('template', 'credentials.py.j2') | b64encode }}" + environment_sh: "{{ lookup('template', 'environment.sh.j2') | b64encode }}" + +# Tower Deployment. +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ meta.name }}' + namespace: '{{ meta.namespace }}' + labels: + app: tower +spec: + replicas: {{ tower_replicas }} + selector: + matchLabels: + app: tower + template: + metadata: + labels: + app: tower + spec: + containers: + - name: memcached + image: '{{ tower_memcached_image }}' + command: + - 'memcached' + - '-s' + - '/var/run/memcached/memcached.sock' + - '-a' + - '0666' + ports: + - containerPort: 1121 + volumeMounts: + - name: {{ meta.name }}-memcached-socket + mountPath: "/var/run/memcached" + - image: '{{ tower_redis_image }}' + name: redis + args: ["redis-server", "/etc/redis.conf"] + ports: + - containerPort: 6379 + volumeMounts: + - name: {{ meta.name }}-redis-config + mountPath: "/etc/redis.conf" + subPath: redis.conf + readOnly: true + - name: {{ meta.name }}-redis-socket + mountPath: "/var/run/redis" + - image: '{{ tower_web_image }}' + name: '{{ meta.name }}-web' + ports: + - containerPort: 8052 + volumeMounts: + - name: "{{ meta.name }}-application-credentials" + mountPath: "/etc/tower/conf.d/" + readOnly: true + - name: {{ meta.name }}-secret-key + mountPath: /etc/tower/SECRET_KEY + subPath: SECRET_KEY + readOnly: true + - name: {{ meta.name }}-settings + mountPath: /etc/tower/settings.py + subPath: settings.py + readOnly: true + - name: {{ meta.name }}-nginx-conf + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + readOnly: true + - name: {{ meta.name }}-launch-awx-web + mountPath: /usr/bin/launch_awx.sh + subPath: launch_awx.sh + readOnly: true + - name: {{ meta.name }}-supervisor-web-config + mountPath: /supervisor.conf + subPath: supervisor.conf + readOnly: true + - name: {{ meta.name }}-redis-socket + mountPath: "/var/run/redis" + - name: {{ meta.name }}-memcached-socket + mountPath: "/var/run/memcached" + - name: supervisor-socket + mountPath: "/var/run/supervisor" + - name: rsyslog-socket + mountPath: "/var/run/awx-rsyslog" + - name: rsyslog-dir + mountPath: "/var/lib/awx/rsyslog" + resources: + requests: + memory: '{{ tower_web_mem_request }}' + cpu: '{{ tower_web_cpu_request }}' + - image: '{{ tower_task_image }}' + name: '{{ meta.name }}-task' +{% if tower_task_privileged == true %} + securityContext: + privileged: true +{% endif %} + command: + - /usr/bin/launch_awx_task.sh + volumeMounts: + - name: "{{ meta.name }}-application-credentials" + mountPath: "/etc/tower/conf.d/" + readOnly: true + - name: {{ meta.name }}-secret-key + mountPath: /etc/tower/SECRET_KEY + subPath: SECRET_KEY + readOnly: true + - name: {{ meta.name }}-settings + mountPath: /etc/tower/settings.py + subPath: settings.py + readOnly: true + - name: {{ meta.name }}-launch-awx-task + mountPath: /usr/bin/launch_awx_task.sh + subPath: launch_awx_task.sh + readOnly: true + - name: {{ meta.name }}-supervisor-web-config + mountPath: "/supervisor.conf" + subPath: supervisor.conf + readOnly: true + - name: {{ meta.name }}-supervisor-task-config + mountPath: /supervisor_task.conf + subPath: supervisor_task.conf + readOnly: true + - name: {{ meta.name }}-redis-socket + mountPath: "/var/run/redis" + - name: {{ meta.name }}-memcached-socket + mountPath: "/var/run/memcached" + - name: supervisor-socket + mountPath: "/var/run/supervisor" + - name: rsyslog-socket + mountPath: "/var/run/awx-rsyslog" + - name: rsyslog-dir + mountPath: "/var/lib/awx/rsyslog" + env: + - name: SUPERVISOR_WEB_CONFIG_PATH + value: "/supervisor.conf" + - name: AWX_SKIP_MIGRATIONS + value: "1" + - name: MY_POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + resources: + requests: + memory: '{{ tower_task_mem_request }}' + cpu: '{{ tower_task_cpu_request }}' + volumes: + - name: "{{ meta.name }}-application-credentials" + secret: + secretName: "{{ meta.name }}-secrets" + items: + - key: credentials_py + path: 'credentials.py' + - key: environment_sh + path: 'environment.sh' + - name: {{ meta.name }}-secret-key + secret: + secretName: '{{ meta.name }}-secrets' + items: + - key: secret_key + path: SECRET_KEY + - name: {{ meta.name }}-settings + configMap: + name: '{{ meta.name }}-tower-configmap' + items: + - key: settings + path: settings.py + - name: {{ meta.name }}-nginx-conf + configMap: + name: '{{ meta.name }}-tower-configmap' + items: + - key: nginx_conf + path: nginx.conf + - name: {{ meta.name }}-redis-config + configMap: + name: {{ meta.name }}-tower-configmap + items: + - key: redis_conf + path: redis.conf + - name: {{ meta.name }}-launch-awx-web + configMap: + name: '{{meta.name }}-launch-awx' + items: + - key: launch-awx-web + path: launch_awx.sh + defaultMode: 0755 + - name: {{ meta.name }}-supervisor-web-config + configMap: + name: '{{ meta.name }}-supervisor-config' + items: + - key: supervisor-web-config + path: supervisor.conf + - name: {{ meta.name }}-launch-awx-task + configMap: + name: '{{ meta.name }}-launch-awx' + items: + - key: launch-awx-task + path: 'launch_awx_task.sh' + defaultMode: 0755 + - name: {{ meta.name }}-supervisor-task-config + configMap: + name: '{{ meta.name }}-supervisor-config' + items: + - key: supervisor-task-config + path: 'supervisor_task.conf' + - name: {{ meta.name }}-redis-socket + emptyDir: {} + - name: {{ meta.name }}-memcached-socket + emptyDir: {} + - name: supervisor-socket + emptyDir: {} + - name: rsyslog-socket + emptyDir: {} + - name: rsyslog-dir + emptyDir: {} + +# Tower Service. +--- +apiVersion: v1 +kind: Service +metadata: + name: '{{ meta.name }}-service' + namespace: '{{ meta.namespace }}' + labels: + app: tower +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8052 + name: http + selector: + app: tower + +# Tower Ingress. +{% if 'ingress' == tower_ingress_type|lower %} +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: '{{ meta.name }}-ingress' + namespace: '{{ meta.namespace }}' +spec: + rules: + - host: '{{ tower_hostname }}' + http: + paths: + - path: / + backend: + serviceName: '{{ meta.name }}-service' + servicePort: 80 +{% endif %} + +{% if 'route' == tower_ingress_type|lower %} +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: '{{ meta.name }}' + namespace: '{{ meta.namespace }}' +spec: + port: + targetPort: http + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: {{ meta.name }}-service + weight: 100 + wildcardPolicy: None +{% endif %} diff --git a/roles/tower/templates/tower_config.yaml.j2 b/roles/tower/templates/tower_config.yaml.j2 index 121c3a1b..17e0d281 100644 --- a/roles/tower/templates/tower_config.yaml.j2 +++ b/roles/tower/templates/tower_config.yaml.j2 @@ -100,32 +100,9 @@ data: if os.getenv("DATABASE_SSLMODE", False): DATABASES['default']['OPTIONS'] = {'sslmode': os.getenv("DATABASE_SSLMODE")} - CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', - 'LOCATION': '{}:{}'.format("{{ meta.name }}-memcached.{{ meta.namespace }}.svc.cluster.local", "11211") - }, - 'ephemeral': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - }, - } - - BROKER_URL = 'redis://{}:{}/'.format( - '{{ meta.name }}-redis.{{ meta.namespace }}.svc.cluster.local', - '6379') - - CHANNEL_LAYERS = { - "default": { - "BACKEND": "channels_redis.core.RedisChannelLayer", - "CONFIG": { - "hosts": [BROKER_URL], - "capacity": 10000, - "group_expiry": 157784760, # 5 years - } - } - } - USE_X_FORWARDED_PORT = True + BROADCAST_WEBSOCKET_PORT = 8052 + BROADCAST_WEBSOCKET_PROTOCOL = 'http' nginx_conf: | worker_processes 1; @@ -228,3 +205,8 @@ data: } } } + redis_conf: | + unixsocket /var/run/redis/redis.sock + unixsocketperm 777 + port 0 + bind 127.0.0.1 diff --git a/roles/tower/templates/tower_memcached.yaml.j2 b/roles/tower/templates/tower_memcached.yaml.j2 deleted file mode 100644 index 94897803..00000000 --- a/roles/tower/templates/tower_memcached.yaml.j2 +++ /dev/null @@ -1,42 +0,0 @@ -# Memcached Deployment. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: '{{ meta.name }}-memcached' - namespace: '{{ meta.namespace }}' - labels: - app: tower-memcached -spec: - replicas: 1 - selector: - matchLabels: - app: tower-memcached - template: - metadata: - labels: - app: tower-memcached - spec: - containers: - - name: memcached - image: '{{ tower_memcached_image }}' - ports: - - containerPort: 11211 - -# Memcached Service. ---- -apiVersion: v1 -kind: Service -metadata: - name: '{{ meta.name }}-memcached' - namespace: '{{ meta.namespace }}' - labels: - app: tower-memcached -spec: - clusterIP: None - ports: - - port: 11211 - protocol: TCP - targetPort: 11211 - selector: - app: tower-memcached diff --git a/roles/tower/templates/tower_redis.yaml.j2 b/roles/tower/templates/tower_redis.yaml.j2 deleted file mode 100644 index 5c2df139..00000000 --- a/roles/tower/templates/tower_redis.yaml.j2 +++ /dev/null @@ -1,41 +0,0 @@ -# Redis Deployment. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: '{{ meta.name }}-redis' - namespace: '{{ meta.namespace }}' - labels: - app: tower-redis -spec: - replicas: 1 - selector: - matchLabels: - app: tower-redis - template: - metadata: - labels: - app: tower-redis - spec: - containers: - - image: '{{ tower_redis_image }}' - name: redis - ports: - - containerPort: 6379 - -# Redis Service. ---- -apiVersion: v1 -kind: Service -metadata: - name: '{{ meta.name }}-redis' - namespace: '{{ meta.namespace }}' - labels: - app: tower-redis -spec: - ports: - - port: 6379 - protocol: TCP - targetPort: 6379 - selector: - app: tower-redis diff --git a/roles/tower/templates/tower_task.yaml.j2 b/roles/tower/templates/tower_task.yaml.j2 deleted file mode 100644 index 09685778..00000000 --- a/roles/tower/templates/tower_task.yaml.j2 +++ /dev/null @@ -1,69 +0,0 @@ -# Tower Task Deployment. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: '{{ meta.name }}-tower-task' - namespace: '{{ meta.namespace }}' - labels: - app: tower-task -spec: - replicas: {{ tower_task_replicas | int }} - selector: - matchLabels: - app: tower-task - template: - metadata: - labels: - app: tower-task - spec: - containers: - - image: '{{ tower_task_image }}' - name: tower-task -{% if tower_task_privileged == true %} - securityContext: - privileged: true -{% endif %} - command: - - /usr/bin/launch_awx_task.sh - envFrom: - - configMapRef: - name: '{{ meta.name }}-tower-configmap' - - secretRef: - name: '{{ meta.name }}-tower-secret' - volumeMounts: - - name: secret-key - mountPath: /etc/tower/SECRET_KEY - subPath: SECRET_KEY - readOnly: true - - name: environment - mountPath: /etc/tower/conf.d/environment.sh - subPath: environment.sh - readOnly: true - - name: settings - mountPath: /etc/tower/settings.py - subPath: settings.py - readOnly: true - resources: - requests: - memory: '{{ tower_task_mem_request }}' - cpu: '{{ tower_task_cpu_request }}' - volumes: - - name: secret-key - secret: - secretName: '{{ meta.name }}-tower-secret' - items: - - key: secret_key - path: SECRET_KEY - - name: environment - configMap: - name: '{{ meta.name }}-tower-configmap' - items: - - key: environment - path: environment.sh - - name: settings - configMap: - name: '{{ meta.name }}-tower-configmap' - items: - - key: settings - path: settings.py diff --git a/roles/tower/templates/tower_web.yaml.j2 b/roles/tower/templates/tower_web.yaml.j2 deleted file mode 100644 index 9105f38f..00000000 --- a/roles/tower/templates/tower_web.yaml.j2 +++ /dev/null @@ -1,138 +0,0 @@ -# Tower Secret. ---- -apiVersion: v1 -kind: Secret -metadata: - name: '{{ meta.name }}-tower-secret' - namespace: '{{ meta.namespace }}' -data: - secret_key: '{{ tower_secret_key | b64encode }}' - admin_password: '{{ tower_admin_password | b64encode }}' - -# Tower Deployment. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: '{{ meta.name }}-tower-web' - namespace: '{{ meta.namespace }}' - labels: - app: tower -spec: - replicas: 1 - selector: - matchLabels: - app: tower - template: - metadata: - labels: - app: tower - spec: - containers: - - image: '{{ tower_web_image }}' - name: tower - ports: - - containerPort: 8052 - volumeMounts: - - name: secret-key - mountPath: /etc/tower/SECRET_KEY - subPath: SECRET_KEY - readOnly: true - - name: environment - mountPath: /etc/tower/conf.d/environment.sh - subPath: environment.sh - readOnly: true - - name: settings - mountPath: /etc/tower/settings.py - subPath: settings.py - readOnly: true - - name: nginx-conf - mountPath: /etc/nginx/nginx.conf - subPath: nginx.conf - readOnly: true - resources: - requests: - memory: '{{ tower_web_mem_request }}' - cpu: '{{ tower_web_cpu_request }}' - volumes: - - name: secret-key - secret: - secretName: '{{ meta.name }}-tower-secret' - items: - - key: secret_key - path: SECRET_KEY - - name: environment - configMap: - name: '{{ meta.name }}-tower-configmap' - items: - - key: environment - path: environment.sh - - name: settings - configMap: - name: '{{ meta.name }}-tower-configmap' - items: - - key: settings - path: settings.py - - name: nginx-conf - configMap: - name: '{{ meta.name }}-tower-configmap' - items: - - key: nginx_conf - path: nginx.conf - -# Tower Service. ---- -apiVersion: v1 -kind: Service -metadata: - name: '{{ meta.name }}-service' - namespace: '{{ meta.namespace }}' - labels: - app: tower -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 8052 - name: http - selector: - app: tower - -# Tower Ingress. -{% if 'ingress' == tower_ingress_type %} ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: '{{ meta.name }}-ingress' - namespace: '{{ meta.namespace }}' -spec: - rules: - - host: '{{ tower_hostname }}' - http: - paths: - - path: / - backend: - serviceName: '{{ meta.name }}-service' - servicePort: 80 -{% endif %} - -{% if 'route' == tower_ingress_type %} ---- -apiVersion: v1 -kind: Route -metadata: - name: '{{ meta.name }}' - namespace: '{{ meta.namespace }}' -spec: - port: - targetPort: http - tls: - insecureEdgeTerminationPolicy: Redirect - termination: edge - to: - kind: Service - name: {{ meta.name }}-service - weight: 100 - wildcardPolicy: None -{% endif %} diff --git a/roles/tower/vars/awx.yml b/roles/tower/vars/awx.yml new file mode 100644 index 00000000..077d023f --- /dev/null +++ b/roles/tower/vars/awx.yml @@ -0,0 +1,2 @@ +--- +uwsgi_bash: "bash -c" diff --git a/roles/tower/vars/tower.yml b/roles/tower/vars/tower.yml new file mode 100644 index 00000000..e6ff3545 --- /dev/null +++ b/roles/tower/vars/tower.yml @@ -0,0 +1,2 @@ +--- +uwsgi_bash: "scl enable rh-postgresql10" diff --git a/watches.yaml b/watches.yaml index cf3c8933..43f72fb5 100644 --- a/watches.yaml +++ b/watches.yaml @@ -1,5 +1,5 @@ --- -- version: v1alpha1 +- version: v1beta1 group: tower.ansible.com kind: Tower playbook: /opt/ansible/main.yml