diff --git a/.github/workflows/main.tf b/.github/workflows/main.tf new file mode 100644 index 0000000..60e3136 --- /dev/null +++ b/.github/workflows/main.tf @@ -0,0 +1,66 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "3.5.0" + } + } +} + + +variable "SSH_PUBLIC_KEY" { + type = string +} + +provider "google" { + + project = "quay-devel" + region = "us-central1" + zone = "us-central1-c" + +} + +resource "google_compute_network" "vpc_network" { + name = "terraform-network" +} + +resource "google_compute_instance" "vm_instance" { + name = "mirror-ci-rhel" + machine_type = "e2-medium" + + boot_disk { + initialize_params { + image = "rhel-8" + } + } + + tags = ["mirror-ci-rhel"] + + network_interface { + network = google_compute_network.vpc_network.name + access_config { + } + } + + metadata = { + ssh-keys = "jonathan:${var.SSH_PUBLIC_KEY}" + } +} + +resource "google_compute_firewall" "ssh-rule" { + name = "vm-ssh" + network = google_compute_network.vpc_network.name + allow { + protocol = "tcp" + ports = ["22", "80", "8080", "443", "8443"] + } + allow { + protocol = "icmp" + } + target_tags = ["mirror-ci-rhel"] + source_ranges = ["0.0.0.0/0"] +} + +output "ip" { + value = google_compute_instance.vm_instance.network_interface.0.access_config.0.nat_ip +} diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml new file mode 100644 index 0000000..5abcff6 --- /dev/null +++ b/.github/workflows/terraform.yml @@ -0,0 +1,94 @@ +name: "Terraform" + +on: + push: + branches: + - master + pull_request: + +jobs: + terraform: + name: "Terraform" + runs-on: ubuntu-latest + env: + GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }} + TF_VAR_SSH_PUBLIC_KEY: ${{ secrets.TF_VAR_SSH_PUBLIC_KEY }} + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install SSH Key + uses: webfactory/ssh-agent@v0.5.2 + with: + ssh-private-key: ${{ secrets.TF_VAR_SSH_PRIVATE_KEY }} + + # - name: Setup Terraform + # uses: hashicorp/setup-terraform@v1 + # with: + # # terraform_version: 0.13.0: + # cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} + + # - name: Terraform Format + # id: fmt + # run: terraform fmt -check + # working-directory: ".github/workflows" + + # - name: Terraform Init + # id: init + # run: terraform init + # working-directory: ".github/workflows" + + # - name: Terraform Plan + # id: plan + # run: terraform plan + # working-directory: ".github/workflows" + + # - name: Terraform Apply + # run: terraform apply --auto-approve + # working-directory: ".github/workflows" + + # - name: Get IP Address + # run: output=$(terraform output ip); echo $output + # working-directory: ".github/workflow" + + - name: Run playbook + uses: dawidd6/action-ansible-playbook@v2 + with: + playbook: p_install-mirror-appliance.yml + key: ${{secrets.TF_VAR_SSH_PRIVATE_KEY}} + inventory: | + [mirror] + 35.224.210.102 + + # - name: Terraform Destroy + # run: terraform destroy --auto-approve + # working-directory: ".github/workflows" + + # - uses: actions/github-script@0.9.0 + # if: github.event_name == 'pull_request' + # env: + # PLAN: "terraform\n${{ steps.plan.outputs.stdout }}" + # with: + # github-token: ${{ secrets.GITHUB_TOKEN }} + # script: | + # const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` + # #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` + # #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` + #
Show Plan + # \`\`\`${process.env.PLAN}\`\`\` + #
+ # *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`; + + # github.issues.createComment({ + # issue_number: context.issue.number, + # owner: context.repo.owner, + # repo: context.repo.repo, + # body: output + # }) + # working-directory: ".github/workflows" + + # - name: Terraform Plan Status + # if: steps.plan.outcome == 'failure' + # run: exit 1 + + \ No newline at end of file diff --git a/p_install-mirror-appliance.yml b/p_install-mirror-appliance.yml new file mode 100644 index 0000000..37ccfa6 --- /dev/null +++ b/p_install-mirror-appliance.yml @@ -0,0 +1,7 @@ +- name: "Install Mirror Appliance" + gather_facts: yes + hosts: mirror + tags: + - quay + roles: + - r_mirror-appliance diff --git a/roles/r_mirror-appliance/defaults/main.yml b/roles/r_mirror-appliance/defaults/main.yml new file mode 100644 index 0000000..9cf4c6b --- /dev/null +++ b/roles/r_mirror-appliance/defaults/main.yml @@ -0,0 +1,5 @@ +--- +redis_image: docker.io/centos/redis-5-centos8 +postgres_image: docker.io/centos/postgresql-10-centos8 +quay_image: quay.io/projectquay/quay:latest +image_archive_path: "{{playbook_dir }}/files/image-archive.yaml" diff --git a/roles/r_mirror-appliance/files/quay-config/config.yaml b/roles/r_mirror-appliance/files/quay-config/config.yaml new file mode 100644 index 0000000..196b7f2 --- /dev/null +++ b/roles/r_mirror-appliance/files/quay-config/config.yaml @@ -0,0 +1,65 @@ +AUTHENTICATION_TYPE: Database +BUILDLOGS_REDIS: + host: localhost + password: password + port: 6379 +DATABASE_SECRET_KEY: "81541057085600720484162638317561463611194901378275494293746615390984668417511" +DB_URI: postgresql://user:password@localhost/quay +DEFAULT_TAG_EXPIRATION: 2w +DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] +DISTRIBUTED_STORAGE_PREFERENCE: + - default +DISTRIBUTED_STORAGE_CONFIG: + default: + - LocalStorage + - storage_path: /datastorage +ENTERPRISE_LOGO_URL: /static/img/quay-horizontal-color.svg +FEATURE_ACI_CONVERSION: false +FEATURE_ANONYMOUS_ACCESS: true +FEATURE_APP_REGISTRY: false +FEATURE_APP_SPECIFIC_TOKENS: true +FEATURE_BUILD_SUPPORT: false +FEATURE_CHANGE_TAG_EXPIRATION: true +FEATURE_DIRECT_LOGIN: true +FEATURE_PARTIAL_USER_AUTOCOMPLETE: true +FEATURE_REPO_MIRROR: false +FEATURE_MAILING: false +FEATURE_REQUIRE_TEAM_INVITE: true +FEATURE_RESTRICTED_V1_PUSH: true +FEATURE_SECURITY_NOTIFICATIONS: true +FEATURE_SECURITY_SCANNER: false +FEATURE_USERNAME_CONFIRMATION: true +FEATURE_USER_CREATION: true +FEATURE_USER_LOG_ACCESS: true +GITHUB_LOGIN_CONFIG: {} +GITHUB_TRIGGER_CONFIG: {} +GITLAB_TRIGGER_KIND: {} +LOGS_MODEL: database +LOGS_MODEL_CONFIG: {} +LOG_ARCHIVE_LOCATION: default +PREFERRED_URL_SCHEME: http +REGISTRY_TITLE: Red Hat Quay +REGISTRY_TITLE_SHORT: Red Hat Quay +REPO_MIRROR_SERVER_HOSTNAME: null +REPO_MIRROR_TLS_VERIFY: true +SECRET_KEY: "30824339799025335633887256663000123118247018465144108496567331049820667127217" +SECURITY_SCANNER_ISSUER_NAME: security_scanner +SERVER_HOSTNAME: quay:8080 +SETUP_COMPLETE: true +SUPER_USERS: + - admin +TAG_EXPIRATION_OPTIONS: + - 0s + - 1d + - 1w + - 2w + - 4w +TEAM_RESYNC_STALE_TIME: 60m +TESTING: false +USERFILES_LOCATION: default +USERFILES_PATH: userfiles/ +USER_EVENTS_REDIS: + host: localhost + password: password + port: 6379 +USE_CDN: false diff --git a/roles/r_mirror-appliance/files/systemd/postgres.service b/roles/r_mirror-appliance/files/systemd/postgres.service new file mode 100644 index 0000000..a6ebbbe --- /dev/null +++ b/roles/r_mirror-appliance/files/systemd/postgres.service @@ -0,0 +1,31 @@ +[Unit] +Description=PostgreSQL Podman Container for Quay +Wants=network.target +After=network-online.target + +[Service] +Type=simple +TimeoutStartSec=5m +ExecStartPre=-/bin/rm -f %t/%n-pid %t/%n-cid +ExecStart=/usr/bin/podman run \ + --name quay-postgresql-service \ + -v /etc/quay-install/pg-data:/var/lib/pgsql/data:Z \ + -e POSTGRESQL_USER=user \ + -e POSTGRESQL_PASSWORD=password \ + -e POSTGRESQL_DATABASE=quay \ + --pod=quay-pod \ + --conmon-pidfile %t/%n-pid \ + --cidfile %t/%n-cid \ + --cgroups=no-conmon \ + --replace \ + docker.io/centos/postgresql-10-centos8 + +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid +PIDFile=%t/%n-pid +KillMode=none +Restart=always +RestartSec=30 + +[Install] +WantedBy=multi-user.target default.target diff --git a/roles/r_mirror-appliance/files/systemd/quay.service b/roles/r_mirror-appliance/files/systemd/quay.service new file mode 100644 index 0000000..3d14945 --- /dev/null +++ b/roles/r_mirror-appliance/files/systemd/quay.service @@ -0,0 +1,29 @@ +[Unit] +Description=Quay Container +Wants=network.target +After=network-online.target + +[Service] +Type=simple +TimeoutStartSec=5m +ExecStartPre=-/bin/rm -f %t/%n-pid %t/%n-cid +ExecStart=/usr/bin/podman run \ + --name quay-app-service \ + -v /etc/quay-install/quay-config:/conf/stack:Z \ + -v /etc/quay-install/quay-storage:/datastorage:Z \ + --pod=quay-pod \ + --conmon-pidfile %t/%n-pid \ + --cidfile %t/%n-cid \ + --cgroups=no-conmon \ + --replace \ + quay.io/projectquay/quay:latest + +ExecStop=-/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10 +ExecStopPost=-/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid +PIDFile=%t/%n-pid +KillMode=none +Restart=always +RestartSec=30 + +[Install] +WantedBy=multi-user.target default.target diff --git a/roles/r_mirror-appliance/files/systemd/redis.service b/roles/r_mirror-appliance/files/systemd/redis.service new file mode 100644 index 0000000..63f73ce --- /dev/null +++ b/roles/r_mirror-appliance/files/systemd/redis.service @@ -0,0 +1,29 @@ +[Unit] +Description=Redis Podman Container for Quay +Wants=network.target +After=network-online.target + +[Service] +Type=simple +TimeoutStartSec=5m +ExecStartPre=-/bin/rm -f %t/%n-pid %t/%n-cid +ExecStart=/usr/bin/podman run \ + --name quay-redis-service \ + -e REDIS_PASSWORD=password \ + --pod=quay-pod \ + --conmon-pidfile %t/%n-pid \ + --cidfile %t/%n-cid \ + --cgroups=no-conmon \ + --replace \ + docker.io/centos/redis-5-centos8 + +ExecStop=-/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10 +ExecStopPost=-/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid +PIDFile=%t/%n-pid +KillMode=none +Restart=always +RestartSec=30 + +[Install] +WantedBy=multi-user.target default.target + diff --git a/roles/r_mirror-appliance/meta/main.yml b/roles/r_mirror-appliance/meta/main.yml new file mode 100644 index 0000000..2e5c36c --- /dev/null +++ b/roles/r_mirror-appliance/meta/main.yml @@ -0,0 +1,3 @@ +--- +allow_duplicates: false + diff --git a/roles/r_mirror-appliance/tasks/autodetect-image-archive.yaml b/roles/r_mirror-appliance/tasks/autodetect-image-archive.yaml new file mode 100644 index 0000000..24b96a0 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/autodetect-image-archive.yaml @@ -0,0 +1,7 @@ +- name: Ansible check file exists. + stat: + path: "{{ image_archive_path }}" + register: p +- name: Image Archive Found. Loading Images. + command: "podman load -i {{ image_archive_path }}" + when: p.stat.exists diff --git a/roles/r_mirror-appliance/tasks/create-podman-pod.yaml b/roles/r_mirror-appliance/tasks/create-podman-pod.yaml new file mode 100644 index 0000000..23f23e7 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/create-podman-pod.yaml @@ -0,0 +1,7 @@ +- name: Create podman pod for shared network namespace + containers.podman.podman_pod: + name: quay-pod + state: started + ports: + - 80:8080 + - 443:8443 diff --git a/roles/r_mirror-appliance/tasks/install-postgres-service.yaml b/roles/r_mirror-appliance/tasks/install-postgres-service.yaml new file mode 100644 index 0000000..a440792 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/install-postgres-service.yaml @@ -0,0 +1,32 @@ +- name: Create necessary directory for Postgres persistent data + ansible.builtin.file: + path: /etc/quay-install/pg-data + state: directory + recurse: yes + +- name: Set permissions on data directory + ansible.posix.acl: + path: /etc/quay-install/pg-data + entry: u:26:-wx + state: present + +- name: Copy Postgres systemd service file + template: src=../files/systemd/postgres.service dest=/etc/systemd/system/quay-postgres.service + +- name: Pull Postgres image + containers.podman.podman_image: + name: "{{ postgres_image }}" + +- name: Start Postgres service + systemd: + name: quay-postgres.service + enabled: yes + daemon_reload: yes + state: started + +- name: Wait for pg_trgm to be installed + command: podman exec -it quay-postgresql-service /bin/bash -c "echo 'CREATE EXTENSION IF NOT EXISTS pg_trgm' | psql -d quay -U postgres" + register: result + until: result.rc == 0 + retries: 20 + delay: 5 diff --git a/roles/r_mirror-appliance/tasks/install-quay-service.yaml b/roles/r_mirror-appliance/tasks/install-quay-service.yaml new file mode 100644 index 0000000..1300ed6 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/install-quay-service.yaml @@ -0,0 +1,34 @@ +- name: Create necessary directory for Quay local storage + ansible.builtin.file: + path: /etc/quay-install/quay-storage + state: directory + recurse: yes + +- name: Create necessary directory for Quay config bundle + ansible.builtin.file: + path: /etc/quay-install/quay-config + state: directory + recurse: yes + +- name: Set permissions on local storage directory + ansible.posix.acl: + path: /etc/quay-install/quay-storage + entry: u:1001:-wx + state: present + +- name: Copy Quay config.yaml file + template: src=../files/quay-config/config.yaml dest=/etc/quay-install/quay-config + +- name: Copy Quay systemd service file + template: src=../files/systemd/quay.service dest=/etc/systemd/system/quay-app.service + +- name: Pull Quay image + containers.podman.podman_image: + name: "{{ quay_image }}" + +- name: Start Quay service + systemd: + name: quay-app.service + enabled: yes + daemon_reload: yes + state: started diff --git a/roles/r_mirror-appliance/tasks/install-redis-service.yaml b/roles/r_mirror-appliance/tasks/install-redis-service.yaml new file mode 100644 index 0000000..48516a4 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/install-redis-service.yaml @@ -0,0 +1,13 @@ +- name: Copy Redis systemd service file + template: src=../files/systemd/redis.service dest=/etc/systemd/system/quay-redis.service + +- name: Pull Redis image + containers.podman.podman_image: + name: "{{ redis_image }}" + +- name: Start Redis service + systemd: + name: quay-redis.service + enabled: yes + daemon_reload: yes + state: started diff --git a/roles/r_mirror-appliance/tasks/main.yaml b/roles/r_mirror-appliance/tasks/main.yaml new file mode 100644 index 0000000..8538190 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/main.yaml @@ -0,0 +1,17 @@ +- name: Set SELinux Rules + include_tasks: set-selinux-rules.yaml + +- name: Create Podman Pod + include_tasks: create-podman-pod.yaml + +- name: Autodetect Image Archive + include_tasks: autodetect-image-archive.yaml + +- name: Install Postgres Service + include_tasks: install-postgres-service.yaml + +- name: Install Redis Service + include_tasks: install-redis-service.yaml + +- name: Install Quay Service + include_tasks: install-quay-service.yaml diff --git a/roles/r_mirror-appliance/tasks/set-selinux-rules.yaml b/roles/r_mirror-appliance/tasks/set-selinux-rules.yaml new file mode 100644 index 0000000..1ecb501 --- /dev/null +++ b/roles/r_mirror-appliance/tasks/set-selinux-rules.yaml @@ -0,0 +1,5 @@ +- name: Set container_manage_cgroup flag on and keep it persistent across reboots + ansible.posix.seboolean: + name: container_manage_cgroup + state: yes + persistent: yes