#2193 OpenShift deployment proposal
Opened 2 months ago by praiskup. Modified a month ago
copr/ praiskup/copr openshift  into  main

@@ -38,11 +38,6 @@ 

          destination = os.path.join(opts.lookaside_location, reponame,

                                     filename, filehash, filename)

  

-         # hack to allow "uploading" into lookaside

-         current_gid = os.getgid()

-         apache_gid = grp.getgrnam("apache").gr_gid

-         os.setgid(apache_gid)

- 

          if not os.path.isdir(os.path.dirname(destination)):

              try:

                  os.makedirs(os.path.dirname(destination))
@@ -52,8 +47,6 @@ 

          if not os.path.exists(destination):

              shutil.copyfile(abs_filename, destination)

  

-         os.setgid(current_gid)

- 

      return my_upload

  

  

file modified
+9 -7
@@ -5,7 +5,7 @@ 

  # pod that listen on the same port.  Therefore we start httpd servers on ports

  # (host:pod):

  #   5000:5000 -- Frontend Apache (API/WebUI)

- #   5001:80   -- DistGit Apache

+ #   5001:5001 -- DistGit Apache

  #   5002:5002 -- Backend Nginx

  #     --:5003 -- Keygen Apache (obtaining keys)

  #
@@ -34,7 +34,7 @@ 

      build:

        context: docker/backend

      hostname: backend-build

-     command: /usr/sbin/runuser -u copr -g copr -G obsrun -- /usr/bin/copr-run-dispatcher builds

+     command: /usr/sbin/runuser -u copr -g copr -G obsrun -- /run-backend /usr/bin/copr-run-dispatcher builds

      depends_on:

        - backend-log

        - resalloc
@@ -48,7 +48,7 @@ 

      build:

        context: docker/backend

      hostname: backend-action

-     command: /usr/sbin/runuser -u copr -g copr -- /usr/bin/copr-run-dispatcher actions

+     command: /usr/sbin/runuser -u copr -g copr -- /run-backend /usr/bin/copr-run-dispatcher actions

      depends_on:

        - backend-log

        - resalloc
@@ -138,29 +138,31 @@ 

  

    distgit-httpd:

      build:

-       context: docker/distgit-httpd/

+       context: docker/distgit/

      hostname: distgit-httpd

      stdin_open: true

      tty: true

      ports:

-       - "5001:80"

+       - "5001:5001"

      volumes:

        - .:/opt/copr:z

        - dist-git:/var/lib/dist-git:z

+     command: /usr/sbin/httpd -DFOREGROUND

  

    keygen-signd:

      build:

-       context: docker/keygen-signd/

+       context: docker/keygen/

      hostname: keygen-signd

      stdin_open: true

      tty: true

      volumes:

        - .:/opt/copr:z

        - copr-keygen:/var/lib/copr-keygen:z

+     command: /signd-entrypoint

  

    keygen-httpd:

      build:

-       context: docker/keygen-httpd/

+       context: docker/keygen/

      hostname: keygen-httpd

      stdin_open: true

      tty: true

file modified
+10 -4
@@ -4,14 +4,16 @@ 

  ENV export LANG=en_US.UTF-8

  ENV PYTHONPATH="/usr/share/copr/"

  

- RUN dnf -y install dnf-plugins-core && dnf -y copr enable @copr/copr

- 

  # TERM is to make the tito work in container, rhbz#1733043

  ENV TERM=linux \

      LANG=en_US.UTF-8

  

  # base packages

- RUN dnf -y update && \

+ RUN dnf -y install dnf-plugins-core && \

+     dnf -y copr enable @copr/copr && \

+     dnf -y copr enable praiskup/obs-sign-noeuid && \

+     dnf -y history undo last && \

Why do we want to undo anything?

+     dnf -y update && \

      dnf -y install htop \

                     make \

                     wget \
@@ -70,7 +72,11 @@ 

      chown -R copr:copr /home/copr

  

  # copr user needs permissions for /bin/sign

- RUN gpasswd -a copr obsrun

+ RUN chmod 0755 /usr/bin/sign

+ 

+ # entrypoint needs to have write access here (group=0)

+ RUN chown copr:root /etc/sign.conf && \

+     chmod 0660 /etc/sign.conf

  

  # Not sure why the directory wasn't created automatically

  RUN mkdir /var/lock/copr-backend

@@ -1,2 +0,0 @@ 

- server: keygen-signd

- allowuser: copr

@@ -0,0 +1,38 @@ 

+ #! /bin/bash

+ 

+ option_variable()

+ {

+     opt=$1

+     opt=${1##--}

+     opt=${opt##-}

+     opt=${opt//-/_}

+     option_variable_result=opt_$opt

+ }

+ 

+ opt_sign_user=$(id -u)

+ opt_sign_host=keygen-signd

+ 

+ ARGS=$(getopt -o "" -l "sign-user:,sign-host:" -n "getopt" -- "$@") \

+     || show_help 1

+ eval set -- "$ARGS"

+ while true; do

+     case $1 in

+     # options with arguments

+     --sign-host|--sign-user)

+         option_variable "$1"

+         eval "$option_variable_result=\$2"

+         shift 2

+         ;;

+     --) shift; break;;  # end

+     *) echo "programmer mistake ($1)" >&2; exit 1;;

+     esac

+ done

+ 

+ cat >/etc/sign.conf <<EOF

I think I understand why it needs to be done here, but it would deserve some comment

+ server: $opt_sign_host

+ allowuser: $opt_sign_user

+ allow-unprivileged-ports: true

+ EOF

+ 

+ # execute the remaining part of the command

+ exec "$@"

@@ -1,26 +0,0 @@ 

- FROM registry.fedoraproject.org/fedora:35

- MAINTAINER copr-devel@lists.fedorahosted.org

- 

- # TERM is to make the tito work in container, rhbz#1733043

- ENV TERM=linux

- 

- # For copr-common

- RUN dnf -y install dnf-plugins-core && dnf -y copr enable @copr/copr

- 

- # base packages

- RUN dnf -y update && \

-     dnf -y install htop \

-                    which \

