diff --git a/.dockerignore b/.dockerignore index a5b1aab59..723e64b91 100644 --- a/.dockerignore +++ b/.dockerignore @@ -25,4 +25,6 @@ coverage test/__pycache__ __pycache__ **/__pycache__ -static/build/** \ No newline at end of file +static/build/** +.gitlab-ci/* +.gitlab-ci.* diff --git a/.gitignore b/.gitignore index 06ba0a6cf..28cffa051 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ *.pyc venv screenshots/screenshots/ -stack +conf/stack */node_modules dist dest diff --git a/.gitlab-ci.jsonnet b/.gitlab-ci.jsonnet index f669df0a1..31c24d796 100644 --- a/.gitlab-ci.jsonnet +++ b/.gitlab-ci.jsonnet @@ -6,8 +6,10 @@ local baseJob = (import '.gitlab-ci/base_jobs.libsonnet')(vars); local stages_list = [ // gitlab-ci stages - 'docker_base', + 'deploy', + 'docker_build', + 'docker_base', 'unit_tests', 'integration', 'docker_release', @@ -91,6 +93,13 @@ local jobs = { env={ [key]: dbname for key in ['MYSQL_ROOT_PASSWORD', 'MYSQL_DATABASE', 'MYSQL_USER', 'MYSQL_PASSWORD'] }), + "deploy-preview": baseJob.QuayDeploy { + environment+: {on_stop: "stop-preview"}, + } + onlyBranch, + + "stop-preview": baseJob.QuayDeployStop { + } + onlyBranch, + }; { diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca92ee270..71d0b6796 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,28 @@ container-release: variables: DOCKER_DRIVER: overlay DOCKER_HOST: tcp://docker-host.gitlab-runner.svc.cluster.local:2375 +deploy-preview: + before_script: + - appr login -u $DOCKER_USER -p $DOCKER_PASS quay.io + environment: + name: review/${CI_COMMIT_REF_SLUG} + on_stop: stop-preview + url: https://quay-${CI_COMMIT_REF_SLUG}.k8s.devtable.com + image: quay.io/appr/appr:kubectl + only: + - branches + script: + - cd deploy/quay-demo-app + - echo -n 1.0.0-${CI_COMMIT_REF_SLUG} > VERSION + - 'echo "{\"image\": \"quay.io/quay/quay-ci:${CI_COMMIT_REF_SLUG}\", \"tag\": \"${CI_COMMIT_REF_SLUG}\"}" > params.json' + - cat params.json + - appr push quay.io/quay -f + - appr deploy quay.io/quay/quay-demo-app@1.0.0-${CI_COMMIT_REF_SLUG} --namespace ci-quay-${CI_COMMIT_REF_SLUG} -x docker_user=$DOCKER_USER -x docker_pass=$DOCKER_PASS + - kubectl get ingresses -n ci-quay-${CI_COMMIT_REF_SLUG} -o wide + stage: deploy + tags: + - kubernetes + when: manual karma-tests: before_script: - cd $QUAYDIR @@ -130,12 +152,34 @@ registry-tests: QUAYDIR: /quay-registry TEST: 'true' stages: -- docker_base +- deploy - docker_build +- docker_base - unit_tests - integration - docker_release - teardown +stop-preview: + before_script: + - appr login -u $DOCKER_USER -p $DOCKER_PASS quay.io + environment: + action: stop + name: review/${CI_COMMIT_REF_SLUG} + url: https://quay-${CI_COMMIT_REF_SLUG}.k8s.devtable.com + image: quay.io/appr/appr:kubectl + only: + - branches + script: + - 'echo "{\"image\": \"quay.io/quay/quay-ci:${CI_COMMIT_REF_SLUG}\", \"tag\": \"${CI_COMMIT_REF_SLUG}\"}" > params.json' + - cat params.json + - appr remove quay.io/quay/quay-demo-app@1.0.0-${CI_COMMIT_REF_SLUG} --namespace ci-quay-${CI_COMMIT_REF_SLUG} -x docker_user=$DOCKER_USER -x docker_pass=$DOCKER_PASS -x params.json + - kubectl get pods -n ci-quay-${CI_COMMIT_REF_SLUG} -o wide + stage: deploy + tags: + - kubernetes + variables: + GIT_STRATEGY: none + when: manual unit-tests: before_script: - cd $QUAYDIR diff --git a/.gitlab-ci/base_jobs.libsonnet b/.gitlab-ci/base_jobs.libsonnet index d90a3eef1..f928f45af 100644 --- a/.gitlab-ci/base_jobs.libsonnet +++ b/.gitlab-ci/base_jobs.libsonnet @@ -35,6 +35,46 @@ function(vars={}) ], }, + local appversion = "1.0.0-%s" % vars.images.quayci.tag, + local namespace = "ci-quay-%s" % vars.images.quayci.tag, + QuayDeploy: { + image: "quay.io/appr/appr:kubectl", + when: "manual", + environment: { + name: "review/%s" % vars.images.quayci.tag, + url: "https://quay-%s.k8s.devtable.com" % vars.images.quayci.tag, + }, + tags: [ + "kubernetes", + ], + stage: "deploy", + before_script: [ + "appr login -u $DOCKER_USER -p $DOCKER_PASS quay.io", + ], + script: [ + "cd deploy/quay-demo-app", + "echo -n %s > VERSION" % appversion, + 'echo "{\\"image\\": \\"%s\\", \\"tag\\": \\"%s\\"}" > params.json' % [vars.images.quayci.name, vars.images.quayci.tag], + "cat params.json", + "appr push quay.io/quay -f", + "appr deploy quay.io/quay/quay-demo-app@%s --namespace %s -x docker_user=$DOCKER_USER -x docker_pass=$DOCKER_PASS" % [appversion, namespace], + "kubectl get ingresses -n %s -o wide" % namespace, + ], + }, + + QuayDeployStop: self.QuayDeploy { + variables: {GIT_STRATEGY: "none"}, + environment+: { + action: "stop" + }, + script: [ + 'echo "{\\"image\\": \\"%s\\", \\"tag\\": \\"%s\\"}" > params.json' % [vars.images.quayci.name, vars.images.quayci.tag], + "cat params.json", + "appr remove quay.io/quay/quay-demo-app@%s --namespace %s -x docker_user=$DOCKER_USER -x docker_pass=$DOCKER_PASS -x params.json" % [appversion, namespace], + "kubectl get pods -n %s -o wide" % namespace, + ], + }, + dbTest(scheme, image, env):: self.QuayTest { variables+: { SKIP_DB_SCHEMA: 'true', diff --git a/deploy/postgres/.kpmignore b/deploy/postgres/.kpmignore new file mode 100644 index 000000000..863817f73 --- /dev/null +++ b/deploy/postgres/.kpmignore @@ -0,0 +1 @@ +variables.yaml diff --git a/deploy/postgres/README.md b/deploy/postgres/README.md new file mode 100644 index 000000000..d97c4930e --- /dev/null +++ b/deploy/postgres/README.md @@ -0,0 +1,8 @@ + +postgres/postgres +=========== + +# Install + +kpm deploy postgres/postgres + diff --git a/deploy/postgres/manifest.yaml b/deploy/postgres/manifest.yaml new file mode 100644 index 000000000..26c938a63 --- /dev/null +++ b/deploy/postgres/manifest.yaml @@ -0,0 +1,29 @@ +--- +package: + name: quay/postgres-app + author: Antoine Legrand + version: 9.6.1-1 + description: postgres + license: MIT + +variables: + image: postgres:9.6.1 + dbname: quay + user: quay + password: quay + data_volumes: + - name: postgres-data + emptyDir: + medium: "" + +resources: + - file: postgres-deployment.yaml + name: postgres + type: deployment + + - file: postgres-service.yaml + name: postgres + type: service + +deploy: + - name: $self diff --git a/deploy/postgres/templates/postgres-deployment.yaml b/deploy/postgres/templates/postgres-deployment.yaml new file mode 100644 index 000000000..ea4b447bc --- /dev/null +++ b/deploy/postgres/templates/postgres-deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: postgres + labels: + k8s-app: postgres +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: postgres + template: + metadata: + labels: + k8s-app: postgres + spec: + containers: + - image: {{image}} + name: postgres + env: + - name: POSTGRES_PASSWORD + value: "{{password}}" + - name: PGPASSWORD + value: "{{password}}" + - name: POSTGRES_USER + value: "{{user}}" + - name: POSTGRES_DB + value: "{{dbname}}" + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + ports: + - containerPort: 5432 + name: postgres + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + # livenessProbe: + # tcpSocket: + # port: "postgres" + # initialDelaySeconds: 5 + # timeoutSeconds: 1 + # readinessProbe: + # initialDelaySeconds: 600 + # exec: + # command: ["psql", "-h", "localhost", "-U", "postgres"] + volumes: {{data_volumes}} diff --git a/deploy/postgres/templates/postgres-service.yaml b/deploy/postgres/templates/postgres-service.yaml new file mode 100644 index 000000000..840c3828c --- /dev/null +++ b/deploy/postgres/templates/postgres-service.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: postgres + name: postgres +spec: + type: ClusterIP + ports: + - port: 5432 + name: postgres + selector: + k8s-app: postgres diff --git a/deploy/postgres/variables.yaml b/deploy/postgres/variables.yaml new file mode 100644 index 000000000..ffbd737ce --- /dev/null +++ b/deploy/postgres/variables.yaml @@ -0,0 +1,7 @@ +user: quay +password: quay +dbname: quay +data_volumes: + - name: "postgres-data" + persistentVolumeClaim: + claimName: pvc-postgres-master diff --git a/deploy/quay-app/.apprignore b/deploy/quay-app/.apprignore new file mode 100644 index 000000000..fb9ac1566 --- /dev/null +++ b/deploy/quay-app/.apprignore @@ -0,0 +1 @@ +stack/ diff --git a/deploy/quay-app/Chart.jsonnet b/deploy/quay-app/Chart.jsonnet new file mode 100644 index 000000000..0741e6851 --- /dev/null +++ b/deploy/quay-app/Chart.jsonnet @@ -0,0 +1,8 @@ +{ + name: 'quay/quay-app', + author: 'Antoine Legrand', + version: std.split(importstr "VERSION", "\n")[0], + description: 'quay', + license: 'MIT', + expander: 'jinja2' +} diff --git a/deploy/quay-app/README.md b/deploy/quay-app/README.md new file mode 100644 index 000000000..ebf96f52e --- /dev/null +++ b/deploy/quay-app/README.md @@ -0,0 +1,9 @@ +# Configure +## +- The package reads automatically ./stack/* and use every files there in configuration. +- if a `./stack/config.yaml` exists, the file is merged with the variable `config`. + Config precedence order: + 1. Default defined in the package level + 2. file content in `stack/*` + 3. value variables.stack_files +Except for `config.yaml`, precedence is a strict replacement, for config.yaml is a mergePatch. diff --git a/deploy/quay-app/lib/quay.libsonnet b/deploy/quay-app/lib/quay.libsonnet new file mode 100644 index 000000000..c42386a60 --- /dev/null +++ b/deploy/quay-app/lib/quay.libsonnet @@ -0,0 +1,16 @@ +local appr = import 'appr.libsonnet'; + +{ +# Read all files in a directory +# @todo(ant31): replace walk by listdir +load_stack_files(path):: ( + if appr.path_exists(path) + then {[appr.path.basename(file)]: appr.readfile(file, encode=true) for file in appr.walkdir(path)} + else {} +), + +# Create a patch to add/update annotation with a rand value. +# Use to force a Deployment rolling-update +rand_label():: {metadata+: {annotations+: {'resource.appr/rand': appr.randAlphaNum()}}}, + +} diff --git a/deploy/quay-app/manifest.jsonnet b/deploy/quay-app/manifest.jsonnet new file mode 100644 index 000000000..d28f4930d --- /dev/null +++ b/deploy/quay-app/manifest.jsonnet @@ -0,0 +1,155 @@ +local appr = import 'appr.libsonnet'; +local quaylib = import 'lib/quay.libsonnet'; + +function( + params={} +) + + +appr.package({ + package: import "Chart.jsonnet", + +variables: { + namespace: 'default', + cluster_domain_name: 'cluster.local', + + # Minimum configuration + base_config: (import "templates/conf/config.libsonnet")($.variables), + + # Additional values stack/config.yaml values + config: {}, + + # path to the local stack configuration directory + stack_path: "stack", + + # load local `stack` directory if exists + stack_files: { + "syslog-ng-extra.conf": appr.b64encode(importstr "templates/conf/syslog-ng-extra.conf")} + + if $.variables.license != null then {"license": appr.b64encode($.variables.license) } else {} + + quaylib.load_stack_files($.variables.stack_path), + + # load license + license: null, + + # Image tag and repo + tag: $.package.version, + image: 'quay.io/quay/quay:%s' % self.tag, + + # Used in the pull secret + docker_user: 'changeme', + docker_pass: 'changeme', + + # Redis configuration + redis_host: 'quay-redis.%s.svc.%s:6379' % [$.variables.namespace, $.variables.cluster_domain_name], + redisconf: {redis_parts:: std.split($.variables.redis_host, ":"), + "host": self.redis_parts[0], port: self.redis_parts[1]}, + + # Configure the ingress with the ingress controller class and domain to use + domain: 'quay.%s.example.com' % $.variables.namespace, + ingress: { + class: 'nginx', + tls: "kubernetes.io/tls-acme", + domains: std.split($.variables.domain, ','), + annotations: {} + }, + + # Force to reload the secret/configuration + reconfigure: "false", + + # Deploy a postgres (don't use it for prod) + deploy_db: 'false', + + # Postgres deployment configuratio + db: { + user: 'quay', + password: 'quay', + name: 'quay', + }, + + # Quay DB_URI + db_uri: 'postgresql://%s:%s@postgres.%s.svc.%s/%s' % [$.variables.db.user, + $.variables.db.password, + $.variables.namespace, + $.variables.cluster_domain_name, + $.variables.db.name], + +}, + + + # ServiceAccount to attach Rbac rules +resources: appr.compact([ # + appr.importResourceDir('templates/') + { + value: {apiVersion: 'v1', kind: 'ServiceAccount', + metadata: {name: 'quay-enterprise'}} + }, + + # Grant secret read/write permission inside the namespace + { + value: (import 'templates/quay-enterprise-role.libsonnet')($.variables), + }, + + # Bind role to the Service account + { + value: (import 'templates/quay-enterprise-rolebinding.libsonnet')($.variables), + }, + + # Quay.io robot / user account. Protected from default values + { + value: (import 'templates/quay-enterprise-pullsecret.libsonnet')($.variables), + protected: if $.variables.docker_user == "changeme" || $.variables.docker_pass == "changeme" + then true else false + }, + + # Quay configuration files (quay/conf/stack), automatically read local the "./stack" directory to load values. + # Values can also be loaded from $.variables.stack_files + # Protected unless explicitly requested (reconfigure == "true"). + { + value: (import 'templates/quay-enterprise-secret.libsonnet')($.variables), + protected: if $.variables.reconfigure == "true" then false else true + }, + + # Quay-registry deployment + # Force a rollout when the secret is reconfigured by updating a label (see randLabel) + { + value: appr.loadObject(appr.jinja2(importstr 'templates/quay-enterprise-app-dp.yaml', $.variables)) + + if $.variables.reconfigure == "true" then + # trigger a rollout + quaylib.rand_label() + else {} + }, # + {value+: if $.variables.reconfigure == "true" then randLabel() else {},}, + + { + template: (importstr 'templates/quay-enterprise-service.yaml'), + }, + + # Redis + { + template: (importstr 'templates/quay-enterprise-redis-service.yaml'), + }, + + { + template: (importstr 'templates/quay-enterprise-redis.yaml'), + }, + + + # Ingress, assumes usage of kube-lego and an ingress controller. + # see variables.ingress for configuration + { + value: (import 'templates/quay-enterprise-ingress.libsonnet')($.variables.ingress), + }, + + +]), + + +deploy: appr.compact([ + if $.variables.deploy_db == 'true' then + {name: 'quay/postgres-app', + variables: { + user: $.variables.db.user, + dbname: $.variables.db.name, + password: $.variables.db.password + }}, + {name: '$self'}, +]), +}, params) diff --git a/deploy/quay-app/templates/conf/config.libsonnet b/deploy/quay-app/templates/conf/config.libsonnet new file mode 100644 index 000000000..672fa38e1 --- /dev/null +++ b/deploy/quay-app/templates/conf/config.libsonnet @@ -0,0 +1,53 @@ +function(vars) +{ + BUILDLOGS_REDIS: vars.redisconf, + USER_EVENTS_REDIS: vars.redisconf, + DB_URI: vars.db_uri, + SETUP_COMPLETE: true, + # Not deployed, features forced turn off + FEATURE_SECURITY_SCANNER: false, + FEATURE_BUILD_SUPPORT: false, + FEATURE_ACI_CONVERSION: false, + FEATURE_GITHUB_BUILD: false, + FEATURE_BITBUCKET_BUILD: false, + FEATURE_GITLAB_BUILD: false, + GITHUB_TRIGGER_CONFIG: null, + GITLAB_TRIGGER_KIND: {}, + AUTHENTICATION_TYPE: "Database", + PREFERRED_URL_SCHEME: "https", + SERVER_HOSTNAME: vars.ingress.domains[0], + EXTERNAL_TLS_TERMINATION: true, + INSTANCE_SERVICE_KEY_KID_LOCATION: 'conf/quay.kid', + INSTANCE_SERVICE_KEY_LOCATION: 'conf/quay.pem', +} + +# local s3_storage = { local_us: ["S3Storage", +# {storage_path: "", +# s3_access_key: vars.storage.s3.access_key, +# s3_secret_key: vars.storage.s3.secret_key, +# s3_bucket: vars.storage.s3.bucket}, +# ] +# }; + +# extra: { +# REGISTRY_TITLE: "Quay (%s)" % vars.ingress.host, +# REGISTRY_TITLE_SHORT: "Quay (%s)" % vars.ingress.host, +# TESTING: true, +# DEBUGGING: true, +# USE_CDN: false, +# FEATURE_ANONYMOUS_ACCESS: true, +# FEATURE_MAILING: false, +# AUTHENTICATION_TYPE: "Database", +# ENTERPRISE_LOGO_URL: "/static/img/quay-logo.png", +# LOG_ARCHIVE_LOCATION: "default", +# TAG_EXPIRATION_OPTIONS: ["2d"], +# DISTRIBUTED_STORAGE_CONFIG: { +# default: [ +# "LocalStorage", +# {storage_path: "/datastorage/registry"}]}, +# DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [], +# DISTRIBUTED_STORAGE_PREFERENCE: ["default"], +# USERFILES_LOCATION: "default", +# USERFILES_PATH: "userfiles/", +# } +# } diff --git a/deploy/quay-app/templates/conf/syslog-ng-extra.conf b/deploy/quay-app/templates/conf/syslog-ng-extra.conf new file mode 100644 index 000000000..5d5b378e0 --- /dev/null +++ b/deploy/quay-app/templates/conf/syslog-ng-extra.conf @@ -0,0 +1,7 @@ +destination d_stdout { + pipe("/dev/stdout"); +}; + +log { + source(s_src); destination(d_stdout); +}; diff --git a/deploy/quay-app/templates/quay-dev-initdb-job.yaml b/deploy/quay-app/templates/quay-dev-initdb-job.yaml new file mode 100644 index 000000000..ccbaef8ae --- /dev/null +++ b/deploy/quay-app/templates/quay-dev-initdb-job.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: quay-dev-initdb +spec: + activeDeadlineSeconds: 100 + template: + metadata: + name: quay-dev-initdb + spec: + containers: + - name: quay + image: quay.io/quay/quay-ci:master + env: + - name: TEST_DATABASE_URI + value: "postgres://" + - name: SKIP_DB_SCHEMA + value: "true" + command: + - venv/bin/python + - initdb.py + volumeMounts: + - name: configvolume + readOnly: false + mountPath: /conf/stack + resources: + limits: + cpu: 500m + memory: 500Mi + imagePullSecrets: + - name: coreos-pull-secret + volumes: + - name: configvolume + secret: + secretName: quay-enterprise-config-secret + restartPolicy: Never diff --git a/deploy/quay-app/templates/quay-enterprise-app-dp.yaml b/deploy/quay-app/templates/quay-enterprise-app-dp.yaml new file mode 100644 index 000000000..a2d96a471 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-app-dp.yaml @@ -0,0 +1,55 @@ +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + namespace: quay-enterprise + name: quay-enterprise-app + labels: + quay-enterprise-component: app +spec: + replicas: 1 + template: + metadata: + labels: + quay-enterprise-component: app + spec: + serviceAccountName: "quay-enterprise" + containers: + - name: quay-enterprise-app + livenessProbe: + httpGet: + path: /status + port: 80 + initialDelaySeconds: 300 + periodSeconds: 30 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + httpGet: + path: /status + port: 80 + initialDelaySeconds: 45 + failureThreshold: 6 + periodSeconds: 20 + env: + - name: QE_K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: {{image}} + ports: + - containerPort: 80 + volumeMounts: + - name: configvolume + readOnly: false + mountPath: /conf/stack + resources: + limits: + cpu: 1 + memory: 2Gi + imagePullSecrets: + - name: coreos-pull-secret + volumes: + - name: configvolume + secret: + secretName: quay-enterprise-config-secret diff --git a/deploy/quay-app/templates/quay-enterprise-ingress.libsonnet b/deploy/quay-app/templates/quay-enterprise-ingress.libsonnet new file mode 100644 index 000000000..b3bf0b3b5 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-ingress.libsonnet @@ -0,0 +1,31 @@ +function(ingress={ class: 'none', tls: "true", domains: ['quay.example.com'] }) + +{ +apiVersion: "extensions/v1beta1", +kind: "Ingress", +metadata: { + annotations: { + "kubernetes.io/ingress.class": ingress.class, + [if std.type(ingress.tls) == "string" then ingress.tls]: "true"} + + if std.objectHas(ingress, "annotations") then ingress.annotations else {}, + name: "quay-enterprise", +}, + +spec: { + rules: [{ + host: domain, + http: { + paths: [{ + backend: { + serviceName: "quay-enterprise", + servicePort: 80,}, + path: "/"}]}, + } for domain in ingress.domains], +} + + +if std.type(ingress.tls) == "string" then + {tls: [{ + hosts: ingress.domains, + secretName: "quay-enterprise-tls", + }]} else {}, +} diff --git a/deploy/quay-app/templates/quay-enterprise-pullsecret.libsonnet b/deploy/quay-app/templates/quay-enterprise-pullsecret.libsonnet new file mode 100644 index 000000000..311600231 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-pullsecret.libsonnet @@ -0,0 +1,14 @@ +local appr = import "appr.libsonnet"; +function(variables={}) +{ +local docker_login = [variables.docker_user, variables.docker_pass], +data: { + ".dockercfg": appr.b64encode('{"quay.io": {"username": "%s", "password": "%s","email":"toto@toto.com","auth": "%s"}}' % (docker_login + [appr.b64encode("%s:%s" % docker_login)])), + }, +kind: "Secret", +metadata: { + name: "coreos-pull-secret", + }, + +type: "kubernetes.io/dockercfg" +} diff --git a/deploy/quay-app/templates/quay-enterprise-redis-service.yaml b/deploy/quay-app/templates/quay-enterprise-redis-service.yaml new file mode 100644 index 000000000..5fd2870d5 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-redis-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: quay-redis + name: quay-redis +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 + selector: + quay-enterprise-component: redis diff --git a/deploy/quay-app/templates/quay-enterprise-redis.yaml b/deploy/quay-app/templates/quay-enterprise-redis.yaml new file mode 100644 index 000000000..14ae4557b --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-redis.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + namespace: quay-enterprise + name: quay-enterprise-redis + labels: + quay-enterprise-component: redis +spec: + replicas: 1 + template: + metadata: + labels: + quay-enterprise-component: redis + spec: + containers: + - name: redis-master + image: quay.io/quay/redis + ports: + - containerPort: 6379 + resources: + limits: + cpu: 100m + memory: 500Mi diff --git a/deploy/quay-app/templates/quay-enterprise-role.libsonnet b/deploy/quay-app/templates/quay-enterprise-role.libsonnet new file mode 100644 index 000000000..b74fe15b2 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-role.libsonnet @@ -0,0 +1,21 @@ +local appr = import "appr.libsonnet"; +function(vars={}) +{ +kind: "Role", +apiVersion: 'rbac.authorization.k8s.io/v1beta1', +metadata: { + name: "quay-enterprise", + }, +rules: [ + { + apiGroups: [""], + resources: ["secrets"], + verbs: ["get", "update", "patch"], + }, + { + apiGroups: [""], + resources: ["namespaces"], + verbs: ["get"], + }, +], +} diff --git a/deploy/quay-app/templates/quay-enterprise-rolebinding.libsonnet b/deploy/quay-app/templates/quay-enterprise-rolebinding.libsonnet new file mode 100644 index 000000000..a6c17f122 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-rolebinding.libsonnet @@ -0,0 +1,21 @@ +function(vars={}) +{ +apiVersion: "rbac.authorization.k8s.io/v1beta1", +kind: "RoleBinding", +metadata: { + name: "quay-enterprise-binding", + namespace: vars.namespace, +}, +roleRef: { + apiGroup: "rbac.authorization.k8s.io", + kind: "Role", + name: "quay-enterprise", + }, +subjects: [ + { + kind: "ServiceAccount", + name: "quay-enterprise", + namespace: vars.namespace, + } +] +} diff --git a/deploy/quay-app/templates/quay-enterprise-secret.libsonnet b/deploy/quay-app/templates/quay-enterprise-secret.libsonnet new file mode 100644 index 000000000..f867e2852 --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-secret.libsonnet @@ -0,0 +1,34 @@ +local appr = import "appr.libsonnet"; +local b64e = appr.b64decode; + +function(vars={}) + +# Deserialize config.yaml if exists +local local_stack_config = ( + local confpath = "config.yaml"; + if std.objectHasAll(vars.stack_files, confpath) + then appr.loadObject(appr.b64decode(vars.stack_files[confpath])) + else {} +); + +# Merge all config together +# Precedence: package-config (vars.config) < local stack/config.yaml < base-config (vars.base-config) +local config_yaml = {'config.yaml': appr.b64encode(appr.to_yaml( + vars.config + + local_stack_config + + vars.base_config))}; + +# Merge stack files +local stack_files = vars.stack_files + config_yaml; + +{ +apiVersion: "v1", +kind: "Secret", +metadata: { + namespace: "quay-enterprise", + name: "quay-enterprise-config-secret"}, + +# base64 encode all files +data: { [file]: stack_files[file] + for file in std.objectFields(stack_files) if stack_files[file] != null} +} diff --git a/deploy/quay-app/templates/quay-enterprise-service.yaml b/deploy/quay-app/templates/quay-enterprise-service.yaml new file mode 100644 index 000000000..95fa264bd --- /dev/null +++ b/deploy/quay-app/templates/quay-enterprise-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: quay-enterprise + name: quay-enterprise +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 80 + targetPort: 80 + selector: + quay-enterprise-component: app diff --git a/deploy/quay-ci-app/README.md b/deploy/quay-ci-app/README.md new file mode 100644 index 000000000..5ad6ab9f8 --- /dev/null +++ b/deploy/quay-ci-app/README.md @@ -0,0 +1,8 @@ + +quay/quay +=========== + +# Install + +kpm deploy quay/quay + diff --git a/deploy/quay-ci-app/VERSION b/deploy/quay-ci-app/VERSION new file mode 100644 index 000000000..66a89fadd --- /dev/null +++ b/deploy/quay-ci-app/VERSION @@ -0,0 +1 @@ +2.4.0-1 diff --git a/deploy/quay-ci-app/ci_stack/config.yaml b/deploy/quay-ci-app/ci_stack/config.yaml new file mode 100644 index 000000000..9e0b296aa --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/config.yaml @@ -0,0 +1,176 @@ +--- +# Uncomment to use a real mysql db running in docker +# DB_URI: mysql+pymysql://root:password@192.168.59.103/quay +# DB_CONNECTION_ARGS: +# threadlocals: true +# autorollback: true + +SECRET_KEY: a36c9d7d-25a9-4d3f-a586-3d2f8dc40a83 + +REGISTRY_TITLE: Quay.io (local) +REGISTRY_TITLE_SHORT: Quay.io (local) + +GITHUB_LOGIN_CONFIG: + GITHUB_ENDPOINT: https://github.com/ + API_ENDPOINT: https://api.github.com/ + CLIENT_ID: 0e8dbe15c4c7630b5480 + CLIENT_SECRET: d4a58ddd3dbe08b7fec109e85564a0d153d3e256 + ORG_RESTRICT: true + ALLOWED_ORGANIZATIONS: + - DevTables + - cOREOS + +#GITHUB_LOGIN_CONFIG: +# GITHUB_ENDPOINT: http://192.168.59.104 +# CLIENT_ID: dc6468ad8690e5aad485 +# CLIENT_SECRET: 78ed1f22b1cce0aafbe363b7cb38258874dbdca6 + +GITHUB_TRIGGER_CONFIG: + GITHUB_ENDPOINT: https://github.com/ + API_ENDPOINT: https://api.github.com/ + CLIENT_ID: cfbc4aca88e5c1b40679 + CLIENT_SECRET: 334cd66a7868259697726e2a1980c6869dbdef49 + +GOOGLE_LOGIN_CONFIG: + CLIENT_ID: 342710155188-onh8ko4uge0mu4odl4vchios4m92ncuu.apps.googleusercontent.com + CLIENT_SECRET: PWgfDNB0RAP4Nrqu9pZT37n9 + +BITBUCKET_TRIGGER_CONFIG: + CONSUMER_KEY: xKcfYn9tjKTq8pELgp + CONSUMER_SECRET: E6ewPUDwvFxY7HUPUsGpMvXHPKDkR8Ur + +GITLAB_TRIGGER_CONFIG: + GITLAB_ENDPOINT: https://gitlab.com + CLIENT_ID: 5f12a8b50aafcf9f3dc1394eeb00d1ccb217d07f0c7f85bb9cb3ffb2d836043f + CLIENT_SECRET: f8dd18718bd2cbd35196eaca62ae56785d947ddd45fbcd7963353c25fcc27ea3 + +FEATURE_BILLING: true +BILLING_TYPE: Stripe +STRIPE_SECRET_KEY: sk_test_PEbmJCYrLXPW0VRLSnWUiZ7Y +STRIPE_PUBLISHABLE_KEY: pk_test_uEDHANKm9CHCvVa2DLcipGRh + +MAIL_SERVER: email-smtp.us-east-1.amazonaws.com +MAIL_USE_TLS: true +MAIL_PORT: 587 +MAIL_USERNAME: AKIAIXV5SDGCPVMU3N4Q +MAIL_PASSWORD: AhmX/vWE91uQ2RtcEKTkfNrzZehEjPNXOXeOXgQNfLao +MAIL_DEFAULT_SENDER: support@quay.io +MAIL_FAIL_SILENTLY: false + +AVATAR_KIND: gravatar + +TESTING: false +DEBUGGING: true +USE_CDN: true + +# Feature Flag: Whether to display the support chat. +FEATURE_SUPPORT_CHAT: true + +# Feature Flag: Whether GitHub login is supported. +FEATURE_GITHUB_LOGIN: true + +# Feature Flag: Whether Google login is supported. +FEATURE_GOOGLE_LOGIN: true + +# Analytics +ANALYTICS_TYPE: Mixpanel +MIXPANEL_KEY: 38014a0f27e7bdc3ff8cc7cc29c869f9 + +# Uncomment this to enable Marketo for dev +# USER_ANALYTICS_TYPE: Marketo +# MARKETO_MUNCHKIN_ID: 231-DAD-511 +# MARKETO_MUNCHKIN_PRIVATE_KEY: corechella16! +# MARKETO_CLIENT_ID: 873e9474-367c-42ee-9f53-af43d895c956 +# MARKETO_CLIENT_SECRET: qqvYC1slFvEJkiye5X3J8fsgEKMu8Dlt +# MARKETO_LEAD_SOURCE: Quay Hosted - Test + +# Build logs +BUILDLOGS_REDIS: + host: 192.168.59.103 +BUILDLOGS_OPTIONS: +- devtable +- building +- deadbeef-dead-beef-dead-beefdeadbeef +- true +BUILDLOGS_MODULE_AND_CLASS: +- test.testlogs +- testlogs.TestBuildLogs + +# User events +USER_EVENTS_REDIS: + host: 192.168.59.103 + +FEATURE_GITHUB_BUILD: true +FEATURE_BITBUCKET_BUILD: true +FEATURE_GITLAB_BUILD: true + +FEATURE_SUPER_USERS: true +SUPER_USERS: +- devtable + +SIGNING_ENGINE: gpg2 + +GPG2_PRIVATE_KEY_NAME: EEB32221 +GPG2_PRIVATE_KEY_FILENAME: signing-private.gpg +GPG2_PUBLIC_KEY_FILENAME: signing-public.gpg + +FEATURE_ACI_CONVERSION: true + +SETUP_COMPLETE: true + +# Uncomment to test LDAP. +# Information: http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/ +# AUTHENTICATION_TYPE: 'LDAP' +# LDAP_URI: 'ldap://ldap.forumsys.com' +# LDAP_BASE_DN: ['dc=example', 'dc=com'] +# LDAP_ADMIN_DN: 'cn=read-only-admin,dc=example,dc=com' +# LDAP_ADMIN_PASSWD: 'password' +# LDAP_USER_RDN: [] + +# Uncomment to test S3 Uploads to an ephemeral bucket +# DISTRIBUTED_STORAGE_CONFIG: +# local_us: +# - S3Storage +# - storage_path: "" +# s3_access_key: AKIAJDF3UKLGZJ7RLJ2A +# s3_secret_key: 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 +# s3_bucket: quay-registry-test + +# Uncomment to test swift storage +# DISTRIBUTED_STORAGE_CONFIG: +# local_us: +# - SwiftStorage +# - swift_container: container_name +# storage_path: /datastorage/registry +# auth_url: http://192.168.59.103:32768/auth/v1.0 +# swift_user: test:tester +# swift_password: testing +# auth_version: 1 +# simple_path_concat: true + +#FEATURE_ANONYMOUS_ACCESS: False + +# CloudWatch AWS Keys +#CLOUDWATCH_AWS_ACCESS_KEY: AKIAJUSUTJ3TGBAC2LMQ +#CLOUDWATCH_AWS_SECRET_KEY: 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 +#CLOUDWATCH_NAMESPACE: Quay/Local + +# Security scanner +FEATURE_SECURITY_SCANNER: true +FEATURE_SECURITY_NOTIFICATIONS: true +SECURITY_SCANNER: + ENDPOINT: https://192.168.99.100:6060 + ENGINE_VERSION_TARGET: 1 + API_VERSION: v1 + API_TIMEOUT_SECONDS: 10 + +INSTANCE_SERVICE_KEY_KID_LOCATION: 'conf/stack/quay.kid' +INSTANCE_SERVICE_KEY_LOCATION: 'conf/stack/quay.pem' + +PROMETHEUS_AGGREGATOR_URL: null + +STAGGER_WORKERS: false + +STATIC_SITE_BUCKET: 'https://s3.amazonaws.com/prod-s3.quay.io/' + +FEATURE_APP_REGISTRY: true diff --git a/deploy/quay-ci-app/ci_stack/license b/deploy/quay-ci-app/ci_stack/license new file mode 100644 index 000000000..b5ef9ec95 --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/license @@ -0,0 +1 @@ +eyJhbGciOiJSUzI1NiJ9.eyJzY2hlbWFWZXJzaW9uIjoidjIiLCJ2ZXJzaW9uIjoiMjciLCJjcmVhdGlvbkRhdGUiOiIyMDE2LTEwLTI1VDAwOjA2OjQzWiIsImV4cGlyYXRpb25EYXRlIjoiMjAxNy0xMC0yNVQwMDowNjo0M1oiLCJsaWNlbnNlIjoie1wic2NoZW1hVmVyc2lvblwiOlwidjJcIixcInZlcnNpb25cIjpcIjI3XCIsXCJhY2NvdW50SURcIjpcIkFDQy02ODY0N0FCRC03REI3LTQ4QzItQjZDNS0yMjEzOEQ5RFwiLFwiYWNjb3VudFNlY3JldFwiOlwiMGIyMjk4ZTAtZDRmOC00M2M4LTk3NDUtNjY5Y2I2NDc2MzA5XCIsXCJjcmVhdGlvbkRhdGVcIjpcIjIwMTYtMTAtMjVUMDA6MDY6NDMuMTgzMzIzWlwiLFwiZXhwaXJhdGlvbkRhdGVcIjpcIjIwMTctMTAtMjVUMDA6MDY6NDMuMTgzMzIzWlwiLFwic3Vic2NyaXB0aW9uc1wiOntcIlNVQi0yMkVDRjk4RS00QUVFLTQzNjktODgwQy0zMjg3ODEyM1wiOntcInBsYW5OYW1lXCI6XCJ0ZWN0b25pYy1lbnRlcnByaXNlLXBvY1wiLFwicHVibGljUGxhbk5hbWVcIjpcIlRlY3RvbmljIEVudGVycHJpc2UgUE9DXCIsXCJwbGFuSURcIjpcIlBSUC1EMzkwN0ZDQS1FM0ExLTQxNUEtQUJBRS1CNEEwMkI1OVwiLFwicHJvZHVjdE5hbWVcIjpcInRlY3RvbmljLWVudGVycHJpc2VcIixcInB1YmxpY1Byb2R1Y3ROYW1lXCI6XCJUZWN0b25pYyBFbnRlcnByaXNlXCIsXCJwcm9kdWN0SURcIjpcIlBSTy04NDU4RUJGRS00NDZDLTQwQUUtQjU3OC1DQjU1QUMyN1wiLFwic2VydmljZVN0YXJ0XCI6XCIyMDE2LTA0LTIwVDIwOjQ0OjAwWlwiLFwic2VydmljZUVuZFwiOlwiMjAxNy0wNC0yMFQyMDo0NDowMFpcIixcImluVHJpYWxcIjpmYWxzZSxcInRyaWFsT25seVwiOmZhbHNlLFwiZHVyYXRpb25cIjo2MCxcImR1cmF0aW9uUGVyaW9kXCI6XCJkYXlzXCIsXCJlbnRpdGxlbWVudHNcIjp7XCJzb2Z0d2FyZS5jb3JldXBkYXRlXCI6MSxcInNvZnR3YXJlLnF1YXlcIjoxLFwic29mdHdhcmUucXVheS5idWlsZGVyc1wiOjk5OTksXCJzb2Z0d2FyZS5xdWF5LmRlcGxveW1lbnRzXCI6MSxcInNvZnR3YXJlLnF1YXkucmVnaW9uc1wiOjEsXCJzb2Z0d2FyZS50ZWN0b25pY1wiOjEsXCJzb2Z0d2FyZS50ZWN0b25pYy5yYW1cIjoxMDI0LFwic3VwcG9ydC5jb3Jlb3NsaW51eC5wcmVtaXVtXCI6MSxcInN1cHBvcnQuY29yZXVwZGF0ZS5wcmVtaXVtXCI6MSxcInN1cHBvcnQucXVheS5wcmVtaXVtXCI6MSxcInN1cHBvcnQudGVjdG9uaWMucHJlbWl1bVwiOjF9fSxcIlNVQi00NjI3QjRDOC0zOUU3LTQ5QTQtODFCRS01OEQ0MUM1NlwiOntcInBsYW5OYW1lXCI6XCJ0ZWN0b25pYy1zdGFydGVyXCIsXCJwdWJsaWNQbGFuTmFtZVwiOlwiVGVjdG9uaWMgU3RhcnRlciBQbGFuXCIsXCJwbGFuSURcIjpcIlBSUC1DNEE0MEQ1NS1CODVGLTREQTAtQTVCNS1BMzQ1QkEwNlwiLFwicHJvZHVjdE5hbWVcIjpcInRlY3RvbmljLXN0YXJ0ZXJcIixcInB1YmxpY1Byb2R1Y3ROYW1lXCI6XCJUZWN0b25pYyBTdGFydGVyXCIsXCJwcm9kdWN0SURcIjpcIlBSTy01ODk0QTE4Qy1FQTIxLTRFRTctOTc3My1COUI2MDBBNVwiLFwic2VydmljZVN0YXJ0XCI6XCIyMDE2LTEwLTAyVDE3OjAxOjM4WlwiLFwic2VydmljZUVuZFwiOlwiMjAxNi0xMS0wMlQxNzowMTozOFpcIixcImluVHJpYWxcIjpmYWxzZSxcInRyaWFsT25seVwiOmZhbHNlLFwiZHVyYXRpb25cIjoxLFwiZHVyYXRpb25QZXJpb2RcIjpcIm1vbnRoc1wiLFwiZW50aXRsZW1lbnRzXCI6e1wiY29zdFwiOjEsXCJzb2Z0d2FyZS50ZWN0b25pY2NvbnNvbGVcIjoxfX0sXCJTVUItOUIxRTA2RTMtMkEyMC00M0E5LTlFQUMtRDJCODEwN0JcIjp7XCJwbGFuTmFtZVwiOlwicHJlbWl1bS1jdXN0b21cIixcInB1YmxpY1BsYW5OYW1lXCI6XCJQcmVtaXVtIC0gQ3VzdG9tXCIsXCJwbGFuSURcIjpcIlBSUC05NjRBQUM4Qi01NjhBLTQwMEMtOTEzQS1CMzQ2NDRGRVwiLFwicHJvZHVjdE5hbWVcIjpcInF1YXktZW50ZXJwcmlzZVwiLFwicHVibGljUHJvZHVjdE5hbWVcIjpcIlF1YXkgRW50ZXJwcmlzZVwiLFwicHJvZHVjdElEXCI6XCJQUk8tNDNFNEQ4QTYtOEQ1MS00NDZFLUIyNjMtRDBBNjVDOUZcIixcInNlcnZpY2VTdGFydFwiOlwiMjAxNi0xMC0xM1QxODowOTowMFpcIixcInNlcnZpY2VFbmRcIjpcIjIwMTctMTAtMTNUMTg6MDk6MDBaXCIsXCJpblRyaWFsXCI6ZmFsc2UsXCJ0cmlhbE9ubHlcIjpmYWxzZSxcImR1cmF0aW9uXCI6MSxcImR1cmF0aW9uUGVyaW9kXCI6XCJ5ZWFyc1wiLFwiZW50aXRsZW1lbnRzXCI6e1wiY29zdFwiOjAsXCJzb2Z0d2FyZS5xdWF5XCI6MSxcInNvZnR3YXJlLnF1YXkuYnVpbGRlcnNcIjo5OTk5OTksXCJzb2Z0d2FyZS5xdWF5LmRlcGxveW1lbnRzXCI6MSxcInNvZnR3YXJlLnF1YXkucmVnaW9uc1wiOjEsXCJzdXBwb3J0LnF1YXkucHJlbWl1bVwiOjF9fSxcIlNVQi1ERjAwNTdENC1CMEEwLTRFQjktOTQ0QS05RTAzQzZCQ1wiOntcInBsYW5OYW1lXCI6XCJxdWF5LWVudGVycHJpc2UtYW5udWFsLWN1c3RvbVwiLFwicHVibGljUGxhbk5hbWVcIjpcIlF1YXkgRW50ZXJwcmlzZVwiLFwicGxhbklEXCI6XCJQUlAtQzNFNkU5NTktMkZGRi00QkI3LTgxMjItRDNFOTdFNkFcIixcInByb2R1Y3ROYW1lXCI6XCJxdWF5LWVudGVycHJpc2VcIixcInB1YmxpY1Byb2R1Y3ROYW1lXCI6XCJRdWF5IEVudGVycHJpc2VcIixcInByb2R1Y3RJRFwiOlwiUFJPLTQzRTREOEE2LThENTEtNDQ2RS1CMjYzLUQwQTY1QzlGXCIsXCJzZXJ2aWNlU3RhcnRcIjpcIjIwMTYtMTAtMjVUMDA6MDU6MDBaXCIsXCJzZXJ2aWNlRW5kXCI6XCIyMDE3LTEwLTI0VDAwOjA1OjAwWlwiLFwiaW5UcmlhbFwiOmZhbHNlLFwidHJpYWxPbmx5XCI6ZmFsc2UsXCJkdXJhdGlvblwiOjEsXCJkdXJhdGlvblBlcmlvZFwiOlwieWVhcnNcIixcImVudGl0bGVtZW50c1wiOntcImNvc3RcIjowLFwic29mdHdhcmUucXVheVwiOjEsXCJzb2Z0d2FyZS5xdWF5LmRlcGxveW1lbnRzXCI6OTk5OTk5LFwic3VwcG9ydC5xdWF5LnByZW1pdW1cIjoxfX19fSJ9.XwPbWiyIthfXKhKj5YEO76kCErEmRyjIK5wMhRz8d6bC7spROyrNC0aikP7UuGOA94I-ZdL-bnrrD8Ijc4hNzvA5SwglmBoJ7uYsqm492DNf3AimXPBX8aMolfjvnBVWs4UaCbzwX2ow95GVPxz6M8DdgypzuPWahpR12jkQ63Ryc6jnDh_9DmtUrQXy0y2xcZmRGsgBMQoC9kJANOQ0jmbAuhhZCG15mTmsEC4S12RnJy7wP_tfYoGikRe01FW-_GsRpPV5BXqP55cSR17PvTGsg3l_dNtmKDa_hrhk3F9u2DNE3h-onbezYUa5J4szJfnZU9hcSK0GurpK4H34Sw \ No newline at end of file diff --git a/deploy/quay-ci-app/ci_stack/license_key b/deploy/quay-ci-app/ci_stack/license_key new file mode 100644 index 000000000..cebc2777b --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/license_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAwJYjuXSCqTAEdSz2lv7GtkT2dXkwTS+wE8sj0+k8QEBK8xQb +gkaDGzXSn22mAO2e5cND8wWj8sWeplOFqa7LA/kU+AA/HGV04xrS122yCRJ2D49J +k9gn8RJv7fnzSahK3v+ZhKeXWaPtA+kwl4u3AkEYiG6w38+vl4HCcg3GFY64iaRw +Us2vRs3OaaCS0vkJ2sgZAAl5x5Tke+FKOC3ubqojDs5g2hfLT5QMIpj158YdKNaP +sztRBzh8Dm6mt8UsHECDde2e4VZwlx3ebEoQCcfsY8s5i6OyUphprZYr0P2/E0qM +7dvhbGOBN4eAw2ZJ3el33anQCdWnFzS4gycpawIDAQABAoIBAGjd2FoVzUgfM24y +q5uQ49dAOgvBj8GX5AMDLGEpsXszBxzRqCEKED3y0tupMylyOoHWD9v3CE0busXK +2Q+KdFWXfgmE6NinjjxT0NcpjjZObScP2Pq+SxGD/prQ7d7/2rUO7SNEtq9DCb6F +bcY3d9GsbJVt4LYeOvj+2UiNo3z8pixIVIYBEIAJbiFUf8ImNy18aI2YsgcIKKx3 +XRcZrQc3lJQO4SgzLEflovl11B8Nvw5XXwXaFn35wmp31L5CtKlPeDT6CDNydTqw +T2ri0xPu4vyvuVidDcVJOh3Bpw5FSI9fwBr9PDjOLi2YgjRtQBQhnvvtPpk7vSeU +bVhNN4ECgYEA5C5v1AHURu5tRj7o9I0Po2DLpt1zszd2ly7ED190Ko9qmZqfTyLz +uBzSk86r2+NMxPhp+uMY2LR0c6LiPAbSVpTOSWL2eatfy/9td9TlK5fVcg6N9vH5 +LYrzuelxSnypm6H300t6CvycrfrscOP4Vs2fdx1yZI0wEngTxL5+sgsCgYEA2BDI +OY+eJ53KRVEp5stbUryW7HJC6HBlH2ZHeMCLese6fsvdTyhL0/2OanXdxG3bOK6F +Ilr3UzTK1Krj7U8W0zRnGMVJfaMoEJOwgBtUqm7rjksP2bujRT9OuLKR+MJbLVLC +0ycoS8iOJWCDIczeL21rgqe1pOp839It/MI+YiECgYBZi9u48IrU10as9Y1IQ39q +l1b0gh2grFhu1hx9B/G3rhagdyyjysyoaS8+cDHDlj0PY4l7utmKWa8Fnlt4QRkU +f0tBQ4QElXt/vBrClxrkc66BFzMhQS6Pb+NcBz+9gpSxDewK0KjxXNdD86AMYXqY +3hMBlN3KlhnSdasUX8mqpwKBgDmAFdkDuIIwguD5nZ4XJmGZYMziB55WMwMtM/4V +t8jgGGigFnB3d96dzuXUIkWhOsMV5sZi0QkqtoPsSqYf8yIYAwvbjRhLcGEg/MrK ++zg0NqnynfBC+Et4cpnCpAhAqQUhzkllVVr9r56Q1bUMEWErzH3D5hpScRMbmzN1 ++iYhAoGACxsSOXRHUMOC3tdcErAsfjc04v13MuuiglH29Ap5e/WoGcr++fCWBnCD +9IGnHZvY+th/vkuaefZqE6oDYMa4TvyJJnU/tx+h1+jbuCwpdqGkKp9z0xjIvUJ5 +L6imBl4Dwl5DjJLL1HhbzF3C7DHWTbHsRF/HWwNjbV9nCIii4AY= +-----END RSA PRIVATE KEY----- diff --git a/deploy/quay-ci-app/ci_stack/license_key.pub b/deploy/quay-ci-app/ci_stack/license_key.pub new file mode 100644 index 000000000..e09604dd4 --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/license_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAliO5dIKpMAR1LPaW/sa2RPZ1eTBNL7ATyyPT6TxAQErzFBuCRoMbNdKfbaYA7Z7lw0PzBaPyxZ6mU4WprssD+RT4AD8cZXTjGtLXbbIJEnYPj0mT2CfxEm/t+fNJqEre/5mEp5dZo+0D6TCXi7cCQRiIbrDfz6+XgcJyDcYVjriJpHBSza9Gzc5poJLS+QnayBkACXnHlOR74Uo4Le5uqiMOzmDaF8tPlAwimPXnxh0o1o+zO1EHOHwObqa3xSwcQIN17Z7hVnCXHd5sShAJx+xjyzmLo7JSmGmtlivQ/b8TSozt2+FsY4E3h4DDZknd6XfdqdAJ1acXNLiDJylr jake@coreserver diff --git a/deploy/quay-ci-app/ci_stack/registry_v2_auth.crt b/deploy/quay-ci-app/ci_stack/registry_v2_auth.crt new file mode 100644 index 000000000..88c783efa --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/registry_v2_auth.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVDCCAjwCCQDNYtlT1+tGbzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJV +UzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRQwEgYDVQQK +EwtDb3JlT1MsIEluYzENMAsGA1UECxMEUXVheTESMBAGA1UEAxMJMTI3LjAuMC4x +MB4XDTE2MDUyMzE1MjUxOVoXDTI2MDUyMTE1MjUxOVowbDELMAkGA1UEBhMCVVMx +ETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UEChML +Q29yZU9TLCBJbmMxDTALBgNVBAsTBFF1YXkxEjAQBgNVBAMTCTEyNy4wLjAuMTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRvOt/XGNIovlr1BWxl2oqs +KDlgnESj6bFENDjs9+YLrB3mSWX6w4Dk2IdNU0EKHeVnnsAuBs83jaFsIVJxrC99 +ndv0PaejBovUbWyYN3zCMur8iNGse/FT4WRqks2m0Wr0jmEAX5piX/eWo/7OQdea +wNAGyH7wE0voMpyVSZMBmxRw07zWnwWBihvhOiiCnXZh32GQMplq0wxk4DkBf3hC +SEaAqsFHKfEFPxVXfdPGeiKKK+P2SAh+uN4miJpGf7Xkuj/Mmzxr1ajNczhPT6OM +pw0R3h/mok1S8zcp8lN/eDdKwjMeP4Rx+Lc0cRluZNa8otq9qYPNSCIkvsSz5b8C +AwEAATANBgkqhkiG9w0BAQUFAAOCAQEAZaaD8fLWEh4RGZ7X38IM/ocwDKaXWpDp +0EC3KMEuar1MET3MtVIXy/k/BLr0HmLRQ2KSV3wFfyOInseVeCvIcKZZo/JF28gR +LJVBcjExSIr6X8RoPgmKt7AdjlUjPV5XpRzDpfYcMaqpjJa75x6RoxC2ybh5Apyk +EzL3Naysk6TVPi5ckUYMLfw3JEbCeaEY4KNwVgsNcs447EcBxwGHTBqGOYtpIfku +SMas81oniMo9LMKv19Bn1oOforaqh8P2c57yregDsCDmP6j0gqkYjhJFCj5JNAKK +KT35QIfTbVFeCXAoLw0+o9Ma1Q+j7LfwdxnikUHNVZmlmjQmTBMwqg== +-----END CERTIFICATE----- diff --git a/deploy/quay-ci-app/ci_stack/registry_v2_auth_private.key b/deploy/quay-ci-app/ci_stack/registry_v2_auth_private.key new file mode 100644 index 000000000..739c5fa0c --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/registry_v2_auth_private.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApG8639cY0ii+WvUFbGXaiqwoOWCcRKPpsUQ0OOz35gusHeZJ +ZfrDgOTYh01TQQod5WeewC4GzzeNoWwhUnGsL32d2/Q9p6MGi9RtbJg3fMIy6vyI +0ax78VPhZGqSzabRavSOYQBfmmJf95aj/s5B15rA0AbIfvATS+gynJVJkwGbFHDT +vNafBYGKG+E6KIKddmHfYZAymWrTDGTgOQF/eEJIRoCqwUcp8QU/FVd908Z6Ioor +4/ZICH643iaImkZ/teS6P8ybPGvVqM1zOE9Po4ynDRHeH+aiTVLzNynyU394N0rC +Mx4/hHH4tzRxGW5k1ryi2r2pg81IIiS+xLPlvwIDAQABAoIBAANdV0oPP63FMafw +zYybRO6DeUs7Q9dPt09uQtdLWgM2B+6QsL3KdMelZxzVozd4eoYgKaprBq6kx1wf +N0tVkh1ip6FBjSVp+49O6HJJZxFBdANE6ZPIwLx+Z+VDHP/iQvS6TlODy3EARFBv +n6luFQDRZNKc4OtgBDUQakCz+U5tuJLqoR8wk/WGQP4FJiZlVwJqNPXMA1A2Mrri +n6WkhfpB30Z5dl9zsR+zJRbwRBjgJCYN37YC7zdHRfIhBPBvDT+8ApR50BGvPGN3 +sLQuH2FsskbgPsIrWMfCxtWr2xbw028GOe7TSjEG63EG7oGAT0O2eQmAcuPc4Dqj +Urn8saECgYEA2LkCe6MysmOtattC/gi3B/rIoOCd+4l9yTnW7S7nk/hdeOzxyqX1 +P7OgVeoYLLk3UJy3qTrNDnc0eGTJz0XyPhLlX0f9lduiSMH92XpNsBG7ngnyMCQF +eAZz8ZlDZC39I8y9CzdcHSLxuHKmQ9jhgUm+EIuf8OlrkjchPdE06i8CgYEAwjxG +cDA5X1hKYgQTObq245vR3txkvETmLVB7hWkjWLzR//a4hXHJT1fg2LxD5EMtCKZ2 +WXKhcy3tbja+c/IEI1L1wA2v/aWlEvi9n354EQ1QzkvCBDFP5enLnItAUzJQ0IgE +dtSUskK+li8aY2LB0EPt0eJmYU0cZUJXbl/ZKXECgYAAtttjPO512A5CQ+a8n5q6 +1ADFRvg+U/2uJBqpPXZV7oOgWmeRm2prg1QL9HGP9CxSf7G7RQ5X9dyeaPahUEG0 +IqvO3JXhYI/wXXNQvC51XhmYM8AwmG3ML3lCWpb2RZCIBay51Lzg+7SAPyB9KMHV +g0C1HUCxspNAMB5T7dSW0QKBgGkxRaCarWeypE4jENpyAXyRNf8xcyj3U4V1EgB1 +qVv0nvK2BsbWkgTzfeVDSK2FqA0IQg49Y6zCUdUfttOKXa1Xz5ocj5SaMiVtKx0G +3DW39WxUYRXuMuw8SzZTwBmOpW/aSjik9ob4WMlzZyIuKPMG5vSFXZcSsO8yF7HC +HRUxAoGBAKtCRLT9I5Ap37gWT8W6AAZygoUqhlYO9qygQrBDaJsHj0ZSHM0TO3ig +Bwq/UxDHBKFV3hmqx5Zmpoa9ZrURb4cBw/+TLq2ppXPLEU+XmEVmqL2323Vyr/Ih +CAIVWFsY3EGQL7TArOfag+v0Nxq3pypOhjweqIWEMDg+gV2+GHhQ +-----END RSA PRIVATE KEY----- diff --git a/deploy/quay-ci-app/ci_stack/signing-private.gpg b/deploy/quay-ci-app/ci_stack/signing-private.gpg new file mode 100644 index 000000000..baaf6af8f Binary files /dev/null and b/deploy/quay-ci-app/ci_stack/signing-private.gpg differ diff --git a/deploy/quay-ci-app/ci_stack/signing-public.gpg b/deploy/quay-ci-app/ci_stack/signing-public.gpg new file mode 100644 index 000000000..e91779503 --- /dev/null +++ b/deploy/quay-ci-app/ci_stack/signing-public.gpg @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQENBFTVMzABCAC8jcnCrNHKk0LgyZTdTFtf9Qm2bK27Y0EyyI8tWefUt4LhQRCA +14dksJVzqWBtpHJnqkYUwfoXZmdz4e9fSS1mmoiHlDwzkuNXx2J1HAnXSxgNMV1D +JQmfxhKQzFTgkTEN03txPZrOMrDNIZSw0gkAbiBGuQXk9/HNGbzdjkd3vk1GF7Vk +v1vITmWQG+QQi7H8zR1NYYuFQb5cdDDuOoQWHXNMIZmK27StZ6MUot3NlquZbs1q +5Gr1HHog0qx+0uYn441zghZ9R1JqaAig0V3eJ8UAbTIMZPO09UUBQKC7O7OgOX/H +92zGWGwkTMUqJNJUr/dj5ocQbpFk8X3yz+d9ABEBAAG0RFF1YXkuaW8gQUNJIENv +bnZlcnRlciAoQUNJIGNvbnZlcnNpb24gc2lnbmluZyBrZXkpIDxzdXBwb3J0QHF1 +YXkuaW8+iQE5BBMBAgAjBQJU1TMwAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgEC +F4AACgkQRjIEfu6zIiHo9Af+MCE4bUOrQ6yrHSPHebHwSARULaTB0Rlj4BAXlv+A +nUJDaaYaYExo8SHZMWF5X4d4mh57DJOsIXMjIWNKpf9/0hpxRu+P8p77YtXOOeRS +3xFdq7cOK1yQ8h/iRoXyLaxAFgWvVH+Ttmx4DLr+NsyzEQBjADeBCcF4YR9OZ7fj +ZYsoq68hH0W7zgZTSrCgvyGxdpu+UWWk/eV/foktxKBMV8K2GmAwyOlsAm59PgUI +EhfFH0WAEx6+jsMFLkn7USPWomFeyMwJJEiMKYCwALWIbNz1/1dtrZZs2QmBcjAu +AMFQhx8fykH4ON8a6fpS3TOEzf0HV1NX295O8wb8vS9B7w== +=aImY +-----END PGP PUBLIC KEY BLOCK----- diff --git a/deploy/quay-ci-app/manifest.jsonnet b/deploy/quay-ci-app/manifest.jsonnet new file mode 100644 index 000000000..da65a523e --- /dev/null +++ b/deploy/quay-ci-app/manifest.jsonnet @@ -0,0 +1,66 @@ +local appr = import "appr.libsonnet"; + +function( + params={} +) + +appr.package({ + package: { + name: "quay/quay-ci-app", + author: "Antoine Legrand", + version: std.split(importstr "VERSION", "\n")[0], + description: "quay", + license: "MIT", + expander: "jinja2" +}, + +variables: { + stack_path: "ci_stack", + config: (import "templates/config.libsonnet")($.variables), + namespace: "default", + tag: "master", + image: "quay.io/quay/quay-ci:%s" % $.variables.tag, + docker_user: 'changeme', + docker_pass: 'changeme', + domain: 'quay-%s.k8s.devtable.com' % $.variables.tag, + ingress: { + class: 'nginx', + tls: "kubernetes.io/tls-acme-stg", + domains: std.split($.variables.domain, ","), + annotations: {} + }, + + license: null, + db: { + user: 'quay', + password: 'quay', + name: 'quay', + }, +} + (import "params.json"), + +resources: appr.compact([ + { + template: (importstr "templates/quay-dev-initdb-job.yaml"), + }, +]), + +deploy: [ + { + name: "quay/postgres-app", + variables: { + user: $.variables.db.user, + dbname: $.variables.db.name, + password: $.variables.db.password + } + }, + + { + name: "quay/quay-app", + variables: $.variables + }, + + # Deploy the initdb script + {name: "$self"}, + + ], +}, params) diff --git a/deploy/quay-ci-app/params.json b/deploy/quay-ci-app/params.json new file mode 100644 index 000000000..d2101f304 --- /dev/null +++ b/deploy/quay-ci-app/params.json @@ -0,0 +1 @@ +{"image": "quay.io/quay/quay-ci:master", "tag": "master"} diff --git a/deploy/quay-ci-app/templates/config.libsonnet b/deploy/quay-ci-app/templates/config.libsonnet new file mode 100644 index 000000000..e06aeb0fa --- /dev/null +++ b/deploy/quay-ci-app/templates/config.libsonnet @@ -0,0 +1,23 @@ +function(vars={}) +{ + REGISTRY_TITLE: "Quay (%s)" % vars.domain, + REGISTRY_TITLE_SHORT: "Quay (%s)" % vars.domain, + TESTING: true, + DEBUGGING: true, + USE_CDN: false, + FEATURE_ANONYMOUS_ACCESS: true, + FEATURE_MAILING: false, + ENTERPRISE_LOGO_URL: "/static/img/quay-logo.png", + LOG_ARCHIVE_LOCATION: "default", + SERVER_HOSTNAME: vars.domain, + EXTERNAL_TLS_TERMINATION: true, + TAG_EXPIRATION_OPTIONS: ["2d"], + DISTRIBUTED_STORAGE_CONFIG: { + default: [ + "LocalStorage", + {storage_path: "/datastorage/registry"}]}, + DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [], + DISTRIBUTED_STORAGE_PREFERENCE: ["default"], + USERFILES_LOCATION: "default", + USERFILES_PATH: "userfiles/", +} diff --git a/deploy/quay-ci-app/templates/quay-dev-initdb-job.yaml b/deploy/quay-ci-app/templates/quay-dev-initdb-job.yaml new file mode 100644 index 000000000..55a07b14d --- /dev/null +++ b/deploy/quay-ci-app/templates/quay-dev-initdb-job.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: quay-dev-initdb +spec: + activeDeadlineSeconds: 600 + template: + metadata: + name: quay-dev-initdb + spec: + containers: + - name: quay + image: quay.io/quay/quay-ci:master + env: + - name: TEST_DATABASE_URI + value: "postgres://" + - name: SKIP_DB_SCHEMA + value: "true" + command: + - venv/bin/python + - initdb.py + volumeMounts: + - name: configvolume + readOnly: false + mountPath: /conf/stack + resources: + limits: + cpu: 500m + memory: 500Mi + imagePullSecrets: + - name: coreos-pull-secret + volumes: + - name: configvolume + secret: + secretName: quay-enterprise-config-secret + restartPolicy: Never diff --git a/test/data/test.db b/test/data/test.db index 2dde19399..7f79f6caa 100644 Binary files a/test/data/test.db and b/test/data/test.db differ diff --git a/util/config/provider/baseprovider.py b/util/config/provider/baseprovider.py index 663c64588..6696ae88e 100644 --- a/util/config/provider/baseprovider.py +++ b/util/config/provider/baseprovider.py @@ -109,7 +109,7 @@ class BaseProvider(object): indicating that this container requires a restart. """ raise NotImplementedError - + def get_volume_path(self, directory, filename): """ Helper for constructing file paths, which may differ between providers. For example, kubernetes can't have subfolders in configmaps """ diff --git a/util/config/provider/k8sprovider.py b/util/config/provider/k8sprovider.py index c3965f015..6b959a2e5 100644 --- a/util/config/provider/k8sprovider.py +++ b/util/config/provider/k8sprovider.py @@ -54,20 +54,20 @@ class KubernetesConfigProvider(FileConfigProvider): self._update_secret_file(filename, contents) except IOError as ioe: raise CannotWriteConfigException(str(ioe)) - + def volume_file_exists(self, filename): secret = self._lookup_secret() if not secret or not secret.get('data'): return False return filename in secret['data'] - + def list_volume_directory(self, path): secret = self._lookup_secret() - + if not secret: return [] - + paths = [] for filename in secret.get('data', {}): if filename.startswith(path): @@ -150,4 +150,4 @@ class KubernetesConfigProvider(FileConfigProvider): return session.send(request.prepare(), verify=False, timeout=2) def get_volume_path(self, directory, filename): - return "_".join([directory.rstrip('/'), filename]) \ No newline at end of file + return "_".join([directory.rstrip('/'), filename])