diff --git a/.github/workflows/deploy_on_push_tag.yaml b/.github/workflows/deploy_on_push_tag.yaml deleted file mode 100644 index c7f1a3c..0000000 --- a/.github/workflows/deploy_on_push_tag.yaml +++ /dev/null @@ -1,74 +0,0 @@ -name: deploy -on: - push: - tags: - - '*.*' -jobs: - build_and_publish: - runs-on: [ubuntu-latest] - env: - DOCKER_LOGIN: ${{ secrets.DOCKER_LOGIN }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - steps: - - name: login_to_docker - run: echo ${DOCKER_PASSWORD} | docker login -u ${DOCKER_LOGIN} --password-stdin - - name: checkout - uses: actions/checkout@v2 - - name: set_release_version - run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF:10} - - name: build_image - run: docker build -t $DOCKER_LOGIN/gitrello:current -t $DOCKER_LOGIN/gitrello:$RELEASE_VERSION -f deploy/Dockerfile . - - name: push_current_image_to_docker_io - run: docker push $DOCKER_LOGIN/gitrello:current - - name: push_versioned_image_to_docker_io - run: docker push $DOCKER_LOGIN/gitrello:$RELEASE_VERSION - collect_static: - needs: [build_and_publish] - runs-on: [ubuntu-latest] - env: - K8S_URL: ${{ secrets.K8S_URL }} - K8S_TOKEN: ${{ secrets.K8S_TOKEN }} - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@v1 - with: - python-version: '3.8.5' - architecture: 'x64' - - name: install_requirements - run: pip install requests - - name: collect_static - run: python deploy/run_kubernetes_job.py -n collect-static -f collect-static-job.yaml -l 180 -s 10 - migrate_database: - needs: [build_and_publish] - runs-on: [ubuntu-latest] - env: - K8S_URL: ${{ secrets.K8S_URL }} - K8S_TOKEN: ${{ secrets.K8S_TOKEN }} - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@v1 - with: - python-version: '3.8.5' - architecture: 'x64' - - name: install_requirements - run: pip install requests - - name: migrate_database - run: python deploy/run_kubernetes_job.py -n migrate-database -f migrate-database-job.yaml -l 180 -s 10 - deploy: - needs: [collect_static, migrate_database] - runs-on: [ubuntu-latest] - env: - K8S_URL: ${{ secrets.K8S_URL }} - K8S_TOKEN: ${{ secrets.K8S_TOKEN }} - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@v1 - with: - python-version: '3.8.5' - architecture: 'x64' - - name: set_release_version - run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF:10} - - name: install_requirements - run: pip install requests - - name: deploy - run: python deploy/deploy.py diff --git a/.github/workflows/run_tests_on_push_to_develop.yaml b/.github/workflows/run_tests_on_push_to_develop.yaml deleted file mode 100644 index bde05dd..0000000 --- a/.github/workflows/run_tests_on_push_to_develop.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: run_tests -on: - push: - tags: - - '!refs/tags/*' - branches: - - 'develop' -jobs: - build_and_publish: - runs-on: [ubuntu-latest] - env: - DOCKER_LOGIN: ${{ secrets.DOCKER_LOGIN }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - steps: - - name: login_to_docker - run: echo ${DOCKER_PASSWORD} | docker login -u ${DOCKER_LOGIN} --password-stdin - - name: checkout - uses: actions/checkout@v2 - - name: build_image - run: docker build -t $DOCKER_LOGIN/gitrello:test -f deploy/Dockerfile --target=test . - - name: push_image_to_docker.io - run: docker push $DOCKER_LOGIN/gitrello:test - run_tests: - needs: [build_and_publish] - runs-on: [ubuntu-latest] - env: - K8S_URL: ${{ secrets.K8S_URL }} - K8S_TOKEN: ${{ secrets.K8S_TOKEN }} - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@v1 - with: - python-version: '3.8.5' - architecture: 'x64' - - name: install_requirements - run: pip install requests - - name: run_tests - run: python deploy/run_kubernetes_job.py -n run-tests -f run-tests-job.yaml -l 180 -s 10 diff --git a/.gitignore b/.gitignore index 6e24ff6..186315c 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ GitHub.sublime-settings # Credentials gcs_creds.json +overrides.yaml diff --git a/deploy/Dockerfile b/Dockerfile similarity index 97% rename from deploy/Dockerfile rename to Dockerfile index 6f08ab0..41ecd33 100644 --- a/deploy/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8.3-slim-buster AS base +FROM python:3.8.5-slim-buster AS base ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PIP_NO_CACHE_DIR=off \ diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..5b8aff5 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,143 @@ +def tag + +pipeline { + environment { + IMAGE_NAME = 'fnsdev/gitrello' + } + agent { + kubernetes { + defaultContainer 'jnlp' + yaml """ + apiVersion: v1 + kind: Pod + metadata: + name: ci + labels: + app: jenkins + spec: + nodeSelector: + type: ci + containers: + - name: python + image: python:3.8.5-slim-buster + command: + - cat + tty: true + resources: + requests: + memory: "400Mi" + cpu: "0.5" + limits: + memory: "400Mi" + cpu: "0.5" + - name: docker + image: docker:19.03 + command: + - cat + tty: true + resources: + requests: + memory: "200Mi" + cpu: "0.2" + limits: + memory: "200Mi" + cpu: "0.2" + volumeMounts: + - name: dockersock + mountPath: /var/run/docker.sock + - name: helm + image: lachlanevenson/k8s-helm:v3.3.1 + command: + - cat + tty: true + volumes: + - name: dockersock + hostPath: + path: /var/run/docker.sock + """ + } + } + stages { + stage ('Run tests') { + environment { + DJANGO_DB_NAME = credentials('test-db-name') + DJANGO_DB_USER = credentials('test-db-user') + DJANGO_DB_HOST = credentials('test-db-host') + DJANGO_DB_PORT = credentials('test-db-port') + DJANGO_DB_PASSWORD = credentials('test-db-password') + } + steps { + container('python') { + sh """ + apt-get update && \ + apt-get install --no-install-recommends -y libpq-dev git gcc libc6-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + """ + sh "pip install -r requirements.txt" + sh "cd gitrello && python manage.py test --noinput" + } + } + } + stage ('Set tag') { + steps { + script { + tag = sh(script: 'git describe', returnStdout: true).trim() + } + } + } + stage('Build image') { + steps { + container('docker') { + sh "docker build -t ${IMAGE_NAME}:${tag} ." + } + } + } + stage('Publish image') { + steps { + container('docker') { + withCredentials([usernamePassword(credentialsId: 'dockerhub', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + sh "echo ${PASSWORD} | docker login -u ${USERNAME} --password-stdin" + sh "docker push ${IMAGE_NAME}:${tag}" + } + } + } + } + stage('Migrate database') { + environment { + DJANGO_DB_NAME = credentials('db-name') + DJANGO_DB_USER = credentials('db-user') + DJANGO_DB_HOST = credentials('db-host') + DJANGO_DB_PORT = credentials('db-port') + DJANGO_DB_PASSWORD = credentials('db-password') + } + steps { + container('python') { + sh "cd gitrello && python manage.py migrate" + } + } + } + stage('Collect static') { + environment { + GS_BUCKET_NAME = credentials('gs-bucket-name') + GS_PROJECT_ID = credentials('gs-project-id') + } + steps { + container('python') { + withCredentials([file(credentialsId: 'gs-credentials', variable: 'GS_CREDENTIALS')]) { + sh "cd gitrello && python manage.py collectstatic --noinput --settings=gitrello.settings_prod" + } + } + } + } + stage('Deploy chart') { + steps { + container('helm') { + withCredentials([file(credentialsId: 'gitrello-overrides', variable: 'OVERRIDES')]) { + sh "helm upgrade gitrello --install ./manifests/gitrello -f ${OVERRIDES} --set deployment.image.tag=${tag}" + } + } + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..7154aef --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# GITrello + +[![Build Status](https://gitrello.me/jenkins/buildStatus/icon?job=gitrello)](https://gitrello.me/jenkins/job/gitrello/) diff --git a/deploy/deploy.py b/deploy/deploy.py deleted file mode 100644 index 9444d1f..0000000 --- a/deploy/deploy.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -import sys - -import requests - - -def main(): - k8s_url = os.getenv('K8S_URL') - k8s_token = os.getenv('K8S_TOKEN') - data = { - 'spec': { - 'template': { - 'spec': { - 'containers': [ - { - 'name': 'gitrello', - 'image': f'fnsdev/gitrello:{os.getenv("RELEASE_VERSION")}' - } - ] - } - } - } - } - headers = { - 'Content-Type': 'application/strategic-merge-patch+json', - 'Authorization': f'Bearer {k8s_token}', - } - - print('Patch deployment') - response = requests.patch( - f'{k8s_url}/apis/apps/v1/namespaces/default/deployments/gitrello', - headers=headers, - json=data, - ) - - if response.status_code not in (200, 201): - print(response.text) - print('Patching deployment failed') - sys.exit(-1) - - # TODO check deployment status - print('Patch deployment succeeded') - - -if __name__ == '__main__': - main() diff --git a/deploy/manifests/deployments/gitrello-deployment.yaml b/deploy/manifests/deployments/gitrello-deployment.yaml deleted file mode 100644 index 923db87..0000000 --- a/deploy/manifests/deployments/gitrello-deployment.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# TODO add requests & limits -# TODO increase replicas -apiVersion: apps/v1 -kind: Deployment -metadata: - name: gitrello - labels: - app: gitrello -spec: - replicas: 1 - selector: - matchLabels: - app: gitrello - template: - metadata: - labels: - app: gitrello - spec: - containers: - - image: fnsdev/gitrello:latest - name: gitrello - env: - - name: DJANGO_SECRET_KEY - valueFrom: - secretKeyRef: - name: environment - key: django_secret_key - - name: DJANGO_DB_NAME - valueFrom: - secretKeyRef: - name: environment - key: django_db_name - - name: DJANGO_DB_USER - valueFrom: - secretKeyRef: - name: environment - key: django_db_user - - name: DJANGO_DB_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: django_db_password - - name: DJANGO_DB_HOST - valueFrom: - secretKeyRef: - name: environment - key: django_db_host - - name: DJANGO_DB_PORT - valueFrom: - secretKeyRef: - name: environment - key: django_db_port - - name: EMAIL_HOST_USER - valueFrom: - secretKeyRef: - name: environment - key: email_host_user - - name: EMAIL_HOST_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: email_host_password - - name: GS_BUCKET_NAME - valueFrom: - secretKeyRef: - name: environment - key: gs_bucket_name - - name: GS_CREDENTIALS - valueFrom: - secretKeyRef: - name: environment - key: gs_credentials - - name: GS_PROJECT_ID - valueFrom: - secretKeyRef: - name: environment - key: gs_project_id - - name: URL - valueFrom: - secretKeyRef: - name: environment - key: url - - name: GITHUB_INTEGRATION_SERVICE_URL - valueFrom: - secretKeyRef: - name: environment - key: github_integration_service_url - - name: GITHUB_CLIENT_ID - valueFrom: - secretKeyRef: - name: environment - key: github_client_id - - name: GITHUB_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: environment - key: github_client_secret - ports: - - containerPort: 80 - name: gitrello diff --git a/deploy/manifests/ingresses/gitrello-ingress.yaml b/deploy/manifests/ingresses/gitrello-ingress.yaml deleted file mode 100644 index c354f48..0000000 --- a/deploy/manifests/ingresses/gitrello-ingress.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: gitrello-service-ingress - annotations: - kubernetes.io/ingress.class: "nginx" -spec: - tls: - - hosts: - - gitrello.me - - www.gitrello.me - secretName: tls - rules: - - host: gitrello.me - http: - paths: - - path: / - backend: - serviceName: gitrello - servicePort: 80 - - host: www.gitrello.me - http: - paths: - - path: / - backend: - serviceName: gitrello - servicePort: 80 diff --git a/deploy/manifests/jobs/collect-static-job.yaml b/deploy/manifests/jobs/collect-static-job.yaml deleted file mode 100644 index 03f2861..0000000 --- a/deploy/manifests/jobs/collect-static-job.yaml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: collect-static -spec: - template: - spec: - containers: - - name: gitrello-collect-static - image: fnsdev/gitrello:current - imagePullPolicy: Always - command: ["sh", "-c", "python manage.py collectstatic --noinput --settings=gitrello.settings_prod"] - env: - - name: DJANGO_SECRET_KEY - valueFrom: - secretKeyRef: - name: environment - key: django_secret_key - - name: DJANGO_DB_NAME - valueFrom: - secretKeyRef: - name: environment - key: django_db_name - - name: DJANGO_DB_USER - valueFrom: - secretKeyRef: - name: environment - key: django_db_user - - name: DJANGO_DB_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: django_db_password - - name: DJANGO_DB_HOST - valueFrom: - secretKeyRef: - name: environment - key: django_db_host - - name: DJANGO_DB_PORT - valueFrom: - secretKeyRef: - name: environment - key: django_db_port - - name: EMAIL_HOST_USER - valueFrom: - secretKeyRef: - name: environment - key: email_host_user - - name: EMAIL_HOST_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: email_host_password - - name: GS_BUCKET_NAME - valueFrom: - secretKeyRef: - name: environment - key: gs_bucket_name - - name: GS_CREDENTIALS - valueFrom: - secretKeyRef: - name: environment - key: gs_credentials - - name: GS_PROJECT_ID - valueFrom: - secretKeyRef: - name: environment - key: gs_project_id - restartPolicy: Never - backoffLimit: 1 - activeDeadlineSeconds: 120 diff --git a/deploy/manifests/jobs/migrate-database-job.yaml b/deploy/manifests/jobs/migrate-database-job.yaml deleted file mode 100644 index 6718fb3..0000000 --- a/deploy/manifests/jobs/migrate-database-job.yaml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: migrate-database -spec: - template: - spec: - containers: - - name: gitrello-migrate-database - image: fnsdev/gitrello:current - imagePullPolicy: Always - command: ["sh", "-c", "python manage.py migrate --noinput --settings=gitrello.settings_prod"] - env: - - name: DJANGO_SECRET_KEY - valueFrom: - secretKeyRef: - name: environment - key: django_secret_key - - name: DJANGO_DB_NAME - valueFrom: - secretKeyRef: - name: environment - key: django_db_name - - name: DJANGO_DB_USER - valueFrom: - secretKeyRef: - name: environment - key: django_db_user - - name: DJANGO_DB_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: django_db_password - - name: DJANGO_DB_HOST - valueFrom: - secretKeyRef: - name: environment - key: django_db_host - - name: DJANGO_DB_PORT - valueFrom: - secretKeyRef: - name: environment - key: django_db_port - - name: EMAIL_HOST_USER - valueFrom: - secretKeyRef: - name: environment - key: email_host_user - - name: EMAIL_HOST_PASSWORD - valueFrom: - secretKeyRef: - name: environment - key: email_host_password - - name: GS_BUCKET_NAME - valueFrom: - secretKeyRef: - name: environment - key: gs_bucket_name - - name: GS_CREDENTIALS - valueFrom: - secretKeyRef: - name: environment - key: gs_credentials - - name: GS_PROJECT_ID - valueFrom: - secretKeyRef: - name: environment - key: gs_project_id - restartPolicy: Never - backoffLimit: 1 - activeDeadlineSeconds: 120 diff --git a/deploy/manifests/jobs/run-tests-job.yaml b/deploy/manifests/jobs/run-tests-job.yaml deleted file mode 100644 index 96c238e..0000000 --- a/deploy/manifests/jobs/run-tests-job.yaml +++ /dev/null @@ -1,40 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: run-tests -spec: - template: - spec: - containers: - - name: gitrello-tests - image: fnsdev/gitrello:test - imagePullPolicy: Always - env: - - name: DJANGO_DB_NAME - valueFrom: - secretKeyRef: - name: test-environment - key: django_db_name - - name: DJANGO_DB_USER - valueFrom: - secretKeyRef: - name: test-environment - key: django_db_user - - name: DJANGO_DB_PASSWORD - valueFrom: - secretKeyRef: - name: test-environment - key: django_db_password - - name: DJANGO_DB_HOST - valueFrom: - secretKeyRef: - name: test-environment - key: django_db_host - - name: DJANGO_DB_PORT - valueFrom: - secretKeyRef: - name: test-environment - key: django_db_port - restartPolicy: Never - backoffLimit: 1 - activeDeadlineSeconds: 120 diff --git a/deploy/manifests/policies/cockroachdb-budget.yaml b/deploy/manifests/policies/cockroachdb-budget.yaml deleted file mode 100644 index 4b67c34..0000000 --- a/deploy/manifests/policies/cockroachdb-budget.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: cockroachdb-budget - labels: - app: cockroachdb -spec: - selector: - matchLabels: - app: cockroachdb - maxUnavailable: 1 diff --git a/deploy/manifests/roles/cockroachdb-cluster-role-binding.yaml b/deploy/manifests/roles/cockroachdb-cluster-role-binding.yaml deleted file mode 100644 index b88a2e1..0000000 --- a/deploy/manifests/roles/cockroachdb-cluster-role-binding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: cockroachdb - labels: - app: cockroachdb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cockroachdb -subjects: -- kind: ServiceAccount - name: cockroachdb - namespace: default diff --git a/deploy/manifests/roles/cockroachdb-cluster-role.yaml b/deploy/manifests/roles/cockroachdb-cluster-role.yaml deleted file mode 100644 index d5ae2fa..0000000 --- a/deploy/manifests/roles/cockroachdb-cluster-role.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: cockroachdb - labels: - app: cockroachdb -rules: -- apiGroups: - - certificates.k8s.io - resources: - - certificatesigningrequests - verbs: - - create - - get - - watch diff --git a/deploy/manifests/roles/cockroachdb-role-binding.yaml b/deploy/manifests/roles/cockroachdb-role-binding.yaml deleted file mode 100644 index 885b447..0000000 --- a/deploy/manifests/roles/cockroachdb-role-binding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: cockroachdb - labels: - app: cockroachdb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: cockroachdb -subjects: -- kind: ServiceAccount - name: cockroachdb - namespace: default diff --git a/deploy/manifests/roles/cockroachdb-role.yaml b/deploy/manifests/roles/cockroachdb-role.yaml deleted file mode 100644 index f1437f3..0000000 --- a/deploy/manifests/roles/cockroachdb-role.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: cockroachdb - labels: - app: cockroachdb -rules: -- apiGroups: - - "" - resources: - - secrets - verbs: - - create - - get diff --git a/deploy/manifests/roles/default_admin_cluster_role_binding.yaml b/deploy/manifests/roles/default_admin_cluster_role_binding.yaml deleted file mode 100644 index 814efb9..0000000 --- a/deploy/manifests/roles/default_admin_cluster_role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: default-cluster-admin-role-binding -subjects: - - kind: ServiceAccount - name: default - namespace: default -roleRef: - kind: ClusterRole - name: cluster-admin - apiGroup: rbac.authorization.k8s.io diff --git a/deploy/manifests/service_accounts/cockroachdb-service-account.yaml b/deploy/manifests/service_accounts/cockroachdb-service-account.yaml deleted file mode 100644 index 7c6a9a0..0000000 --- a/deploy/manifests/service_accounts/cockroachdb-service-account.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: cockroachdb - labels: - app: cockroachdb diff --git a/deploy/manifests/services/cockroachdb-public-service.yaml b/deploy/manifests/services/cockroachdb-public-service.yaml deleted file mode 100644 index ee6373e..0000000 --- a/deploy/manifests/services/cockroachdb-public-service.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - # This service is meant to be used by clients of the database. It exposes a ClusterIP that will - # automatically load balance connections to the different database pods. - name: cockroachdb-public - labels: - app: cockroachdb - annotations: - metallb.universe.tf/allow-shared-ip: gitrello -spec: - ports: - # The main port, served by gRPC, serves Postgres-flavor SQL, internode - # traffic and the cli. - - port: 26257 - targetPort: 26257 - name: grpc - # The secondary port serves the UI as well as health and debug endpoints. - - port: 8080 - targetPort: 8080 - name: http - selector: - app: cockroachdb - type: LoadBalancer diff --git a/deploy/manifests/services/cockroachdb-service.yaml b/deploy/manifests/services/cockroachdb-service.yaml deleted file mode 100644 index cd87baa..0000000 --- a/deploy/manifests/services/cockroachdb-service.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - # This service only exists to create DNS entries for each pod in the stateful - # set such that they can resolve each other's IP addresses. It does not - # create a load-balanced ClusterIP and should not be used directly by clients - # in most circumstances. - name: cockroachdb - labels: - app: cockroachdb - annotations: - # Use this annotation in addition to the actual publishNotReadyAddresses - # field below because the annotation will stop being respected soon but the - # field is broken in some versions of Kubernetes: - # https://github.com/kubernetes/kubernetes/issues/58662 - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - # Enable automatic monitoring of all instances when Prometheus is running in the cluster. - prometheus.io/scrape: "true" - prometheus.io/path: "_status/vars" - prometheus.io/port: "8080" -spec: - ports: - - port: 26257 - targetPort: 26257 - name: grpc - - port: 8080 - targetPort: 8080 - name: http - # We want all pods in the StatefulSet to have their addresses published for - # the sake of the other CockroachDB pods even before they're ready, since they - # have to be able to talk to each other in order to become ready. - publishNotReadyAddresses: true - clusterIP: None - selector: - app: cockroachdb diff --git a/deploy/manifests/services/gitrello-service.yaml b/deploy/manifests/services/gitrello-service.yaml deleted file mode 100644 index c4876bf..0000000 --- a/deploy/manifests/services/gitrello-service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: gitrello - labels: - app: gitrello -spec: - ports: - - protocol: TCP - port: 80 - targetPort: 80 - name: http - selector: - app: gitrello - type: ClusterIP diff --git a/deploy/manifests/services/nginx-ingress-service.yaml b/deploy/manifests/services/nginx-ingress-service.yaml deleted file mode 100644 index da96360..0000000 --- a/deploy/manifests/services/nginx-ingress-service.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: ingress-nginx - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx - annotations: - metallb.universe.tf/allow-shared-ip: gitrello -spec: - type: LoadBalancer - ports: - - name: http - port: 80 - targetPort: 80 - protocol: TCP - - name: https - port: 443 - targetPort: 443 - protocol: TCP - selector: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx diff --git a/deploy/manifests/statefulsets/cockroachdb-statefulset.yaml b/deploy/manifests/statefulsets/cockroachdb-statefulset.yaml deleted file mode 100644 index fdd1777..0000000 --- a/deploy/manifests/statefulsets/cockroachdb-statefulset.yaml +++ /dev/null @@ -1,128 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: cockroachdb -spec: - serviceName: "cockroachdb" - replicas: 3 - selector: - matchLabels: - app: cockroachdb - template: - metadata: - labels: - app: cockroachdb - spec: - serviceAccountName: cockroachdb - # Init containers are run only once in the lifetime of a pod, before - # it's started up for the first time. It has to exit successfully - # before the pod's main containers are allowed to start. - initContainers: - # The init-certs container sends a certificate signing request to the - # kubernetes cluster. - # You can see pending requests using: kubectl get csr - # CSRs can be approved using: kubectl certificate approve - # - # All addresses used to contact a node must be specified in the --addresses arg. - # - # In addition to the node certificate and key, the init-certs entrypoint will symlink - # the cluster CA to the certs directory. - - name: init-certs - image: cockroachdb/cockroach-k8s-request-cert:0.4 - imagePullPolicy: IfNotPresent - command: - - "/bin/ash" - - "-ecx" - - "/request-cert -namespace=${POD_NAMESPACE} -certs-dir=/cockroach-certs -type=node -addresses=0.0.0.0,localhost,127.0.0.1,$(hostname -f),$(hostname -f|cut -f 1-2 -d '.'),cockroachdb-public,cockroachdb-public.$(hostname -f|cut -f 3- -d '.') -symlink-ca-from=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - volumeMounts: - - name: certs - mountPath: /cockroach-certs - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: app - operator: In - values: - - cockroachdb - topologyKey: kubernetes.io/hostname - containers: - - name: cockroachdb - image: cockroachdb/cockroach:v20.1.2 - imagePullPolicy: IfNotPresent - resources: - requests: - cpu: "0.4" - memory: "0.8Gi" - limits: - # NOTE: Unless you have enabled the non-default Static CPU Management Policy - # and are using an integer number of CPUs, we don't recommend setting a CPU limit. - # See: - # https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy - # https://github.com/kubernetes/kubernetes/issues/51135 - cpu: "0.4" - memory: "0.8Gi" - ports: - - containerPort: 26257 - name: grpc - - containerPort: 8080 - name: http - livenessProbe: - httpGet: - path: "/health" - port: http - scheme: HTTPS - initialDelaySeconds: 30 - periodSeconds: 5 - readinessProbe: - httpGet: - path: "/health?ready=1" - port: http - scheme: HTTPS - initialDelaySeconds: 10 - periodSeconds: 5 - failureThreshold: 2 - volumeMounts: - - name: datadir - mountPath: /cockroach/cockroach-data - - name: certs - mountPath: /cockroach/cockroach-certs - env: - - name: COCKROACH_CHANNEL - value: kubernetes-secure - command: - - "/bin/bash" - - "-ecx" - # The use of qualified `hostname -f` is crucial: - # Other nodes aren't able to look up the unqualified hostname. - - "exec /cockroach/cockroach start --logtostderr --certs-dir /cockroach/cockroach-certs --advertise-host $(hostname -f) --http-addr 0.0.0.0 --join cockroachdb-0.cockroachdb,cockroachdb-1.cockroachdb,cockroachdb-2.cockroachdb --cache 0.2Gi --max-sql-memory 0.2Gi" - # No pre-stop hook is required, a SIGTERM plus some time is all that's - # needed for graceful shutdown of a node. - terminationGracePeriodSeconds: 60 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir - - name: certs - emptyDir: {} - podManagementPolicy: Parallel - updateStrategy: - type: RollingUpdate - volumeClaimTemplates: - - metadata: - name: datadir - spec: - accessModes: - - "ReadWriteOnce" - storageClassName: "manual" - resources: - requests: - storage: "2Gi" diff --git a/deploy/run_kubernetes_job.py b/deploy/run_kubernetes_job.py deleted file mode 100644 index 639f2dd..0000000 --- a/deploy/run_kubernetes_job.py +++ /dev/null @@ -1,160 +0,0 @@ -# TODO it will not work correctly if job can fail and restart"" - -import argparse -import os -import sys -import time - -import requests - - -class KubernetesJobException(Exception): - pass - - -# TODO logging -class KubernetesJob: - ACTIVE = 'active' - SUCCEEDED = 'succeeded' - FAILED = 'failed' - - def __init__(self, name, file_name, k8s_url, k8s_token): - path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'manifests', 'jobs', file_name)) - - with open(path, 'r') as file: - self.manifest = file.read() - self.name = name - self._url = k8s_url - self._token = k8s_token - - def clean_up(self): - headers = { - 'Authorization': f'Bearer {self._token}', - 'Content-Type': 'application/json', - } - data = { - 'kind': 'DeleteOptions', - 'apiVersion': 'batch/v1', - 'propagationPolicy': 'Background', - 'gracePeriodSeconds': 0, - } - - print('Cleaning up') - response = requests.delete( - f'{self._url}/apis/batch/v1/namespaces/default/jobs/{self.name}', - headers=headers, - json=data, - ) - if not response.status_code == 200: - print(response.text) - raise KubernetesJobException('Clean up failed') - - print('Clean up succeeded') - - def create(self): - headers = { - 'Authorization': f'Bearer {self._token}', - 'Content-Type': 'application/yaml', - } - - print('Creating job') - response = requests.post( - f'{self._url}/apis/batch/v1/namespaces/default/jobs', - data=self.manifest, - headers=headers - ) - - if response.status_code not in (200, 201, 202): - print(response.text) - raise KubernetesJobException('Creating job failed') - - print('Job created') - - def get_status(self): - headers = {'Authorization': f'Bearer {self._token}'} - - print('Getting status') - response = requests.get(f'{self._url}/apis/batch/v1/namespaces/default/jobs/{self.name}', headers=headers) - - if response.status_code != 200: - print(response.text) - raise KubernetesJobException('Check job status failed') - - response = response.json() - if response['status'].get('active') is not None: - return self.ACTIVE - - if response['status'].get('failed') is not None: - return self.FAILED - - return self.SUCCEEDED - - def get_logs(self): - headers = {'Authorization': f'Bearer {self._token}'} - - print('Getting logs') - response = requests.get( - f'{self._url}/api/v1/namespaces/default/pods?labelSelector=job-name%3D{self.name}', - headers=headers, - ) - if response.status_code != 200: - print(response.text) - raise KubernetesJobException('Get logs failed. Could not get pods list') - - pod = response.json()['items'][0] - pod_name = pod['metadata']['name'] - - response = requests.get(f'{self._url}/api/v1/namespaces/default/pods/{pod_name}/log', headers=headers) - - if response.status_code != 200: - print(response.text) - raise KubernetesJobException('Get logs failed. Could not get pod`s logs') - - return response.text - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('-n', '--name', type=str) - parser.add_argument('-f', '--file-name', type=str) - parser.add_argument('-l', '--time-limit', type=int) - parser.add_argument('-s', '--sleep-time', type=int) - args = parser.parse_args() - - job = KubernetesJob( - name=args.name, - file_name=args.file_name, - k8s_url=os.getenv('K8S_URL'), - k8s_token=os.getenv('K8S_TOKEN'), - ) - - try: - job.create() - - waiting_for = 0 - while True: - time.sleep(args.sleep_time) - waiting_for += args.sleep_time - - status = job.get_status() - if status != job.ACTIVE or waiting_for >= args.time_limit: - break - - print(job.get_logs()) - print(f'Job status: {status}') - job.clean_up() - - if status != job.SUCCEEDED: - sys.exit(-1) - - except KubernetesJobException as e: - print(e) - job.clean_up() - sys.exit(-1) - except Exception as e: - print(e) - sys.exit(-1) - - -if __name__ == '__main__': - main() diff --git a/gitrello/gitrello/settings.py b/gitrello/gitrello/settings.py index 7112dfc..285a699 100644 --- a/gitrello/gitrello/settings.py +++ b/gitrello/gitrello/settings.py @@ -2,7 +2,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') +SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') or 'DUMMY_SECRET_KEY' DEBUG = False diff --git a/gitrello/gitrello/settings_local.py b/gitrello/gitrello/settings_local.py index 538c7e8..6f0a7e3 100644 --- a/gitrello/gitrello/settings_local.py +++ b/gitrello/gitrello/settings_local.py @@ -7,8 +7,6 @@ from gitrello.settings import * -SECRET_KEY = 'aDFgbU43GTgf@34cxbJhg7gsgd^hdgH%' - DEBUG = True # To disable IPython debug messages diff --git a/gitrello/gitrello/settings_prod.py b/gitrello/gitrello/settings_prod.py index d9aa3d3..48344d6 100644 --- a/gitrello/gitrello/settings_prod.py +++ b/gitrello/gitrello/settings_prod.py @@ -28,8 +28,11 @@ GS_BUCKET_NAME = os.getenv('GS_BUCKET_NAME') DEFAULT_FILE_STORAGE = 'gitrello.gcloud_storages.GoogleCloudMediaStorage' STATICFILES_STORAGE = 'gitrello.gcloud_storages.GoogleCloudStaticFilesStorage' -GS_CREDENTIALS = service_account.Credentials.from_service_account_info( - info=ast.literal_eval(os.getenv('GS_CREDENTIALS')), -) +try: + GS_CREDENTIALS = service_account.Credentials.from_service_account_info( + info=ast.literal_eval(os.getenv('GS_CREDENTIALS')), + ) +except Exception: + GS_CREDENTIALS = service_account.Credentials.from_service_account_file(os.getenv('GS_CREDENTIALS')) GS_PROJECT_ID = os.getenv('GS_PROJECT_ID') GS_DEFAULT_ACL = 'publicRead' diff --git a/gitrello/gitrello/settings_test.py b/gitrello/gitrello/settings_test.py index 62da9ee..203413c 100644 --- a/gitrello/gitrello/settings_test.py +++ b/gitrello/gitrello/settings_test.py @@ -1,7 +1,5 @@ from gitrello.settings import * -SECRET_KEY = 'TEST_SECRET_KEY' - URL = 'http://127.0.0.1:8000' GITHUB_INTEGRATION_SERVICE_URL = 'http://127.0.0.1:8001' diff --git a/deploy/manifests/persistent_volumes/cockroachdb-pv-0.yaml b/manifests/cockroachdb/cockroachdb-pv-0.yaml similarity index 87% rename from deploy/manifests/persistent_volumes/cockroachdb-pv-0.yaml rename to manifests/cockroachdb/cockroachdb-pv-0.yaml index 9531245..5be587b 100644 --- a/deploy/manifests/persistent_volumes/cockroachdb-pv-0.yaml +++ b/manifests/cockroachdb/cockroachdb-pv-0.yaml @@ -5,7 +5,7 @@ metadata: labels: app: cockroachdb spec: - storageClassName: manual + storageClassName: cockroachdb capacity: storage: 2Gi accessModes: diff --git a/deploy/manifests/persistent_volumes/cockroachdb-pv-1.yaml b/manifests/cockroachdb/cockroachdb-pv-1.yaml similarity index 87% rename from deploy/manifests/persistent_volumes/cockroachdb-pv-1.yaml rename to manifests/cockroachdb/cockroachdb-pv-1.yaml index d8f04d1..c87c8b8 100644 --- a/deploy/manifests/persistent_volumes/cockroachdb-pv-1.yaml +++ b/manifests/cockroachdb/cockroachdb-pv-1.yaml @@ -5,7 +5,7 @@ metadata: labels: app: cockroachdb spec: - storageClassName: manual + storageClassName: cockroachdb capacity: storage: 2Gi accessModes: diff --git a/deploy/manifests/persistent_volumes/cockroachdb-pv-2.yaml b/manifests/cockroachdb/cockroachdb-pv-2.yaml similarity index 87% rename from deploy/manifests/persistent_volumes/cockroachdb-pv-2.yaml rename to manifests/cockroachdb/cockroachdb-pv-2.yaml index 4f2ef15..4aa5405 100644 --- a/deploy/manifests/persistent_volumes/cockroachdb-pv-2.yaml +++ b/manifests/cockroachdb/cockroachdb-pv-2.yaml @@ -5,7 +5,7 @@ metadata: labels: app: cockroachdb spec: - storageClassName: manual + storageClassName: cockroachdb capacity: storage: 2Gi accessModes: diff --git a/manifests/cockroachdb/values.yaml b/manifests/cockroachdb/values.yaml new file mode 100644 index 0000000..99e18f0 --- /dev/null +++ b/manifests/cockroachdb/values.yaml @@ -0,0 +1,22 @@ +statefulset: + resources: + limits: + cpu: "0.4" + memory: "800Mi" + requests: + cpu: "0.4" + memory: "800Mi" +storage: + persistentVolume: + storageClass: "cockroachdb" + size: 2Gi +service: + public: + type: LoadBalancer + annotations: + metallb.universe.tf/allow-shared-ip: gitrello +conf: + cache: "200Mi" + max-sql-memory: "200Mi" +tls: + enabled: true diff --git a/manifests/gitrello/.helmignore b/manifests/gitrello/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/manifests/gitrello/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/manifests/gitrello/Chart.yaml b/manifests/gitrello/Chart.yaml new file mode 100644 index 0000000..c252128 --- /dev/null +++ b/manifests/gitrello/Chart.yaml @@ -0,0 +1,8 @@ +apiVersion: v2 +name: gitrello +description: Trello clone with GitHub integration + +type: application + +version: 0.1.0 +appVersion: 0.18 diff --git a/manifests/gitrello/charts/.gitkeep b/manifests/gitrello/charts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/manifests/gitrello/templates/NOTES.txt b/manifests/gitrello/templates/NOTES.txt new file mode 100644 index 0000000..1025a85 --- /dev/null +++ b/manifests/gitrello/templates/NOTES.txt @@ -0,0 +1,2 @@ +1. Thank you for using GITrello +2. # TODO diff --git a/manifests/gitrello/templates/_helpers.tpl b/manifests/gitrello/templates/_helpers.tpl new file mode 100644 index 0000000..e7d090d --- /dev/null +++ b/manifests/gitrello/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "gitrello.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gitrello.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gitrello.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "gitrello.labels" -}} +helm.sh/chart: {{ include "gitrello.chart" . }} +{{ include "gitrello.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "gitrello.selectorLabels" -}} +app.kubernetes.io/name: {{ include "gitrello.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "gitrello.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "gitrello.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/manifests/gitrello/templates/deployment.yaml b/manifests/gitrello/templates/deployment.yaml new file mode 100644 index 0000000..cde9b48 --- /dev/null +++ b/manifests/gitrello/templates/deployment.yaml @@ -0,0 +1,141 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gitrello.fullname" . }} + labels: + {{- include "gitrello.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.deployment.replicaCount }} + selector: + matchLabels: + {{- include "gitrello.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.deployment.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gitrello.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.deployment.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gitrello.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.deployment.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "fnsdev/gitrello:{{ .Values.deployment.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.deployment.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + httpHeaders: + - name: Host + value: {{ .Values.host | quote }} + readinessProbe: + httpGet: + path: / + port: http + httpHeaders: + - name: Host + value: {{ .Values.host | quote }} + resources: + {{- toYaml .Values.deployment.resources | nindent 12 }} + env: + - name: DJANGO_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_secret_key + - name: DJANGO_DB_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_db_name + - name: DJANGO_DB_USER + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_db_user + - name: DJANGO_DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_db_password + - name: DJANGO_DB_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_db_host + - name: DJANGO_DB_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: django_db_port + - name: EMAIL_HOST_USER + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: email_host_user + - name: EMAIL_HOST_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: email_host_password + - name: GS_BUCKET_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: gs_bucket_name + - name: GS_CREDENTIALS + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: gs_credentials + - name: GS_PROJECT_ID + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: gs_project_id + - name: URL + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: url + - name: GITHUB_INTEGRATION_SERVICE_URL + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: github_integration_service_url + - name: GITHUB_CLIENT_ID + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: github_client_id + - name: GITHUB_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.secret.name }} + key: github_client_secret + {{- with .Values.deployment.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.deployment.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.deployment.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/manifests/gitrello/templates/ingress.yaml b/manifests/gitrello/templates/ingress.yaml new file mode 100644 index 0000000..f9180d9 --- /dev/null +++ b/manifests/gitrello/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "gitrello.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "gitrello.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .type }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- end }} + {{- end}} +{{- end }} diff --git a/manifests/gitrello/templates/secret.yaml b/manifests/gitrello/templates/secret.yaml new file mode 100644 index 0000000..5c411ea --- /dev/null +++ b/manifests/gitrello/templates/secret.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.secret.name }} +type: Opaque +stringData: + django_secret_key: {{ .Values.secret.django_secret_key | quote }} + django_db_name: {{ .Values.secret.django_db_name | quote }} + django_db_user: {{ .Values.secret.django_db_user | quote }} + django_db_password: {{ .Values.secret.django_db_password | quote }} + django_db_host: {{ .Values.secret.django_db_host | quote }} + django_db_port: {{ .Values.secret.django_db_port | quote }} + email_host_user: {{ .Values.secret.email_host_user | quote }} + email_host_password: {{ .Values.secret.email_host_password | quote }} + gs_bucket_name: {{ .Values.secret.gs_bucket_name | quote }} + gs_project_id: {{ .Values.secret.gs_project_id | quote }} + gs_credentials: {{ .Values.secret.gs_credentials | quote }} + url: {{ .Values.secret.url | quote }} + github_integration_service_url: {{ .Values.secret.github_integration_service_url | quote }} + github_client_id: {{ .Values.secret.github_client_id | quote }} + github_client_secret: {{ .Values.secret.github_client_secret | quote }} diff --git a/manifests/gitrello/templates/service.yaml b/manifests/gitrello/templates/service.yaml new file mode 100644 index 0000000..c9a646c --- /dev/null +++ b/manifests/gitrello/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "gitrello.fullname" . }} +{{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} + labels: + {{- include "gitrello.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "gitrello.selectorLabels" . | nindent 4 }} diff --git a/manifests/gitrello/templates/serviceaccount.yaml b/manifests/gitrello/templates/serviceaccount.yaml new file mode 100644 index 0000000..7c9cb8b --- /dev/null +++ b/manifests/gitrello/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "gitrello.serviceAccountName" . }} + labels: + {{- include "gitrello.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/manifests/gitrello/templates/tests/test-connection.yaml b/manifests/gitrello/templates/tests/test-connection.yaml new file mode 100644 index 0000000..bbfe0fa --- /dev/null +++ b/manifests/gitrello/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "gitrello.fullname" . }}-gitrello-connection" + labels: + {{- include "gitrello.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "gitrello.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/manifests/gitrello/values.yaml b/manifests/gitrello/values.yaml new file mode 100644 index 0000000..e265931 --- /dev/null +++ b/manifests/gitrello/values.yaml @@ -0,0 +1,107 @@ +# Default values for gitrello. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Required for liveness & readiness probes +host: example.com + +labels: + app: gitrello + +selectorLabels: + app: gitrello + +serviceAccount: + # Specifies whether a service account should be created + create: false + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "default" + +secret: + # Secret's name + name: environment + + # Required secrets + django_secret_key: "example" + django_db_name: "example" + django_db_user: "example" + django_db_password: "example" + django_db_host: "cockroachdb-public" + django_db_port: "26257" + email_host_user: "example@gmail.com" + email_host_password: "example" + gs_bucket_name: "example" + gs_project_id: "1111111" + gs_credentials: "credentials_json" + url: "https://example.com" + github_integration_service_url: "github-integration-service" + github_client_id: "example" + github_client_secret: "example" + +deployment: + replicaCount: 1 + + image: + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: 0.16dev + + imagePullSecrets: [] + + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: {} + # capabilities: + # drop:environment + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + resources: { } + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: { } + tolerations: [ ] + affinity: { } + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + # paths: + # - host: gitrello.me + # paths: + # - path: / + # type: Prefix + # - host: www.gitrello.me + # paths: + # - path: / + # type: Prefix + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local diff --git a/manifests/ingress-nginx/values.yaml b/manifests/ingress-nginx/values.yaml new file mode 100644 index 0000000..f1cbe53 --- /dev/null +++ b/manifests/ingress-nginx/values.yaml @@ -0,0 +1,4 @@ +controller: + service: + annotations: + metallb.universe.tf/allow-shared-ip: gitrello diff --git a/manifests/jenkins/jenkins-ingress.yaml b/manifests/jenkins/jenkins-ingress.yaml new file mode 100644 index 0000000..fb4ab30 --- /dev/null +++ b/manifests/jenkins/jenkins-ingress.yaml @@ -0,0 +1,33 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: jenkins-ingress + annotations: + kubernetes.io/ingress.class: "nginx" +spec: + tls: + - hosts: + - gitrello.me + - www.gitrello.me + secretName: tls + rules: + - host: gitrello.me + http: + paths: + - path: /jenkins + pathType: Prefix + backend: + service: + name: jenkins + port: + number: 8081 + - host: www.gitrello.me + http: + paths: + - path: /jenkins + pathType: Prefix + backend: + service: + name: jenkins + port: + number: 8081 diff --git a/manifests/jenkins/jenkins-pv.yaml b/manifests/jenkins/jenkins-pv.yaml new file mode 100644 index 0000000..32a5880 --- /dev/null +++ b/manifests/jenkins/jenkins-pv.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: jenkins-pv +spec: + storageClassName: jenkins + capacity: + storage: 4Gi + accessModes: + - ReadWriteOnce + hostPath: + path: "/jenkins/data" diff --git a/manifests/jenkins/values.yaml b/manifests/jenkins/values.yaml new file mode 100644 index 0000000..caa066b --- /dev/null +++ b/manifests/jenkins/values.yaml @@ -0,0 +1,32 @@ +master: + serviceType: ClusterIP + servicePort: 8081 + installPlugins: + - kubernetes:1.27.1 + - workflow-aggregator:2.6 + - workflow-job:2.40 + - git:4.4.1 + - github:1.31.0 + - configuration-as-code:1.41 + - matrix-auth:2.6.2 + - embeddable-build-status:2.0.3 + jenkinsUrl: https://gitrello.me/jenkins + jenkinsAdminEmail: fnsdevelopment@gmail.com + JCasC: + securityRealm: |- + local: + allowsSignup: false + # https://github.com/helm/charts/issues/15453 + customInitContainers: + - name: "volume-mount-permission" + image: "busybox" + command: ["/bin/chown", "-R", "1000", "/var/jenkins_home"] + volumeMounts: + - name: "jenkins-home" + mountPath: "/var/jenkins_home" + securityContext: + runAsUser: 0 + jenkinsUriPrefix: "/jenkins" +persistence: + storageClass: jenkins + size: "4Gi" diff --git a/manifests/metallb/metallb-config-example.yaml b/manifests/metallb/metallb-config-example.yaml new file mode 100644 index 0000000..a03268e --- /dev/null +++ b/manifests/metallb/metallb-config-example.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: metallb +data: + config: | + address-pools: + - name: default + protocol: layer2 + addresses: + - 0.0.0.0/32 diff --git a/poetry.lock b/poetry.lock index 889dad4..a29684b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -67,7 +67,7 @@ description = "A high-level Python Web framework that encourages rapid developme name = "django" optional = false python-versions = ">=3.6" -version = "3.1" +version = "3.1.1" [package.dependencies] asgiref = ">=3.2.10,<3.3.0" @@ -102,11 +102,11 @@ category = "main" description = "Support for many storage backends in Django" name = "django-storages" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.9.1" +python-versions = ">=3.5" +version = "1.10" [package.dependencies] -Django = ">=1.11" +Django = ">=2.2" [package.dependencies.google-cloud-storage] optional = true @@ -160,10 +160,10 @@ description = "Google API client core library" name = "google-api-core" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.22.1" +version = "1.22.2" [package.dependencies] -google-auth = ">=1.19.1,<2.0dev" +google-auth = ">=1.21.1,<2.0dev" googleapis-common-protos = ">=1.6.0,<2.0dev" protobuf = ">=3.12.0" pytz = "*" @@ -182,7 +182,7 @@ description = "Google Authentication Library" name = "google-auth" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.20.1" +version = "1.21.1" [package.dependencies] cachetools = ">=2.0.0,<5.0" @@ -214,12 +214,12 @@ description = "Google Cloud Storage API client library" name = "google-cloud-storage" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.30.0" +version = "1.31.0" [package.dependencies] google-auth = ">=1.11.0,<2.0dev" -google-cloud-core = ">=1.2.0,<2.0dev" -google-resumable-media = ">=0.6.0,<2.0dev" +google-cloud-core = ">=1.4.1,<2.0dev" +google-resumable-media = ">=1.0.0,<2.0dev" [[package]] category = "main" @@ -614,8 +614,8 @@ python-versions = ">=3.6.1" version = "8.1" [metadata] -content-hash = "3ea42246ab70bab83dcace60b236dbfb5b4f8617977caf53bed5c097f2741f32" -python-versions = "3.8.3" +content-hash = "0b464071969ac68e458ffc12f368bd8ae4b6f696d5ac8003ba4433e52c8ad589" +python-versions = "3.8.5" [metadata.files] aniso8601 = [ @@ -673,8 +673,8 @@ click = [ {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] django = [ - {file = "Django-3.1-py3-none-any.whl", hash = "sha256:1a63f5bb6ff4d7c42f62a519edc2adbb37f9b78068a5a862beff858b68e3dc8b"}, - {file = "Django-3.1.tar.gz", hash = "sha256:2d390268a13c655c97e0e2ede9d117007996db692c1bb93eabebd4fb7ea7012b"}, + {file = "Django-3.1.1-py3-none-any.whl", hash = "sha256:b5fbb818e751f660fa2d576d9f40c34a4c615c8b48dd383f5216e609f383371f"}, + {file = "Django-3.1.1.tar.gz", hash = "sha256:59c8125ca873ed3bdae9c12b146fbbd6ed8d0f743e4cf5f5817af50c51f1fc2f"}, ] django-cockroachdb = [ {file = "django-cockroachdb-3.1.tar.gz", hash = "sha256:3acb36906ac0b7725f3847e21ca6dc9ff83975b5672156edea0b74ce281baf9d"}, @@ -685,8 +685,8 @@ django-filter = [ {file = "django_filter-2.3.0-py3-none-any.whl", hash = "sha256:616848eab6fc50193a1b3730140c49b60c57a3eda1f7fc57fa8505ac156c6c75"}, ] django-storages = [ - {file = "django-storages-1.9.1.tar.gz", hash = "sha256:a59e9923cbce7068792f75344ed7727021ee4ac20f227cf17297d0d03d141e91"}, - {file = "django_storages-1.9.1-py2.py3-none-any.whl", hash = "sha256:3103991c2ee8cef8a2ff096709973ffe7106183d211a79f22cf855f33533d924"}, + {file = "django-storages-1.10.tar.gz", hash = "sha256:36ed8dab33d761954498189592ce005920095fcbc02dab4184eb51393c370991"}, + {file = "django_storages-1.10-py3-none-any.whl", hash = "sha256:1e37da57678e6cf1e9914f84099a305323e4e1f261afe54fdb703cae7aa6fbc3"}, ] djangorestframework = [ {file = "djangorestframework-3.11.1-py3-none-any.whl", hash = "sha256:8b1ac62c581dbc5799b03e535854b92fc4053ecfe74bad3f9c05782063d4196b"}, @@ -701,20 +701,20 @@ faker = [ {file = "Faker-4.1.2.tar.gz", hash = "sha256:ff188c416864e3f7d8becd8f9ee683a4b4101a2a2d2bcdcb3e84bb1bdd06eaae"}, ] google-api-core = [ - {file = "google-api-core-1.22.1.tar.gz", hash = "sha256:35cba563034d668ae90ffe1f03193a84e745b38f09592f60258358b5e5ee6238"}, - {file = "google_api_core-1.22.1-py2.py3-none-any.whl", hash = "sha256:431839101b7edc7b0e6cccca0441cb9015f728fc5f098e146e123bf523e8cf71"}, + {file = "google-api-core-1.22.2.tar.gz", hash = "sha256:779107f17e0fef8169c5239d56a8fbff03f9f72a3893c0c9e5842ec29dfedd54"}, + {file = "google_api_core-1.22.2-py2.py3-none-any.whl", hash = "sha256:67e33a852dcca7cb7eff49abc35c8cc2c0bb8ab11397dc8306d911505cae2990"}, ] google-auth = [ - {file = "google-auth-1.20.1.tar.gz", hash = "sha256:2f34dd810090d0d4c9d5787c4ad7b4413d1fbfb941e13682c7a2298d3b6cdcc8"}, - {file = "google_auth-1.20.1-py2.py3-none-any.whl", hash = "sha256:ce1fb80b5c6d3dd038babcc43e221edeafefc72d983b3dc28b67b996f76f00b9"}, + {file = "google-auth-1.21.1.tar.gz", hash = "sha256:bcbd9f970e7144fe933908aa286d7a12c44b7deb6d78a76871f0377a29d09789"}, + {file = "google_auth-1.21.1-py2.py3-none-any.whl", hash = "sha256:f4d5093f13b1b1c0a434ab1dc851cd26a983f86a4d75c95239974e33ed406a87"}, ] google-cloud-core = [ {file = "google-cloud-core-1.4.1.tar.gz", hash = "sha256:613e56f164b6bee487dd34f606083a0130f66f42f7b10f99730afdf1630df507"}, {file = "google_cloud_core-1.4.1-py2.py3-none-any.whl", hash = "sha256:4c9e457fcfc026fdde2e492228f04417d4c717fb0f29f070122fb0ab89e34ebd"}, ] google-cloud-storage = [ - {file = "google-cloud-storage-1.30.0.tar.gz", hash = "sha256:0634addb7576d48861d9963312fc82a0436042b8f282414ed58ca76d73edee54"}, - {file = "google_cloud_storage-1.30.0-py2.py3-none-any.whl", hash = "sha256:02ac63059c798d4b8ba9057921be745707dc2d3316f5f366de91c24cc23cd77e"}, + {file = "google-cloud-storage-1.31.0.tar.gz", hash = "sha256:4f51c7700242a9d54c07117f25fec5d110ab85435b3ce60ac28cc553f8ea938b"}, + {file = "google_cloud_storage-1.31.0-py2.py3-none-any.whl", hash = "sha256:34fb8f7e8a2a633cbfb09d8dec38b3450c4029af1a328a67bca64f6226a1f4a5"}, ] google-crc32c = [ {file = "google-crc32c-1.0.0.tar.gz", hash = "sha256:9439b960b6ecd847557675d130fc3626d762bf535da595c20a6949a705fb3eae"}, diff --git a/pyproject.toml b/pyproject.toml index 0388648..d248afa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "Trello clone with GitHub integration" authors = ["Uladzislau Stasheuski "] [tool.poetry.dependencies] -python = "3.8.3" +python = "3.8.5" django = "^3.0.8" django-cockroachdb = "^3.0.1" django-filter = "^2.3.0" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5339ab0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,51 @@ +aniso8601==7.0.0 +asgiref==3.2.10 +cachetools==4.1.1 +certifi==2020.6.20 +cffi==1.14.2; python_version >= "3.5" +chardet==3.0.4 +click==7.1.2 +django==3.1.1 +django-cockroachdb==3.1 +django-filter==2.3.0 +django-storages==1.10 +djangorestframework==3.11.1 +factory-boy==2.12.0 +faker==4.1.2 +google-api-core==1.22.2 +google-auth==1.21.1 +google-cloud-core==1.4.1 +google-cloud-storage==1.31.0 +google-crc32c==1.0.0; python_version >= "3.5" +google-resumable-media==1.0.0 +googleapis-common-protos==1.52.0 +graphene==2.1.8 +graphene-django==2.13.0 +-e git+https://github.com/FNSdev/graphene-django-optimizer.git@e1a3d0412d06f6b95bb9505d5fa6f161c7013446#egg=graphene-django-optimizer +graphql-core==2.3.2 +graphql-relay==2.0.1 +h11==0.9.0 +httptools==0.1.1; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" +idna==2.10 +promise==2.3 +protobuf==3.13.0 +psycopg2==2.8.5 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycparser==2.20; python_version >= "3.5" +pyjwt==1.7.1 +python-dateutil==2.8.1 +python-dotenv==0.14.0 +pytz==2020.1 +requests==2.24.0 +rsa==4.6; python_version >= "3.5" +rx==1.6.1 +singledispatch==3.4.0.3 +six==1.15.0 +sqlparse==0.3.1 +text-unidecode==1.3 +unidecode==1.1.1 +urllib3==1.25.10 +uvicorn==0.11.8 +uvloop==0.14.0; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" +websockets==8.1