-                    wget \

-                    vim \

-                    cgit

- 

- RUN dnf -y install copr-dist-git && \

-     dnf clean all

- 

- RUN rm /etc/httpd/conf.d/ssl.conf

- 

- RUN echo "AliasMatch \"/repo(/.*)/md5(/.*)\" \"/var/lib/dist-git/cache/lookaside\\$1\\$2\"" >> /etc/httpd/conf.d/dist-git/lookaside-copr.conf && \

-     echo "Alias /repo/ /var/lib/dist-git/cache/lookaside/" >>  /etc/httpd/conf.d/dist-git/lookaside-copr.conf

- 

- CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

file modified
+15 -6
@@ -5,21 +5,28 @@ 

  ENV TERM=linux

  ENV PYTHONPATH=/usr/share/copr/

  

- RUN dnf -y install dnf-plugins-core && dnf -y copr enable @copr/copr

- 

  # base packages

- RUN dnf -y update && \

+ RUN dnf -y install dnf-plugins-core && \

+     dnf -y copr enable @copr/copr && \

+     dnf -y update && \

      dnf -y install htop \

                     which \

                     wget \

                     vim \

                     cgit \

                     python3-rpkg \

-                    python3-ipdb

- 

- RUN dnf -y install copr-dist-git && \

+                    python3-ipdb \

+                    && \

+     dnf -y install copr-dist-git && \

      dnf clean all

  

+ RUN rm /etc/httpd/conf.d/ssl.conf

+ 

+ RUN echo "AliasMatch \"/repo(/.*)/md5(/.*)\" \"/var/lib/dist-git/cache/lookaside\\$1\\$2\"" >> /etc/httpd/conf.d/dist-git/lookaside-copr.conf && \

+     echo "Alias /repo/ /var/lib/dist-git/cache/lookaside/" >>  /etc/httpd/conf.d/dist-git/lookaside-copr.conf

+ 

+ RUN sed -i 's/Listen 80/Listen 5001/' /etc/httpd/conf/httpd.conf

+ 

  RUN mkdir /tmp/copr-dist-git

  RUN chown copr-dist-git:packager /tmp/copr-dist-git

  
@@ -36,4 +43,6 @@ 

  RUN sed -i "s/^cache-size.*//" /etc/cgitrc

  RUN echo 'scan-path=/var/lib/dist-git/git/rpms' | tee -a /etc/cgitrc

  

+ RUN chown root:root /var/run/httpd && chmod g+rwx /var/run/httpd

+ 

  CMD ["/usr/sbin/runuser", "-u", "root", "-g", "packager", "/usr/bin/importer_runner.py"]

@@ -1,6 +1,6 @@ 

  #! /bin/sh

  

- cd

+ cd /usr/share/copr/coprs_frontend/

  ./manage.py create-db --alembic alembic.ini

  ./manage.py create-chroot fedora-rawhide-x86_64

  exec /usr/sbin/httpd -DFOREGROUND

@@ -1,5 +0,0 @@ 

- #! /bin/sh

- 

- # restore the ownership on files on volumes

- rpm --setugids copr-keygen

- exec /usr/sbin/httpd "-DFOREGROUND"

@@ -1,15 +0,0 @@ 

- FROM registry.fedoraproject.org/fedora:35

- MAINTAINER copr-devel@lists.fedorahosted.org

- 

- # Copy files from the host into the container

- COPY files/ /

- 

- # Create copr-signer:copr-signer manually, so we can

- # be sure that the UID and GID is same on all keygen containers

- RUN groupadd -r copr-signer -g 992

- RUN useradd -r copr-signer -u 993 -g 992 -d /var/lib/copr-keygen

- 

- # Install copr-keygen package

- RUN dnf -y update gnupg2 && dnf -y install copr-keygen && dnf clean all

- 

- CMD ["/usr/sbin/signd"]

@@ -1,18 +0,0 @@ 

- ---

- 

- # See `man sign.conf`

- #

- #    Allow only connections from the specified ip addresses,

- #    subnets expressed in CIDR notation, and/or hostnames.

- #    Note that hostnames are resolved using reverse DNS

- #    lookups, so there must be reverse entries in the DNS

- #    server, and it should be secured against DNS poisoning

- #    attacks.

- #    Must be present.

- #

- # Since we cannot easily allow hostnames and containers IP

- # addresses may change, just hackily allow everything

- allow: 0.0.0.0/0

- 

- phrases: /var/lib/copr-keygen/phrases

- gpg: /bin/gpg_copr.sh

docker/keygen/Dockerfile docker/keygen-httpd/Dockerfile
file renamed
+27 -10
@@ -6,10 +6,12 @@ 

  # Create copr-signer:copr-signer manually, so we can

  # be sure that the UID and GID is same on all keygen containers

  RUN groupadd -r copr-signer -g 992

- RUN useradd -r copr-signer -u 993 -g 992 -d /var/lib/copr-keygen

+ RUN useradd -r copr-signer -u 993 -g 992 -G 0 -d /var/lib/copr-keygen

  

  # base packages

  RUN dnf -y update && \

+     dnf -y install dnf-plugins-core && \

+     dnf -y copr enable praiskup/obs-sign-noeuid && \

      dnf -y install htop \

                     httpd \

                     make \
@@ -26,17 +28,32 @@ 

      dnf -y install copr-keygen && \

      dnf clean all

  

- # system setup for copr-keygen

- RUN mkdir /var/log/uwsgi /var/run/uwsgi && \

-     chown apache:apache /var/log/uwsgi && \

-     chmod 775 /var/log/uwsgi && \

-     chown apache:apache /var/run/uwsgi && \

-     chmod 775 /var/run/uwsgi && \

-     usermod copr-signer -G apache

- 

  # Copy files from the host into the container

  COPY files/ /

  

  RUN sed -i 's/Listen 80/#Listen 80/g' /etc/httpd/conf/httpd.conf

  

- CMD ["/entrypoint"]

+ # OpenShift runs this project as <RANDOMUID>:root

+ # Podman runs this as copr-signer with root in supplementary groups

