--- # Tasks required by 10-quay-deploy.adoc. - name: Issue a new Cert for Quay if necessary. hosts: workstation.lab.example.com gather_subset: min tasks: - name: Check if Quay key exists to save time ansible.builtin.stat: path: "{{ ansible_facts['user_dir'] }}/ca/quay-key.pem" get_attributes: no get_checksum: no get_mime: no register: qkey_file - name: Check if Quay cert exists to save time ansible.builtin.stat: path: "{{ ansible_facts['user_dir'] }}/ca/quay-cert.pem" get_attributes: no get_checksum: no get_mime: no register: qcert_file - name: Create a new private key for Quay, if it does not exist yet. community.crypto.openssl_privatekey: path: "{{ ansible_facts['user_dir'] }}/ca/quay-key.pem" type: RSA size: 4096 mode: 0600 when: qkey_file.stat.exists == false - name: Create a CSR for Quay community.crypto.openssl_csr: path: "{{ ansible_facts['user_dir'] }}/ca/quay-csr.pem" privatekey_path: "{{ ansible_facts['user_dir'] }}/ca/quay-key.pem" subject: C: US ST: North Carolina L: Raleigh O: Red Hat OU: RHT CN: registry.ocp4.example.com use_common_name_for_san: yes mode: 0600 when: qcert_file.stat.exists == false - name: Issue a certificate for Quay if one isn't there yet. ansible.builtin.command: cmd: openssl ca -config {{ ansible_facts['user_dir'] }}/ca/openssl.cnf -passin pass:verysecret -in {{ ansible_facts['user_dir'] }}/ca/quay-csr.pem -out {{ ansible_facts['user_dir'] }}/ca/quay-cert.pem -batch -notext creates: "{{ ansible_facts['user_dir'] }}/ca/quay-cert.pem" - name: Load CA cert and Quay cert. ansible.builtin.set_fact: ca_cert: "{{ lookup('file', ansible_facts['user_dir'] + '/ca/ca-cert.pem') }}" quay_cert: "{{ lookup('file', ansible_facts['user_dir'] + '/ca/lab-ca/newcerts/00.pem') }}" - name: Concatenate Quay and CA certs. ansible.builtin.copy: dest: "{{ ansible_facts['user_dir'] }}/ca/quay-cert.pem" content: | {{ quay_cert }} {{ ca_cert }} - name: Ensure registry VM has a data directory for Quay. hosts: registry.ocp4.example.com become: yes gather_subset: min tasks: - name: Ensure data directory is there. ansible.builtin.file: path: /local/quay mode: 0770 owner: quay group: quay state: directory - name: Configure containers and their environment on registry VM. hosts: registry.ocp4.example.com gather_subset: min remote_user: quay tasks: - name: Pull all the images if necessary. containers.podman.podman_image: name: "{{ registry_host }}/quay/quay-rhel8:v{{ quay_version }}" pull: yes state: present - name: Create Quay config directory if necessary. ansible.builtin.file: path: "{{ ansible_facts['user_dir'] }}/config" state: directory mode: 0770 - name: Publish Quay key on registry. ansible.builtin.copy: src: /home/student/ca/quay-key.pem dest: "{{ ansible_facts['user_dir'] }}/config/ssl.key" mode: 0440 - name: Publish Quay cert on registry. ansible.builtin.copy: src: /home/student/ca/quay-cert.pem dest: "{{ ansible_facts['user_dir'] }}/config/ssl.cert" mode: 0440 - name: Publish Quay config file. ansible.builtin.copy: dest: "{{ ansible_facts['user_dir'] }}/config/config.yaml" content: | BUILDLOGS_REDIS: host: redis password: verysecret port: 6379 CREATE_NAMESPACE_ON_PUSH: true DATABASE_SECRET_KEY: 410c87de-8ad8-4f4c-9670-2ec25bc87191 DB_URI: postgresql://quay:secret@postgresql:5432/quay DISTRIBUTED_STORAGE_CONFIG: default: - LocalStorage - storage_path: /registry DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] DISTRIBUTED_STORAGE_PREFERENCE: - default FEATURE_MAILING: false SECRET_KEY: 7ce58d4d-b6f5-4400-ba6b-77b9f728a115 SERVER_HOSTNAME: registry.ocp4.example.com PREFERRED_URL_SCHEME: https SETUP_COMPLETE: true SUPER_USERS: - admin TESTING: false USER_EVENTS_REDIS: host: redis password: verysecret port: 6379 mode: 0660 # TODO: recursive! - name: Ensure Quay data dirs are owned by the correct user. become_method: containers.podman.podman_unshare become: yes ansible.builtin.file: path: "{{ item }}" state: directory owner: 1001 loop: - /local/quay - "{{ ansible_facts['user_dir'] }}/config" - name: Ensure systemd user dir is there. ansible.builtin.file: path: "{{ ansible_facts['user_dir'] }}/.config/systemd/user" state: directory - name: Deploy service units. ansible.builtin.template: dest: "{{ ansible_facts['user_dir'] }}/.config/systemd/user/quay.service" src: "templates/quay.service.j2" - name: Reload systemd. ansible.builtin.systemd_service: daemon_reload: yes scope: user - name: Enable services and start them. ansible.builtin.systemd_service: name: quay scope: user state: started enabled: yes register: startup - name: Wait a bit if the Quay container was just started. ansible.builtin.uri: method: GET url: https://registry.ocp4.example.com/ headers: Accept: application/json Content-Type: application/json validate_certs: no status_code: - 200 - 404 - 502 when: startup.changed register: startup_wait until: startup_wait.status == 200 retries: 30 delay: 5 - name: Check if the admin user exists already. ansible.builtin.uri: method: GET url: https://registry.ocp4.example.com/api/v1/users/admin headers: Accept: application/json Content-Type: application/json validate_certs: no status_code: - 200 - 404 return_content: yes register: adminuser_is_there - name: Create an admin user if not yet there. block: - name: Obtain an encoded CSRF token. ansible.builtin.uri: method: GET url: https://registry.ocp4.example.com/ headers: Accept: application/json Content-Type: application/json validate_certs: no return_content: yes ignore_errors: yes register: csrf_token_payload - ansible.builtin.assert: that: - csrf_token_payload.cookies['_csrf_token'] is defined fail_msg: "No CSRF token returned by registry. Can not proceed." success_msg: "Good, CSRF token found in response." # In case of issues, run with -v and this will show the raw cookie. - ansible.builtin.debug: var: csrf_token_payload.cookies verbosity: 1 - name: Store the cookie as a new fact. We need it later. ansible.builtin.set_fact: csrf_cookie: "{{ csrf_token_payload.cookies['_csrf_token'] }}" # In case of issues, run with -v and this will show the cookie payload. - ansible.builtin.debug: var: csrf_cookie verbosity: 1 # Must chop out the part of the token before the first dot (the rest is control shit). # Next, and pad it (==) at the end to have 112 characters (no checking done here). # Lastly, convert that from JSON to a dict and obtain the value of the token (_csrf_token). - name: Store CSRF token as a new fact. ansible.builtin.set_fact: csrf_token: "{{ (csrf_token_payload.cookies['_csrf_token'] | ansible.builtin.regex_replace('^(\\w+)\\..*$', '\\1==') | ansible.builtin.b64decode | ansible.builtin.from_json)['_csrf_token'] }}" # In case of issues, run with -v and this will show the decoded token. - ansible.builtin.debug: var: csrf_token verbosity: 1 - name: Send a POST request to registry API to create the admin user. ansible.builtin.uri: method: POST url: https://registry.ocp4.example.com/api/v1/user/ headers: Accept: application/json Content-Type: application/json Cookie: _csrf_token={{ csrf_cookie }} X-CSRF-Token: "{{ csrf_token }}" body: | { "username": "admin", "password": "redhat123", "repeatPassword": "redhat123", "email": "admin@example.com" } body_format: json validate_certs: no return_content: yes register: admin_user_response # In case of issues, run with -v and this will show the response. - ansible.builtin.debug: var: admin_user_response verbosity: 1 when: adminuser_is_there.status == 404 ...