diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0029c34 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +deploy/ +htmlcov/ +.github/ +.env/ +.python-version +skaffold.yaml + + +*.pyc +*.pyo +*.pyd +__pycache__ +.git diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..5b8de5e --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,72 @@ +# GitHub Actions + +The files in this directory are used to configure the Github Actions workflows for +`geneweaver-api`. The workflows are used to automatically build and test the project +when changes are pushed to the repository. + +Any file that starts with an underscore (`_`) is a "reusable workflow". These files +are not directly used by GitHub Actions, but are instead referenced by the workflows +files that do not start with an underscore. + +There are five reusable workflows: + +- Check Coverage (`_check-coverage-action.yml`): This workflow is used to check the code + coverage of the project. +- Format Lint (`_format-lint-action.yml`): This workflow is used to check the formatting + and linting of the project. +- Run Tests (`_run-tests-action.yml`): This workflow is used to run the tests for the + project. +- Skaffold Build (`_skaffold-build-k8s.yml`): This workflow is used to build the + Docker images for the project. +- Skaffold Deploy (`_skaffold-deploy-action.yml`): This workflow is used to deploy the + Docker images to kubernetes. + +There are two _main_ workflows that are used by GitHub Actions: + +- Pull Requests (`pull_requests.yml`): This workflow is used to build and test the + project when a pull request is opened. +- Release (`release.yml`): This workflow that is run whenever the version number changes + on the `main` branch. + +There are also three quality assurance workflows that are run on any change to the main +branch: + +- Coverage (`coverage.yml`): This workflow is used to check the code coverage of the + project. +- Style (`style.yml`): This workflow is used to check the formatting and linting of the + project. +- Tests (`tests.yml`): This workflow is used to run the tests for the project. + + +## Pull Requests + +The pull request workflow is run whenever a pull request is opened. This workflow +will: + +- Check the formatting and linting of the project. +- Run the tests for the project. +- Check the code coverage of the project. +- Build the Docker images (into the `test` registry) for the project. +- Deploy the Docker images (from the `test` registry) to kubernetes (into the `dev` + environment). + +## Release + +The release workflow is run whenever the version number changes on the `main` branch. +This workflow will: + +- Check the formatting and linting of the project. +- Run the tests for the project. +- Check the code coverage of the project. +- Build the Docker images (into the `prod` registry) for the project. +- Deploy the Docker images (from the `prod` registry) to kubernetes (into the `sqa` + environment). + - It will wait for approval from SQA before running this step +- If the version number is not a pre-release version (contains a letter) it will then: + - Deploy the Docker images (from the `prod` registry) to kubernetes (into the + `stage` environment). + - It will wait for approval from SQA before running this step + - Deploy the Docker images (from the `prod` registry) to kubernetes (into the `prod` + environment). + - It will wait for approval from SQA before running this step + - It will then create a draft GitHub release \ No newline at end of file diff --git a/.github/workflows/_check-coverage-action.yml b/.github/workflows/_check-coverage-action.yml index 910936f..0990df5 100644 --- a/.github/workflows/_check-coverage-action.yml +++ b/.github/workflows/_check-coverage-action.yml @@ -27,7 +27,7 @@ on: type: string default: "no" jobs: - run-tests: + check_coverage: runs-on: ${{ inputs.runner-os }} steps: - uses: actions/checkout@v3 @@ -54,12 +54,49 @@ jobs: --cov-report=html \ --cov-fail-under=${{ inputs.required-coverage }} > coverage_report.txt - name: Upload coverage report + if: '!cancelled()' uses: actions/upload-artifact@v3 with: name: coverage-report path: coverage_report.txt - name: Upload coverage report + if: '!cancelled()' uses: actions/upload-artifact@v3 with: name: coverage-report-html - path: htmlcov \ No newline at end of file + path: htmlcov + comment-coverage-report: + needs: [ check_coverage ] + runs-on: ubuntu-latest + if: ${{always() && github.event_name == 'pull_request'}} + permissions: + pull-requests: write + steps: + - name: Download coverage report artifact + uses: actions/download-artifact@v3 + with: + name: coverage-report + - name: Read coverage report + id: read-coverage + run: | + echo "COVERAGE_REPORT<> $GITHUB_ENV + cat coverage_report.txt >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '### Test Coverage Report' + - name: Create or update comment + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + edit-mode: replace + body: | + ### Test Coverage Report + ``` + ${{ env.COVERAGE_REPORT }} + ``` \ No newline at end of file diff --git a/.github/workflows/_skaffold-build-k8s.yml b/.github/workflows/_skaffold-build-k8s.yml new file mode 100644 index 0000000..2cbb096 --- /dev/null +++ b/.github/workflows/_skaffold-build-k8s.yml @@ -0,0 +1,34 @@ +name: 'Skaffold Build' +on: + workflow_call: + inputs: + default_image_repo: + description: 'Default image repo' + required: false + type: string + default: "us-docker.pkg.dev/jax-cs-registry/docker/geneweaver" +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Skaffold + run: | + curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \ + sudo install skaffold /usr/local/bin/ + - name: Authenticate to Google Cloud + uses: 'google-github-actions/auth@v1' + with: + credentials_json: '${{ secrets.GCLOUD_REGISTRY_SA_KEY }}' + - name: Docker Login + run: gcloud auth configure-docker us-docker.pkg.dev,us-east1-docker.pkg.dev + - name: Build + run: | + skaffold build \ + --default-repo=${{ inputs.default_image_repo }} \ + --file-output=build.json + - name: Upload Build Artifact Information + uses: actions/upload-artifact@v3 + with: + name: build-artifact-json + path: build.json diff --git a/.github/workflows/_skaffold-deploy-k8s.yml b/.github/workflows/_skaffold-deploy-k8s.yml new file mode 100644 index 0000000..399ef14 --- /dev/null +++ b/.github/workflows/_skaffold-deploy-k8s.yml @@ -0,0 +1,41 @@ +name: 'Skaffold Deploy' +on: + workflow_call: + inputs: + environment: + description: 'Deployment environment/profile' + required: true + type: string +jobs: + deploy: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - uses: actions/checkout@v3 + - name: Download Build Artifact Information + uses: actions/download-artifact@v3 + with: + name: build-artifact-json + - name: Authenticate to Google Cloud + uses: 'google-github-actions/auth@v1' + with: + credentials_json: '${{ secrets.GCLOUD_CLUSTER_SA_KEY }}' + - id: setup-gcloud + name: Setup Gcloud + uses: 'google-github-actions/setup-gcloud@v1' + - id: get-gke-credentials + name: Get GKE credentials + uses: 'google-github-actions/get-gke-credentials@v1' + with: + cluster_name: ${{ vars.CLUSTER_NAME }} + location: ${{ vars.CLUSTER_REGION }} + project_id: ${{ vars.CLUSTER_PROJECT }} + - name: Install Skaffold + run: | + curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \ + sudo install skaffold /usr/local/bin/ + - name: Deploy + run: | + skaffold deploy \ + --profile ${{ inputs.environment }} \ + --build-artifacts=build.json diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 4a03441..f1f4ead 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,49 +1,13 @@ name: Coverage on: - pull_request: - branches: - - 'main' push: branches: - 'main' jobs: check-coverage: uses: ./.github/workflows/_check-coverage-action.yml + permissions: + pull-requests: write with: required-coverage: ${{ vars.REQUIRED_COVERAGE }} coverage-module: "geneweaver.api" - comment-coverage-report: - needs: [ check-coverage ] - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - permissions: - pull-requests: write - steps: - - name: Download coverage report artifact - uses: actions/download-artifact@v3 - with: - name: coverage-report - - name: Read coverage report - id: read-coverage - run: | - echo "COVERAGE_REPORT<> $GITHUB_ENV - cat coverage_report.txt >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - name: Find Comment - uses: peter-evans/find-comment@v2 - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: '### Test Coverage Report' - - name: Create or update comment - uses: peter-evans/create-or-update-comment@v3 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - edit-mode: replace - body: | - ### Test Coverage Report - ``` - ${{ env.COVERAGE_REPORT }} - ``` \ No newline at end of file diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml new file mode 100644 index 0000000..cf38837 --- /dev/null +++ b/.github/workflows/pull_requests.yml @@ -0,0 +1,46 @@ +name: Pull Request Test, Build and Deploy +on: + pull_request: + branches: + - 'main' +jobs: + format-lint: + name: "Format and Lint" + uses: ./.github/workflows/_format-lint-action.yml + with: + python-version: '3.9' + check-coverage: + name: "Check Coverage" + needs: [format-lint] + uses: ./.github/workflows/_check-coverage-action.yml + permissions: + pull-requests: write + with: + required-coverage: ${{ vars.REQUIRED_COVERAGE }} + coverage-module: "geneweaver.api" + test: + name: "Run Tests" + needs: [format-lint] + strategy: + matrix: + os: [ubuntu-latest] + python-version: ['3.10', '3.11'] + uses: ./.github/workflows/_run-tests-action.yml + with: + runner-os: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} + required-coverage: ${{ vars.REQUIRED_COVERAGE }} + build: + name: "Build: Dev" + needs: [test, check-coverage] + uses: ./.github/workflows/_skaffold-build-k8s.yml + secrets: inherit + with: + default_image_repo: "us-east1-docker.pkg.dev/jax-cs-registry/docker-test/geneweaver" + deploy: + name: "Deploy: Dev" + needs: [build] + uses: ./.github/workflows/_skaffold-deploy-k8s.yml + secrets: inherit + with: + environment: "jax-cluster-dev-10--dev" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d77e35a..b955776 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,33 +12,44 @@ permissions: jobs: format-lint: + name: "Format and Lint" uses: ./.github/workflows/_format-lint-action.yml with: python-version: '3.9' + check-coverage: + name: "Check Coverage" + needs: [format-lint] + uses: ./.github/workflows/_check-coverage-action.yml + permissions: + pull-requests: write + with: + required-coverage: ${{ vars.REQUIRED_COVERAGE }} + coverage-module: "geneweaver.api" test: - needs: format-lint + name: "Run Tests" + needs: [check-coverage, format-lint] + strategy: + matrix: + os: [ubuntu-latest] + python-version: ['3.10', '3.11'] uses: ./.github/workflows/_run-tests-action.yml with: - python-version: '3.9' - runner-os: 'ubuntu-latest' - upload-coverage: false + runner-os: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} required-coverage: ${{ vars.REQUIRED_COVERAGE }} - release: + version: needs: test runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@v3 - - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.9'z - + python-version: '3.9' - name: Install dependencies run: | pip install toml - - name: Check for version change id: version_check run: | @@ -55,7 +66,6 @@ jobs: echo "New version detected" echo "should_release=false" >> $GITHUB_OUTPUT fi - - name: Determine Release Type id: release_type run: | @@ -67,10 +77,54 @@ jobs: echo "Full release version detected" echo "prerelease=false" >> $GITHUB_OUTPUT fi - - - name: Install Poetry - if: ${{ steps.version_check.outputs.should_release }} == 'true' - run: | - curl -sSL https://install.python-poetry.org | python3 - - - # TODO: Add deploy to kubernetes step \ No newline at end of file + build: + name: "Build" + needs: [ test, check-coverage, format-lint ] + if: ${{ steps.version_check.outputs.should_release }} == 'true' + uses: ./.github/workflows/_skaffold-build-k8s.yml + secrets: inherit + deploy_sqa: + name: "Deploy: SQA" + needs: [build, version] + if: ${{ steps.version_check.outputs.should_release }} == 'true' + uses: ./.github/workflows/_skaffold-deploy-k8s.yml + secrets: inherit + with: + environment: "jax-cluster-dev-10--sqa" + deploy_stage: + name: "Deploy: Stage" + needs: [ build, version, deploy_sqa] + if: ${{ steps.version_check.outputs.should_release == 'true' && steps.version_check.outputs.prerelease == 'false'}} + uses: ./.github/workflows/_skaffold-deploy-k8s.yml + secrets: inherit + with: + environment: "jax-cluster-prod-10--stage" + deploy_prod: + name: "Deploy: Prod" + needs: [ build, version, deploy_sqa] + if: ${{ steps.version_check.outputs.should_release == 'true' && steps.version_check.outputs.prerelease == 'false'}} + uses: ./.github/workflows/_skaffold-deploy-k8s.yml + secrets: inherit + with: + environment: "jax-cluster-prod-10--prod" + release: + name: "Create Github Release Draft" + runs-on: ubuntu-latest + needs: [ deploy_prod ] + if: ${{ steps.version_check.outputs.should_release == 'true' && steps.version_check.outputs.prerelease == 'false'}} + steps: + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.version_check.outputs.version }} + name: Release v${{ steps.version_check.outputs.version }} + draft: true + prerelease: ${{ steps.release_type.outputs.prerelease }} + body: | + Release v${{ steps.version_check.outputs.version }} + files: | + dist/* + LICENSE + README.md \ No newline at end of file diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index bb5988f..a590a19 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -1,8 +1,5 @@ name: Style on: - pull_request: - branches: - - 'main' push: branches: - 'main' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e702bf3..9bde38e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,8 +1,5 @@ name: Tests on: - pull_request: - branches: - - 'main' push: branches: - 'main' @@ -10,7 +7,7 @@ jobs: test: strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest] python-version: ['3.9', '3.10', '3.11'] uses: ./.github/workflows/_run-tests-action.yml with: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f34a069 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.9 + +ENV PYTHONUNBUFFERED 1 +ENV POETRY_HOME=/opt/poetry, POETRY_VIRTUALENVS_CREATE=false, POETRY_VERSION=1.3.0 + +# Install poetry +RUN python3 -m pip install --upgrade pip && \ + curl -sSL https://install.python-poetry.org | python3 - + +ENV PATH="${POETRY_HOME}/bin:${PATH}" + +WORKDIR /app + +COPY pyproject.toml poetry.lock /app/ + +RUN poetry install --without dev --sync --no-root + +COPY /src /app/src + +RUN poetry install --only-root + +CMD ["poetry", "run", "uvicorn", "geneweaver.api.main:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers"] diff --git a/README.MD b/README.MD index 4b3f74c..3403265 100644 --- a/README.MD +++ b/README.MD @@ -24,3 +24,36 @@ virtualenv activated, or just run `poetry run uvicorn geneweaver.api.main:app -- This will host the application on `http://127.0.0.1:8000/` which means the swagger docs page is available at `http://127.0.0.1:8000/docs`. + + +### Continuous Integration & Deployment +When a PR is crated in GitHub, it will automatically trigger a workflow that will run +the tests and build the docker images, and then deploy to `dev`. Please be aware of this +when creating tests in order to avoid conflicts with other PRs. + +When a PR is merged into `main`, it will automatically trigger a workflow that will run +the tests and build the docker images, and then deploy to `sqa`. + +In order for any deployment to run, other than to `dev`, two things must be true: + - the deployment must be approved by SQA. + - the version number in `pyproject.toml` must be incremented. + +In order for the `stage` and `prod` deployments to run, the version number in +`pyproject.toml` must not contain a letter. This indicates that it is a release version. + +#### Version Numbers +When creating a bugfix or feature addition PR, it is required that your version number +contains a letter. This indicates to SQA that the code needs to be tests before it is +released. + +For example, if the current version is `0.1.0`, then your PR should increment +the version number to `0.1.1a0` when creating a bugfix PR. The SQA team will then +test your code in the `sqa` environment. + +If the code passes SQA testing, they will inform you that `0.1.1a0` has passed QA, at +which point you should create a PR with a single line change that increments the version +number to `0.1.1`. + +If `0.1.1a0` fails QA, then you will need to create a fix, and increment the version +number to `0.1.1a1`. This process will continue until the code passes QA, at which +point you will increment the version number to `0.1.1` and create a PR to merge into diff --git a/deploy/k8s/base/configmap.yaml b/deploy/k8s/base/configmap.yaml new file mode 100644 index 0000000..bef4100 --- /dev/null +++ b/deploy/k8s/base/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: geneweaver-config +data: + AUTH_CLIENT_ID: "T7bj6wlmtVcAN2O6kzDRwPVFyIj4UQNs" \ No newline at end of file diff --git a/deploy/k8s/base/deployment.yaml b/deploy/k8s/base/deployment.yaml new file mode 100644 index 0000000..f263ee8 --- /dev/null +++ b/deploy/k8s/base/deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: geneweaver-api + labels: + app: geneweaver-api +spec: + replicas: 1 + selector: + matchLabels: + app: geneweaver-api + template: + metadata: + labels: + app: geneweaver-api + spec: + serviceAccountName: workload-identity-geneweaver + containers: + - name: geneweaver-api + image: geneweaver-api + imagePullPolicy: Always + envFrom: + - configMapRef: + name: geneweaver-config + - secretRef: + name: geneweaver-db + ports: + - containerPort: 8000 \ No newline at end of file diff --git a/deploy/k8s/base/ingress.yaml b/deploy/k8s/base/ingress.yaml new file mode 100644 index 0000000..14a2b28 --- /dev/null +++ b/deploy/k8s/base/ingress.yaml @@ -0,0 +1,13 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: divdb-api-ingress + annotations: + # NOTE: When deploying a new instance, make sure to use the staging issuer first + # so that you don't hit the rate limit for the production issuer. + cert-manager.io/cluster-issuer: "letsencrypt-staging" + # cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/auth-url: "https://auth.jax-cluster-dev-10.jax.org/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://auth.jax-cluster-dev-10.jax.org/oauth2/start?rd=https://$http_host$escaped_request_uri" +spec: + ingressClassName: nginx diff --git a/deploy/k8s/base/kustomization.yaml b/deploy/k8s/base/kustomization.yaml new file mode 100644 index 0000000..4a836d7 --- /dev/null +++ b/deploy/k8s/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - configmap.yaml + - deployment.yaml + - service.yaml + # TODO: Uncomment the following line to enable ingress + # - ingress.yaml \ No newline at end of file diff --git a/deploy/k8s/base/service.yaml b/deploy/k8s/base/service.yaml new file mode 100644 index 0000000..23c7a0d --- /dev/null +++ b/deploy/k8s/base/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: geneweaver-api + labels: + app: geneweaver-api +spec: + type: ClusterIP + selector: + app: geneweaver-api + ports: + - protocol: TCP + name: direct + port: 80 + targetPort: 8000 diff --git a/deploy/k8s/overlays/jax-cluster-dev-10--dev/kustomization.yaml b/deploy/k8s/overlays/jax-cluster-dev-10--dev/kustomization.yaml new file mode 100644 index 0000000..1ef6ac7 --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-dev-10--dev/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: dev + +bases: +- ../../base + +#patchesStrategicMerge: +# - configmap.yaml +# - ingress.yaml diff --git a/deploy/k8s/overlays/jax-cluster-dev-10--sqa/kustomization.yaml b/deploy/k8s/overlays/jax-cluster-dev-10--sqa/kustomization.yaml new file mode 100644 index 0000000..dd9db0f --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-dev-10--sqa/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: sqa + +bases: +- ../../base + +#patchesStrategicMerge: +# - configmap.yaml +# - ingress.yaml diff --git a/deploy/k8s/overlays/jax-cluster-prod-10--prod/configmap.yaml b/deploy/k8s/overlays/jax-cluster-prod-10--prod/configmap.yaml new file mode 100644 index 0000000..0b9539a --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-prod-10--prod/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: geneweaver-config +data: + AUTH_CLIENT_ID: "oVm9omUtLBpVyL7YfJA8gp3hHaHwyVt8" \ No newline at end of file diff --git a/deploy/k8s/overlays/jax-cluster-prod-10--prod/kustomization.yaml b/deploy/k8s/overlays/jax-cluster-prod-10--prod/kustomization.yaml new file mode 100644 index 0000000..623871b --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-prod-10--prod/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: prod + +bases: +- ../../base + +#patchesStrategicMerge: +# - configmap.yaml +# - ingress.yaml diff --git a/deploy/k8s/overlays/jax-cluster-prod-10--stage/configmap.yaml b/deploy/k8s/overlays/jax-cluster-prod-10--stage/configmap.yaml new file mode 100644 index 0000000..0b9539a --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-prod-10--stage/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: geneweaver-config +data: + AUTH_CLIENT_ID: "oVm9omUtLBpVyL7YfJA8gp3hHaHwyVt8" \ No newline at end of file diff --git a/deploy/k8s/overlays/jax-cluster-prod-10--stage/kustomization.yaml b/deploy/k8s/overlays/jax-cluster-prod-10--stage/kustomization.yaml new file mode 100644 index 0000000..783b14d --- /dev/null +++ b/deploy/k8s/overlays/jax-cluster-prod-10--stage/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: stage + +bases: +- ../../base + +#patchesStrategicMerge: +# - configmap.yaml +# - ingress.yaml diff --git a/skaffold.yaml b/skaffold.yaml new file mode 100644 index 0000000..4d8b65d --- /dev/null +++ b/skaffold.yaml @@ -0,0 +1,40 @@ +apiVersion: skaffold/v2beta29 +kind: Config +metadata: + name: geneweaver-api +build: + tagPolicy: + gitCommit: + variant: AbbrevCommitSha + artifacts: + - image: geneweaver-api + context: . + docker: + dockerfile: Dockerfile + local: + useBuildkit: true +test: + - image: geneweaver-api + structureTests: + - deploy/tests/* +profiles: + - name: jax-cluster-dev-10--dev + deploy: + kustomize: + paths: + - deploy/k8s/overlays/jax-cluster-dev-10--dev + - name: jax-cluster-dev-10--sqa + deploy: + kustomize: + paths: + - deploy/k8s/overlays/jax-cluster-dev-10--sqa + - name: jax-cluster-prod-10--stage + deploy: + kustomize: + paths: + - deploy/k8s/overlays/jax-cluster-prod-10--stage + - name: jax-cluster-prod-10--prod + deploy: + kustomize: + paths: + - deploy/k8s/overlays/jax-cluster-prod-10--prod diff --git a/src/geneweaver/api/core/config.py b/src/geneweaver/api/core/config.py index 1968b69..9bfbeff 100644 --- a/src/geneweaver/api/core/config.py +++ b/src/geneweaver/api/core/config.py @@ -1,7 +1,4 @@ """A namespace for the initialized Geneweaver API configuration.""" from geneweaver.api.core.config_class import GeneweaverAPIConfig -from geneweaver.db.core.settings_class import Settings as DBSettings settings = GeneweaverAPIConfig() - -db_settings = DBSettings() diff --git a/src/geneweaver/api/core/config_class.py b/src/geneweaver/api/core/config_class.py index e45de7c..5791d4a 100644 --- a/src/geneweaver/api/core/config_class.py +++ b/src/geneweaver/api/core/config_class.py @@ -1,33 +1,37 @@ """Namespace for the config class for the Geneweaver API.""" -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional -from pydantic import BaseSettings, PostgresDsn, validator +from geneweaver.db.core.settings_class import Settings as DBSettings +from pydantic import BaseSettings, validator class GeneweaverAPIConfig(BaseSettings): """Config class for the Geneweaver API.""" - API_PREFIX: str = "" + LOG_LEVEL: str = "INFO" - POSTGRES_SERVER: str - POSTGRES_USER: str - POSTGRES_PASSWORD: str - POSTGRES_DB: str - SQLALCHEMY_DATABASE_URI: Optional[PostgresDsn] = None + API_PREFIX: str = "/api" - @validator("SQLALCHEMY_DATABASE_URI", pre=True) - def assemble_db_connection( - cls, v: Optional[str], values: Dict[str, Any] # noqa: N805 - ) -> Union[str, PostgresDsn]: - """Build the database connection string.""" - if isinstance(v, str): + DB_HOST: str + DB_USERNAME: str + DB_PASSWORD: str + DB_NAME: str + DB_PORT: int = 5432 + DB: Optional[DBSettings] = None + + @validator("DB", pre=True) + def assemble_db_settings( + cls, v: Optional[DBSettings], values: Dict[str, Any] # noqa: N805 + ) -> DBSettings: + """Build the database settings.""" + if isinstance(v, DBSettings): return v - return PostgresDsn.build( - scheme="postgresql", - user=values.get("POSTGRES_USER"), - password=values.get("POSTGRES_PASSWORD"), - host=values.get("POSTGRES_SERVER"), - path=f"/{values.get('POSTGRES_DB') or ''}", + return DBSettings( + SERVER=values.get("DB_HOST"), + NAME=values.get("DB_NAME"), + USERNAME=values.get("DB_USERNAME"), + PASSWORD=values.get("DB_PASSWORD"), + PORT=values.get("DB_PORT"), ) AUTH_DOMAIN: str = "geneweaver.auth0.com" @@ -38,7 +42,7 @@ def assemble_db_connection( "openid profile email": "read", } JWT_PERMISSION_PREFIX: str = "approle" - AUTH_CLIENT_ID: str = "oVm9omUtLBpVyL7YfJA8gp3hHaHwyVt8" + AUTH_CLIENT_ID: str = "T7bj6wlmtVcAN2O6kzDRwPVFyIj4UQNs" class Config: """Configuration for the BaseSettings class.""" diff --git a/src/geneweaver/api/dependencies.py b/src/geneweaver/api/dependencies.py index 6ddf8ed..774f4cd 100644 --- a/src/geneweaver/api/dependencies.py +++ b/src/geneweaver/api/dependencies.py @@ -4,7 +4,7 @@ import psycopg from fastapi import Depends -from geneweaver.api.core.config import db_settings, settings +from geneweaver.api.core.config import settings from geneweaver.api.core.security import Auth0, UserInternal from geneweaver.db.user import by_sso_id from psycopg.rows import dict_row @@ -21,7 +21,7 @@ def cursor() -> Generator: """Get a cursor from the connection pool.""" - with psycopg.connect(db_settings.URI, row_factory=dict_row) as conn: + with psycopg.connect(settings.DB.URI, row_factory=dict_row) as conn: with conn.cursor() as cur: yield cur