+ RUN chmod g+rwx /var/log/httpd

+ 

+ # Drop the suid bit

+ RUN chmod 0755 /usr/bin/sign

+ 

+ # entrypoint needs to have write access here (group=0)

+ RUN chown copr-signer:root /etc/sign.conf && \

+     chmod 0660 /etc/sign.conf

+ 

+ # TODO: we should just check for non-root accounts

+ RUN sed -i "s|getpass.getuser() != 'copr-signer'|False|" /usr/bin/gpg-copr

+ 

+ RUN dirs="/var/run/signd /var/run/httpd" ; \

+     for dir in $dirs; do \

+       mkdir -p "$dir" && \

+       chown root:root "$dir" && \

+       chmod 0770 "$dir" ; \

+     done

+ 

+ USER copr-signer

+ 

+ CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

I think this shouldn't be here. Not sure if CMD is required, if it is, I would put bash or exit there, or something, because this line is IMHO never executed, and it is overrided by docker-compose.

docker/keygen/files/etc/httpd/conf.d/copr-keygen.conf docker/keygen-httpd/files/etc/httpd/conf.d/copr-keygen.conf
file renamed
file was moved with no change to the file
@@ -0,0 +1,17 @@ 

+ #! /bin/bash

+ 

+ allow_statement=$1

+ test -z "$allow_statement" && allow_statement="0.0.0.0/0"

+ 

+ cat >/etc/sign.conf <<EOF

+ allow: $allow_statement

+ phrases: /var/lib/copr-keygen/phrases

+ gpg: /usr/bin/gpg-copr

+ allowuser: $(id -u)

+ allow-unprivileged-ports: true

+ EOF

+ 

+ # In case the volume is empty.

+ mkdir --mode=0700 -p /var/lib/copr-keygen/phrases /var/lib/copr-keygen/gnupg

+ 

+ exec /usr/sbin/signd

file modified
+5 -2
@@ -7,12 +7,15 @@ 

  # Copr production deployment is described here

  # https://pagure.io/fedora-infra/ansible/blob/master/f/roles/copr/backend/tasks/resalloc.yml

  

- RUN dnf install -y vim \

+ RUN dnf install -y ansible \

+                    vim \

                     resalloc \

+                    resalloc-aws \

                     resalloc-server \

                     sqlite \

                     findutils \

-                    openssh-clients

+                    openssh-clients \

+     && dnf clean all

  

  # copy filesystem setup

  COPY files/ /

@@ -0,0 +1,1 @@ 

+ secret*

file added
+4
@@ -0,0 +1,4 @@ 

+ AP := ansible-playbook -vv -c local -i localhost,

+ 

+ deploy:

+ 	$(AP) deploy.yml

file added
+69
@@ -0,0 +1,69 @@ 

+ Deploy Copr build system in OpenShift

+ =====================================

+ 

+ ... in two minutes, if you have AWS credentials.

:D

+ 

+ This directory contains the deployment scripts and base configuration that allow

+ you to quickly deploy a fully-working Copr build system infrastructure into an

+ OpenShift cluster, with builders being automatically started in cloud (currently

+ pre-configured AWS).

+ 

+ Note: At the time of writing this document, it is not common to be able to start

+ privileged containers in OpenShift, nor rootless containers (user namespaces).

+ Therefore, builders need to stay as virtual machines only.

+ 

+ 1. get an OpenShift Cluster

+ 2. get AWS token (for EC2 access)

+ 3. $ cp secret-vars.yml.template secret-vars.yml and fill the gaps

+ 4. hit the $ make

+ 

To be honest, I don't know how to fill the gaps in the secret-vars.yml file.

Can you please enhance this document, the template file, or add a new Fedora copr specific deployoment document?

  • Where is our instance of OpenShift?
  • What --server do I specify for oc login?
  • Where do I find the passwords, etc

Thank you for the feedback. I'll try to fill the gaps with some better placeholders (plus we have the internal documentation for the Red Hat stage stack). Perhaps we could experiment with the Fedora infra OpenShift...

+ Currently we maintain the images here: https://quay.io/organization/copr

+ 

+ WARNING: This deployment is in a pre-production state!

+ 

+ TODO

+ ====

+ 

+ - copr-keygen pod signing process needs to be secured, currently the pod accepts

+   sign requests from any other pod in the project because we "allow 0.0.0.0/0"

+ 

+ - start logging to stdout/stderr, so we can just do 

+   'oc logs <podname> -c <container>', according to

+   https://docs.openshift.com/container-platform/4.9/openshift_images/create-images.html

+   Alternatively at least implement log-rotation.

+ 

+ - this should be applied downstream in Fedora

+   https://github.com/openSUSE/obs-sign/pull/36

+ 

+ - zombie reaping?

+ 

+ - Let's Encrypt automation

+ 

+ - starting the containers against a locally maintained code (from git root),

+   currently we just use 'docker-compose'

+ 

+ - automate PostgreSQL initialization from a SQL dump file

+ 

+ - cron jobs (automatic build removals, etc.)

+ 

+ - better container image tagging (currently everything in :test)

+ 

+ - automatic image builds (quay.io builds are broken for F35

+   https://bugzilla.redhat.com/show_bug.cgi?id=2025899)

+ 

+ - automatize the AWS SSH key creation/removal (this is the hardest part in the

+   secret-vars.yml config file)

+ 

+ - separate the normal and secret vars (now everything is in secret-vars.yml)

+ 

+ 

+ Research

+ ========

+ 

+ - write an operator for starting builders hosted in OpenShift?  But we need to

+   wait for the state when "user namespaces" are "commonly" available

+ 

+ - automatic termination of orphaned resalloc instances - this happens easily

+   when project is deleted (oc delete project <your project>)

+ 

+ - experiment with Terraform, instead of Ansible

@@ -0,0 +1,24 @@ 

+ [backend]

+ results_baseurl=http://copr-backend:8080/results/

+ frontend_base_url=http://copr-frontend:5000

+ frontend_auth={{ frontend_backend_password }}

+ destdir=/var/lib/copr/public_html/results

+ sleeptime=20

+ builds_max_workers=3

+ actions_max_workers=2

+ do_sign=true

+ keygen_host=copr-keygen:5003

+ prune_days=14

+ resalloc_connection=http://resalloc:49100

+ 

+ redis_host=redis

+ redis_port=6379

+ redis_db=1

+ 

+ 

+ [builder]

+ timeout=108000

+ consecutive_failure_threshold=30

+ 

+ [ssh]

+ builder_config=/backend-home/.ssh/config

empty or binary file added
@@ -0,0 +1,4 @@ 

+ [dist-git]

+ frontend_base_url=http://copr-frontend:5000

+ frontend_auth={{ frontend_backend_password }}

+ per_task_log_dir=/var/lib/copr-dist-git/per-task-logs/

@@ -0,0 +1,10 @@ 

+ [dist-git]

+ git_author_name  = Copr Dist Git

+ git_author_email = <copr-devel@lists.fedoraproject.org>

+ 

+ cache_dir   = /var/lib/dist-git/cache

+ gitroot_dir = /var/lib/dist-git/git

+ #this is difference from standard config!

+ git_gc_depth   = 3

+ 

+ gitolite    = False

@@ -0,0 +1,35 @@ 

+ ENV="local"

+ BACKEND_PASSWORD = "{{ frontend_backend_password }}"

+ SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://{{ postgres_user }}:{{ postgres_password }}@postgresql/{{ postgres_database_name }}'

+ DEBUG = True

+ SQLALCHEMY_ECHO = False

+ SEND_EMAILS = False

+ PUBLIC_COPR_HOSTNAME = 'localhost:5000'

+ PUBLIC_COPR_BASE_URL = 'http://frontend:5000'

+ BACKEND_BASE_URL = 'http://{{ backend_fqdn }}/'

+ DIST_GIT_CLONE_URL = 'http://{{ distgit_fqdn }}/git/'

+ DIST_GIT_URL = 'http://localhost:5001/cgit'

+ COPR_DIST_GIT_LOGS_URL = 'http://localhost:5001/per-task-logs'

+ LOG_FILENAME = "/var/log/copr-frontend/frontend.log"

+ LOG_DIR = "/var/log/copr-frontend/"

+ INTRANET_IPS = ["127.0.0.1", "192.168.1.0/24"]

+ BUILDER_IPS = ["127.0.0.1"]

+ STORAGE_DIR = "/var/lib/copr/data/srpm_storage"

+ GROUP_DENYLIST = ['fedorabugs', 'packager', 'provenpackager']

+ REDIS_HOST = "redis"

+ REDIS_PORT = 6379

+ NEWS_URL = "https://fedora-copr.github.io/"

+ NEWS_FEED_URL = "https://fedora-copr.github.io/feed.xml"

+ OPENID_PROVIDER_URL = "https://id.fedoraproject.org"

+ DELETE_EOL_CHROOTS_AFTER = 180

+ EOL_CHROOTS_NOTIFICATION_PERIOD = 80

+ ENABLE_DISCUSSION = False

+ ITEMS_PER_PAGE = 10

+ PAGES_URLS_COUNT = 5

+ DEFAULT_BUILD_MEMORY = 2048

+ MIN_BUILD_MEMORY = 2048

+ MAX_BUILD_MEMORY = 4096

+ DEFAULT_BUILD_TIMEOUT = 3600 * 5

+ MIN_BUILD_TIMEOUT = 0

+ MAX_BUILD_TIMEOUT = 108000

+ CACHE_TYPE = "NullCache"

@@ -0,0 +1,3 @@ 

+ [default]

+ aws_access_key_id={{ aws_config.access_key_id }}

+ aws_secret_access_key={{ aws_config.secret_access_key }}

@@ -0,0 +1,51 @@ 

+ # vi: ft=yaml

+ ---

+ copr_os_{{ project.replace("-", "_") }}_{{ deployment }}_aws_x86:

+   max: 4

+   max_starting: 1

+   max_prealloc: 1

+   tags:

+     - copr_builder

+     - arch_noarch

+     - arch_x86_64

+     - arch_x86_64_native

+     - arch_i386

+     - arch_i386_native

+     - arch_i586

+     - arch_i586_native

+     - arch_i686

+     - arch_i686_native

+     - arch_s390x

+     - arch_s390x_emulated

+     - arch_ppc64le

+     - arch_ppc64le_emulated

+     - arch_aarch64

+     - arch_aarch64_emulated

+   cmd_new: |

+     set -x

+     /usr/bin/resalloc-aws-new \

+     --aws-profile default \

+     --ami ami-09127a5df568314d3 \

+     --ssh-key-name "{{ aws_config.ssh_key.name }}" \

+     --debug \

+     --private-ip \

+     --security-group-id sg-07a0adee998a8fcde \

+     --possible-subnet subnet-0b853a752f0f7eba5 \

+     --possible-subnet subnet-05dd25fba5582bb6a \

+     --instance-type t3a.medium \

+     --tag RedHatGroup=copr \

+     --tag ServiceName=copr \

+     --tag ServiceComponent=builder-testing-copr-openshift \

+     --tag ServiceOwner=Copr \

+     --tag AppCode=COPR-001 \

+     --tag ServicePhase=Dev \

+     --tag CoprInstance=testing-openshift \

+     --tag arch=x86_64 \

+     --playbook /etc/resallocserver/spinup-playbook.yml

+ 

+   cmd_delete: /usr/bin/resalloc-aws-delete --aws-profile default

+   cmd_livecheck: "resalloc-check-vm-ip"

+   livecheck_period: 180

+   reuse_opportunity_time: 180

+   reuse_max_count: 8

+   reuse_max_time: 1800

@@ -0,0 +1,4 @@ 

+ db_url: 'sqlite:////var/lib/resallocserver/db.sqlite'

+ logdir: '/var/log/resallocserver'

+ hostname: '0.0.0.0'

+ loglevel: 'debug'

@@ -0,0 +1,68 @@ 

+ ---

+ - name: provision AWS builder

+   hosts: all

+   become: true

+   user: fedora

+ 

+   vars:

+     devel: true

+     ansible_python_interpreter: /usr/bin/python3

+ 

+   tasks:

+     - name: setup the hostname so we can easily identify the box

+       hostname: name="{% raw %}{{ lookup('env', 'RESALLOC_NAME') | default('unknown-builder') | replace('_', '-') }}{% endraw %}"

+ 

+     - name: disable updates-testing

+       file:

+         path: /etc/yum.repos.d/fedora-updates-testing.repo

+         state: absent

+ 

+     - name: stop and disable systemd-oomd, rhbz 2051154

+       service:

+         name: systemd-oomd

+         state: stopped

+         enabled: no

+ 

+     - name: install copr-builder and other latest packages

+       dnf: state=latest pkg=copr-builder

+ 

+     - name: run /bin/copr-update-builder from copr-builder package

+       shell: /usr/bin/copr-update-builder

+ 

+     - name: put copr-rpmbuild configuration file in the right place

+       copy:

+         dest: /etc/copr-rpmbuild/main.ini

+         content: |

+           [main]

+           frontend_url = {{ frontend_base_url }}

+           distgit_lookaside_url = https://{{ '${%' }} raw {{ '%}{{' }} git_props:remote_netloc {{ '}}{%' }} endraw {{ '%}' }}/repo/pkgs/%(repo_path)s/%(filename)s/%(hashtype)s/%(hash)s/%(filename)s

+           distgit_clone_url = {scheme}://{netloc}/%(repo_path)s

+           rpm_vendor_copr_name = Testing Copr

+ 

+           [distgit0]

+           distgit_hostname_pattern = src.fedoraproject.org

+           distgit_lookaside_url = https://src.fedoraproject.org/repo/pkgs/%(ns1)s/%(name)s/%(filename)s/%(hashtype)s/%(hash)s/%(filename)s

+           distgit_clone_url = https://src.fedoraproject.org/%(repo_path)s

+ 

+     - name: install copr-distgit-client configuration

+       copy:

+         dest: /etc/copr-distgit-client/local-copr.ini

+         content: |

+           [local-copr]

+           clone_hostnames = {{ distgit_fqdn }}

+           lookaside_location = http://{{ distgit_fqdn }}

+           lookaside_uri_pattern = repo/pkgs/{namespace[1]}/{namespace[0]}/{name}/{filename}/{hash}/{filename}

+ 

+     - name: mockbuilder authorized_keys

+       authorized_key: user=mockbuilder key="{{ aws_config.ssh_key.public }}"

+ 

+     - name: root authorized_keys

+       authorized_key: user=root key="{{ aws_config.ssh_key.public }}"

+ 

+     - name: mount cache filesystem on /var/cache/mock

+       mount: path=/var/cache/mock state=mounted src=mock_cache_tmpfs fstype=tmpfs opts="size=32G"

+ 

+     - name: Collect facts about builder hardware

+       setup:

+         gather_subset:

+           - hardware

file added
+226
@@ -0,0 +1,226 @@ 

+ ---

+ - name: Copr deployment

+   hosts: all

+   vars:

+     validate_certs: false

+     service: copr

+     deployment: dev

+     sandbox_namespace: "{{ service }}-{{ deployment }}-sandbox"

+     project_dir: "{{ playbook_dir }}"

+     path_to_secrets: "{{ project_dir }}/secrets"

+     path_to_services: "{{ project_dir }}/services"

+ 

+     postgres_user: copr-fe

+     postgres_database_name: copr-db

+ 

+   vars_files:

+     "{{ project_dir }}/secret-vars.yml"

+ 

+   tasks:

+     - name: detect the currently operated OpenShift cluster

+       shell: oc config view --minify -o jsonpath='{.clusters[*].cluster.server}'

+       register: oc_api_endpoint_detected

+       changed_when: false

+       tags: always

+ 

+     - name: check that we work with the right OpenShift cluster

+       assert:

+         that:

+           - oc_api_endpoint_detected.stdout_lines[0] == oc_api_endpoint

+         msg: "OpenShift API mismatch"

+       tags: always

+ 

+     - name: detect the OpenShift API key - ARE YOU LOGGED IN?

+       command: oc whoami -t

+       register: openshift_token_detected

+       no_log: true

+       changed_when: false

+       tags: always

+ 

+     - name: define the api_key variable

+       set_fact:

+         api_key: "{{ openshift_token_detected.stdout_lines[0] }}"

+       tags: always

+ 

+     - name: Create the project

+       k8s:

+         definition: "{{ lookup('template', 'project.yaml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: always

+ 

+     # Normally we would use 'image: " "' in the PG template, but the k8s Ansible

+     # module doesn't seem to realize it means "no change" and reports "changed"

+     # all the time.  Therefore we detect it first.

+     - name: Get the actual PostgreSQL image from ImageStream

+       shell: oc get dc postgresql -o jsonpath='{.spec.template.spec.containers[0].image}'

+       register: pgis

+       changed_when: false

+       failed_when: false

+ 

+     - set_fact: postgresql_image={{ pgis.stdout }}

+ 

+     - name: Deploy PostgreSQL service

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/postgres.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+ 

+ 

+     # Normally we would use 'image: " "' in the PG template, but the k8s Ansible

+     # module doesn't seem to realize it means "no change" and reports "changed"

+     # all the time.  Therefore we detect it first.

+     - name: Get the actual Redis image from ImageStream

+       shell: oc get dc redis -o jsonpath='{.spec.template.spec.containers[0].image}'

+       register: r_is

+       changed_when: false

+       failed_when: false

+     - set_fact: redis_image={{ r_is.stdout }}

+ 

+     - name: Deploy Redis service

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/redis.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+ 

+     # Normally we would use 'image: " "' in the PG template, but the k8s Ansible

+     # module doesn't seem to realize it means "no change" and reports "changed"

+     # all the time.  Therefore we detect it first.

+     - name: Get the actual Copr Frontend image from an ImageStream

+       shell: oc get dc copr-frontend -o jsonpath='{.spec.template.spec.containers[0].image}'

+       register: cf_is

+       changed_when: false

+       failed_when: false

+       tags: frontend

+ 

+     - set_fact: copr_frontend_image={{ cf_is.stdout }}

+       tags: frontend

+ 

+     - name: Instantiate Frontend config

+       set_fact:

+         frontend_config: "{{ lookup('template', '{{ project_dir }}/config/frontend-copr.conf') }}"

+       tags:

+         - frontend

+       no_log: true

+ 

+     - name: Deploy Copr Frontend pod

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/frontend.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: frontend

+ 

+     - name: get the latest resalloc image

+       shell: oc get istag/resalloc:test -o jsonpath='{.image.dockerImageReference}'

+       register: resalloc_is

+       changed_when: false

+       failed_when: false

+       tags: resalloc

+ 

+     - name: Instantiate Frontend config

+       set_fact:

+         frontend_config: "{{ lookup('template', '{{ project_dir }}/config/frontend-copr.conf') }}"

+       tags:

+         - frontend

+       no_log: true

+ 

+     - name: instantiate Resalloc config

+       set_fact:

+         resalloc_pool_yaml: "{{ lookup('template', '{{ project_dir }}/config/resalloc-pool.yaml.j2') }}"

+         resalloc_server_yaml: "{{ lookup('template', '{{ project_dir }}/config/resalloc-server.yaml.j2') }}"

+         resalloc_image: "{{ resalloc_is.stdout }}"

+         aws_credentials: "{{ lookup('template', '{{ project_dir }}/config/resalloc-aws-credentials.j2') }}"

+         resalloc_spinup_playbook: "{{ lookup('file', '{{ project_dir }}/config/resalloc-spinup-playbook.yml.j2') }}"

+       no_log: true

+       tags: resalloc

+ 

+     - name: Deploy the Resalloc pod

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/resalloc.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: resalloc

+ 

+     - name: Instantiate Backend config

+       set_fact:

+         backend_config: "{{ lookup('template', '{{ project_dir }}/config/backend-copr-be.conf') }}"

+         backend_httpd_config: "{{ lookup('template', '{{ project_dir }}/config/backend-nginx.conf') }}"

+       no_log: true

+       tags: backend

+ 

+     - name: Get the actual Copr Backend image from an ImageStream

+       shell: oc get dc copr-backend -o jsonpath='{.spec.template.spec.containers[0].image}'

+       register: cb_is

+       changed_when: false

+       failed_when: false

+       tags: backend

+ 

+     - name: get the latest nginx image

+       shell: oc get istag/copr-backend-httpd:test -o jsonpath='{.image.dockerImageReference}'

+       register: nginx_is

+       changed_when: false

+       failed_when: false

+       tags: backend

+ 

+     - set_fact:

+         copr_backend_image: "{{ cb_is.stdout }}"

+         nginx_image: "{{ nginx_is.stdout }}"

+       tags: backend

+ 

+     - name: Deploy Copr Backend pod

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/backend.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: backend

+ 

+     - name: Instantiate DistGit configs

+       set_fact:

+         distgit_config: "{{ lookup('template', '{{ project_dir }}/config/distgit-distgit.conf.j2') }}"

+         distgit_copr_config: "{{ lookup('template', '{{ project_dir }}/config/distgit-copr.conf.j2') }}"

+       no_log: true

+       tags: distgit

+ 

+     - name: Get the actual Copr DistGit image from an ImageStream

+       shell: oc get dc copr-distgit -o jsonpath='{.spec.template.spec.containers[0].image}'

+       register: cdg_is

+       changed_when: false

+       failed_when: false

+       tags: distgit

+ 

+     - set_fact:

+         copr_distgit_image: "{{ cdg_is.stdout or ' ' }}"

+       tags: distgit

+ 

+     - name: Deploy Copr DistGit pod

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/distgit.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: distgit

+ 

+ 

+     - name: get the latest keygen image

+       shell: oc get istag/copr-keygen:test -o jsonpath='{.image.dockerImageReference}'

+       register: copr_keygen_is

+       changed_when: false

+       failed_when: false

+       tags: keygen

+ 

+     - set_fact:

+         copr_keygen_image: "{{ copr_keygen_is.stdout or ' ' }}"

+       tags: keygen

+ 

+     - name: Deploy Copr Keygen pod

+       k8s:

+         namespace: "{{ project }}"

+         definition: "{{ lookup('template', '{{ path_to_services }}/keygen.yml.j2') }}"

+         api_key: "{{ api_key }}"

+         validate_certs: "{{ validate_certs }}"

+       tags: keygen

@@ -0,0 +1,5 @@ 

+ ---

+ apiVersion: project.openshift.io/v1

+ kind: Project

+ metadata:

+   name: {{ project }}

@@ -0,0 +1,35 @@ 

+ ---

+ # This is used to assure that the 'oc' commands are executed against

+ # the expected OpenShift cluster.  But still, you need to first 'oc login'.

+ oc_api_endpoint: https://your-api-of-openshift.example.com:6443

+ 

+ # Name of the OpenShift project (namespace) to create and use

+ project: <project-name>

+ 

+ # Password for the PostgreSQL pod

+ postgres_password: ...

+ 

+ # Token for the {Backend,DistGit} => Frontend communication.  Generate some

+ # long string here.

+ frontend_backend_password: ...

+ 

+ # Copr builders are hosted outside from the OpenShift cluster, but still they

+ # need to contact these machines on fully qualified domain names.

+ frontend_base_url: http://<pod-name>-<project-name>.<openshift-stack-domain>

+ distgit_fqdn: <pod-name>-<project-name>.<openshift-stack-domain>

+ backend_fqdn: <pod-name>-<project-name>.<openshift-stack-domain>

+ 

+ # AWS EC2 configuration

+ aws_config:

+   # API token

+   access_key_id: ...

+   secret_access_key: ...

+   # Please pre-generate some SSH key that will be used by the Resalloc

+   # and Backend pods for using/maintaining the builders.

+   ssh_key:

+     name: ...

+     private: |

+       -----BEGIN RSA PRIVATE KEY-----

+       ... your very long script here ...

+       -----END RSA PRIVATE KEY-----

+     public: ssh-rsa AAAAB3Nz....

@@ -0,0 +1,281 @@ 

+ # vi: ft=yaml

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-backend-results

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "3Gi"

+ 

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-backend-logs

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "1Gi"

+ 

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-backend-locks

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "10M"

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: copr-backend-config

+ type: Opaque

+ data:

+   copr-be.conf: "{{ backend_config | b64encode }}"

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: backend-home

+ type: Opaque

+ data:

+   id_rsa: "{{ aws_config.ssh_key.private | b64encode }}"

+   ssh_config: SG9zdCAqCiAgIElkZW50aXR5RmlsZSB+Ly5zc2gvaWRfcnNhCiAgIFN0cmljdEhvc3RLZXlDaGVja2luZyAgbm8KICAgVXNlcktub3duSG9zdHNGaWxlIC9kZXYvbnVsbAogICBTZXJ2ZXJBbGl2ZUludGVydmFsIDIwCiAgIFNlcnZlckFsaXZlQ291bnRNYXggNQogICBDb25uZWN0VGltZW91dCA2MAo=

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: copr-backend-httpd-config

+ type: Opaque

+ data:

+   nginx-copr-be.conf: "{{ backend_httpd_config | b64encode }}"

+ 

+ ---

+ apiVersion: v1

+ kind: Service

+ metadata:

+   name: copr-backend

+ spec:

+   ports:

+     - name: copr-backend-httpd

+       port: 8080

+       targetPort: 8080

+   selector:

+     name: copr-backend-httpd

+ 

+ ---

+ apiVersion: image.openshift.io/v1

+ kind: ImageStream

+ metadata:

+   name: copr-backend

+ spec:

+   tags:

+     - from:

+         kind: DockerImage

+         name: quay.io/copr/backend:test

+       importPolicy:

+         scheduled: true

+       name: test

+ 

+ ---

+ apiVersion: image.openshift.io/v1

+ kind: ImageStream

+ metadata:

+   name: copr-backend-httpd

+ spec:

+   tags:

+     - from:

+         kind: DockerImage

+         name: quay.io/centos7/nginx-120-centos7

+       importPolicy:

+         scheduled: true

+       name: test

+ 

+ ---

+ kind: DeploymentConfig

+ apiVersion: v1

+ metadata:

+   name: copr-backend

+ spec:

+   template:

+     metadata:

+       labels:

+         name: copr-backend

+     spec:

+       containers:

+         - name: log

+           image: "{{ copr_backend_image }}"

+           imagePullPolicy: IfNotPresent

+           command: ["/usr/bin/copr_run_logger.py"]

+           volumeMounts:

+             - name: config

+               mountPath: /etc/copr

+             - name: logs

+               mountPath: /var/log/copr-backend

+ 

+         - name: actions

+           image: "{{ copr_backend_image }}"

+           imagePullPolicy: IfNotPresent

+           volumeMounts:

+             - name: config

+               mountPath: /etc/copr

+             - name: results

+               mountPath: /var/lib/copr/public_html

+             - name: locks

+               mountPath: /var/lock/copr-backend

+           command: ["/run-backend", "--sign-host", "copr-keygen", "/usr/bin/copr-run-dispatcher", "actions"]

+ 

+         - name: builds

+           image: "{{ copr_backend_image }}"

+           imagePullPolicy: IfNotPresent

+           volumeMounts:

+             - name: config

+               mountPath: /etc/copr

+             - name: results

+               mountPath: /var/lib/copr/public_html

+             - name: locks

+               mountPath: /var/lock/copr-backend

+             - name: home

+               mountPath: /backend-home

+           env:

+             - name: HOME

+               value: /backend-home

+           command: ["/run-backend", "--sign-host", "copr-keygen", "/usr/bin/copr-run-dispatcher", "builds"]

+ 

+       # start these containers on the same node with copr-backend-httpd!

+       affinity:

+         podAffinity:

+           requiredDuringSchedulingIgnoredDuringExecution:

+             - labelSelector:

+                 matchExpressions:

+                   - key: name

+                     operator: In

+                     values:

+                       - copr-backend-httpd

+               topologyKey: kubernetes.io/hostname

+ 

+ 

+       volumes:

+         - name: config

+           secret:

+             secretName: copr-backend-config

+             optional: false

+ 

+         - name: home

+           secret:

+             secretName: backend-home

+             optional: false

+             defaultMode: 0600

+             items:

+               - key: id_rsa

+                 path: .ssh/id_rsa

+               - key: ssh_config

+                 path: .ssh/config

+ 

+         - name: logs

+           persistentVolumeClaim:

+             claimName: copr-backend-logs

+ 

+         - name: results

+           persistentVolumeClaim:

+             claimName: copr-backend-results

+ 

+         - name: locks

+           persistentVolumeClaim:

+             claimName: copr-backend-locks

+ 

+       restartPolicy: Always

+ 

+   replicas: 1

+   strategy:

+     type: Recreate

+ 

+   triggers:

+     - imageChangeParams:

+         automatic: true

+         containerNames:

+           - actions

+           - builds

+           - log

+         from:

+           kind: ImageStreamTag

+           name: copr-backend:test

+       type: ImageChange

+ 

+     - type: ConfigChange

+ 

+ 

+ ---

+ kind: DeploymentConfig

+ apiVersion: v1

+ metadata:

+   name: copr-backend-httpd

+ spec:

+   template:

+     metadata:

+       labels:

+         name: copr-backend-httpd

+     spec:

+       containers:

+         - name: httpd

+           image: "{{ nginx_image }}"

+           imagePullPolicy: IfNotPresent

+           command: ["nginx", "-g", "daemon off;"]

+           volumeMounts:

+             - name: results

+               mountPath: /opt/app-root/src

+             - name: config

+               mountPath: /opt/app-root/etc/nginx.d/

+ 

+       volumes:

+         - name: results

+           persistentVolumeClaim:

+             claimName: copr-backend-results

+ 

+         - name: config

+           secret:

+             secretName: copr-backend-httpd-config

+             optional: false

+ 

+       restartPolicy: Always

+ 

+   replicas: 1

+   strategy:

+     type: Recreate

+ 

+   triggers:

+     - imageChangeParams:

+         automatic: true

+         containerNames:

+           - httpd

+         from:

+           kind: ImageStreamTag

+           name: copr-backend-httpd:test

+       type: ImageChange

+ 

+     - type: ConfigChange

+ 

+ ---

+ apiVersion: route.openshift.io/v1

+ kind: Route

+ metadata:

+   name: copr-backend

+ spec:

+   port:

+     targetPort: copr-backend-httpd

+   to:

+     kind: Service

+     name: copr-backend

@@ -0,0 +1,183 @@ 

+ # vi: ft=yaml

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-distgit-data

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "3Gi"

+ 

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-distgit-logs

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "1Gi"

+ 

+ ---

+ apiVersion: v1

+ kind: PersistentVolumeClaim

+ metadata:

+   name: copr-distgit-locks

+ spec:

+   accessModes:

+     - ReadWriteOnce

+   resources:

+     requests:

+       storage: "10M"

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: distgit-config

+ type: Opaque

+ data:

+   dist-git.conf: "{{ distgit_config | b64encode }}"

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: distgit-copr-config

+ type: Opaque

+ data:

+   copr-dist-git.conf: "{{ distgit_copr_config | b64encode }}"

+ 

+ ---

+ apiVersion: v1

+ kind: Service

+ metadata:

+   name: copr-distgit

+ spec:

+   ports:

+     - name: copr-distgit-http

+       port: 5001

+       targetPort: 5001

+   selector:

+     name: copr-distgit

+ 

+ ---

+ apiVersion: image.openshift.io/v1

+ kind: ImageStream

+ metadata:

+   name: copr-distgit

+ spec:

+   tags:

+     - from:

+         kind: DockerImage

+         name: quay.io/copr/distgit:test

+       importPolicy:

+         scheduled: true

+       name: test

+ 

+ ---

+ kind: DeploymentConfig

+ apiVersion: v1

+ metadata:

+   name: copr-distgit

+ spec:

+   template:

+     metadata:

+       labels:

+         name: copr-distgit

+     spec:

+       containers:

+         - name: imports

+           image: "{{ copr_distgit_image }}"

+           imagePullPolicy: IfNotPresent

+           volumeMounts:

+             - name: distgit-copr-config

+               mountPath: /etc/copr

+             - name: distgit-config

+               mountPath: /etc/dist-git

+             - name: storage

+               mountPath: /var/lib/dist-git

+             - name: logs

+               mountPath: /var/lib/copr-dist-git

+             - name: logs

+               mountPath: /var/log/copr-dist-git

+             - name: locks

+               mountPath: /var/lock/copr-dist-git

+           command: ["bash", "-c", "mkdir -p /var/lib/dist-git/cache /var/lib/dist-git/git && exec /usr/bin/importer_runner.py"]

+ 

+         - name: httpd

+           image: "{{ copr_distgit_image }}"

+           imagePullPolicy: IfNotPresent

+           volumeMounts:

+             - name: distgit-copr-config

+               mountPath: /etc/copr

+             - name: distgit-config

+               mountPath: /etc/dist-git

+             - name: storage

+               mountPath: /var/lib/dist-git

+             - name: logs

+               mountPath: /var/lib/copr-dist-git

+             - name: logs

+               mountPath: /var/log/copr-dist-git

+             - name: logs

+               mountPath: /var/log/httpd

+           command: ["/usr/sbin/httpd", "-DFOREGROUND"]

+ 

+       volumes:

+         - name: distgit-config

+           secret:

+             secretName: distgit-config

+             optional: false

+ 

+         - name: distgit-copr-config

+           secret:

+             secretName: distgit-copr-config

+             optional: false

+ 

+         - name: storage

+           persistentVolumeClaim:

+             claimName: copr-distgit-data

+ 

+         - name: logs

+           persistentVolumeClaim:

+             claimName: copr-distgit-logs

+ 

+         - name: locks

+           persistentVolumeClaim:

+             claimName: copr-distgit-locks

+ 

+       restartPolicy: Always

+ 

+   replicas: 1

+   strategy:

+     type: Recreate

+ 

+   triggers:

+     - imageChangeParams:

+         automatic: true

+         containerNames:

+           - imports

+           - httpd

+         from:

+           kind: ImageStreamTag

+           name: copr-distgit:test

+       type: ImageChange

+ 

+     - type: ConfigChange

+ 

+ ---

+ apiVersion: route.openshift.io/v1

+ kind: Route

+ metadata:

+   name: copr-distgit

+ spec:

+   port:

+     targetPort: copr-distgit-http

+   to:

+     kind: Service

+     name: copr-distgit

@@ -0,0 +1,95 @@ 

+ # vim: ft=yaml

+ 

+ ---

+ apiVersion: v1

+ kind: Secret

+ metadata:

+   name: copr-frontend-config

+ type: Opaque

+ data:

+   copr.conf: "{{ frontend_config | b64encode }}"

+ 

+ ---

+ apiVersion: v1

+ kind: Service

+ metadata:

+   name: copr-frontend

+ spec:

+   ports:

+     - name: copr-frontend-httpd

+       port: 5000

+       targetPort: 5000

+   selector:

+     name: copr-frontend

+ 

+ ---

+ apiVersion: image.openshift.io/v1

+ kind: ImageStream

+ metadata:

+   name: copr-frontend

+ spec:

+   tags:

+     - from:

+         kind: DockerImage

+         name: quay.io/copr/frontend:test

+       importPolicy:

+         scheduled: true

+       name: test

+ 

+ ---

+ kind: DeploymentConfig

+ apiVersion: v1

+ metadata:

+   name: copr-frontend

+ spec:

+   template:

+     metadata:

+       labels:

+         name: copr-frontend

+     spec:

+       containers:

+         - name: copr-frontend

+           image: "{{ copr_frontend_image }}"

+           imagePullPolicy: IfNotPresent

+           ports:

+             - containerPort: 5000

+               protocol: TCP

+           resources:

+             limits: