Skip to content

Commit 7594181

Browse files
authored
Namex pay db update (#1891) (#1892)
- sync namex-pay to namex-api cloudsql db connector / keyless pubsub
1 parent 1e8f8ee commit 7594181

18 files changed

Lines changed: 2350 additions & 2194 deletions

services/namex-pay/.env.sample

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
SECRET_KEY=
22

33
# Database
4-
NAMEX_DATABASE_HOST=
5-
NAMEX_DATABASE_NAME=
6-
NAMEX_DATABASE_PASSWORD=
7-
NAMEX_DATABASE_PORT=
8-
NAMEX_DATABASE_USERNAME=
4+
# only for local db
5+
# check dev-scripts/local-db/docker-compose.yml for exact values
6+
# similar values are also used in https://github.com/bcgov/bcregistry-sre/blob/main/.github/workflows/backend-ci.yaml
7+
DATABASE_USERNAME=postgres
8+
DATABASE_PASSWORD="postgres"
9+
DATABASE_NAME="unittesting"
10+
DATABASE_HOST="localhost"
11+
DATABASE_PORT="54345"
12+
DATABASE_SCHEMA="public"
13+
DATABASE_OWNER="postgres"
914

10-
DATABASE_TEST_HOST=
11-
DATABASE_TEST_NAME=
15+
# only when conenecting to clousql db
16+
DATABASE_INSTANCE_CONNECTION_NAME=
17+
DATABASE_NAME=namex
18+
DATABASE_USERNAME="...@gov.bc.ca" # your email, which needs to be added as IAM user to cloudsql instance and granted readwrite access
19+
DATABASE_IP_TYPE=public
20+
DATABASE_OWNER=userHQH
21+
22+
#unit tests
23+
DATABASE_TEST_USERNAME=
1224
DATABASE_TEST_PASSWORD=
25+
DATABASE_TEST_NAME=
26+
DATABASE_TEST_HOST=
1327
DATABASE_TEST_PORT=
14-
DATABASE_TEST_USERNAME=
15-
16-
# Oracle Database
17-
NRO_USER=
18-
NRO_PASSWORD=
19-
NRO_DB_NAME=
20-
ORACLE_HOST=
21-
ORACLE_PORT=1521
2228

2329
# APIs
2430
PAY_API_URL=
2531
PAY_API_VERSION=
2632

27-
BUSINESS_GCP_AUTH_KEY=
2833
NAMEX_MAILER_TOPIC=
29-
PAY_SUB_AUDIENCE=
30-
AUTHPAY_SERVICE_ACCOUNT=
34+
NAMEX_NR_STATE_TOPIC=
35+
3136
DEBUG_REQUEST=

services/namex-pay/Dockerfile

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
1-
FROM python:3.12.2
2-
USER root
1+
# Stage 1: Build environment (with Poetry + dependencies installed)
2+
FROM python:3.12.5-slim AS development_build
33

44
ARG VCS_REF="missing"
55
ARG BUILD_DATE="missing"
66

77
ENV VCS_REF=${VCS_REF}
88
ENV BUILD_DATE=${BUILD_DATE}
9-
9+
ENV PORT=8080
1010

1111
LABEL org.label-schema.vcs-ref=${VCS_REF} \
12-
org.label-schema.build-date=${BUILD_DATE}
12+
org.label-schema.build-date=${BUILD_DATE} \
13+
vendor="BCROS"
1314

1415
USER root
1516

1617
ARG APP_ENV \
17-
# Needed for fixing permissions of files created by Docker:
18-
UID=1000 \
19-
GID=1000
18+
UID=1000 \
19+
GID=1000
2020

2121
ENV APP_ENV=${APP_ENV} \
22-
# python:
23-
PYTHONFAULTHANDLER=1 \
24-
PYTHONUNBUFFERED=1 \
25-
PYTHONHASHSEED=random \
26-
PYTHONDONTWRITEBYTECODE=1 \
27-
# pip:
28-
PIP_NO_CACHE_DIR=1 \
29-
PIP_DISABLE_PIP_VERSION_CHECK=1 \
30-
PIP_DEFAULT_TIMEOUT=100 \
31-
PIP_ROOT_USER_ACTION=ignore \
32-
# poetry:
33-
POETRY_VERSION=1.3.2 \
34-
POETRY_NO_INTERACTION=1 \
35-
POETRY_VIRTUALENVS_CREATE=false \
36-
POETRY_CACHE_DIR='/var/cache/pypoetry' \
37-
POETRY_HOME='/usr/local'
22+
# python:
23+
PYTHONFAULTHANDLER=1 \
24+
PYTHONUNBUFFERED=1 \
25+
PYTHONHASHSEED=random \
26+
PYTHONDONTWRITEBYTECODE=1 \
27+
# pip:
28+
PIP_NO_CACHE_DIR=1 \
29+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
30+
PIP_DEFAULT_TIMEOUT=100 \
31+
PIP_ROOT_USER_ACTION=ignore \
32+
# poetry:
33+
POETRY_VERSION=2.1.3 \
34+
POETRY_NO_INTERACTION=1 \
35+
POETRY_VIRTUALENVS_CREATE=false \
36+
POETRY_CACHE_DIR='/var/cache/pypoetry' \
37+
POETRY_HOME='/usr/local'
3838

3939
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]
4040

@@ -50,7 +50,7 @@ RUN apt-get update && apt-get upgrade -y \
5050
wait-for-it \
5151
&& curl -sSL 'https://install.python-poetry.org' | python - \
5252
&& poetry --version \
53-
# Cleaning cache:
53+
# Clean up apt cache
5454
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
5555
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
5656

@@ -60,29 +60,29 @@ RUN groupadd -g "${GID}" -r web \
6060
&& useradd -d '/code' -g web -l -r -u "${UID}" web \
6161
&& chown web:web -R '/code'
6262

63-
# Copy only requirements, to cache them in docker layer
63+
# Copy dependency files first (better caching)
6464
COPY --chown=web:web ./poetry.lock ./pyproject.toml /code/
6565

66+
# Copy app source
6667
COPY --chown=web:web ./src /code/src
6768
COPY --chown=web:web ./README.md /code
6869

69-
# Project initialization:
70+
# Install dependencies
7071
RUN --mount=type=cache,target="$POETRY_CACHE_DIR" \
7172
echo "$APP_ENV" \
7273
&& poetry version \
73-
# Install deps:
74-
&& poetry run pip install -U pip \
74+
&& poetry update \
7575
&& poetry install \
76-
$(if [ -z ${APP_ENV+x} ] | [ "$APP_ENV" = 'production' ]; then echo '--only main'; fi) \
76+
$(if [ -z ${APP_ENV+x} ] || [ "$APP_ENV" = 'production' ]; then echo '--only main'; fi) \
7777
--no-interaction --no-ansi
7878

79-
# Running as non-root user:
79+
# Run as non-root
8080
USER web
8181

82-
# The following stage is only for production:
83-
# FROM development_build AS production_build
82+
# Stage 2: Production image (lighter)
83+
FROM development_build AS production_build
8484
COPY --chown=web:web . /code
8585

8686
EXPOSE 8080
8787

88-
CMD gunicorn --bind 0.0.0.0:8080 --config /code/gunicorn_config.py wsgi:app
88+
CMD gunicorn --bind 0.0.0.0:${PORT} --config /code/gunicorn_config.py wsgi:app

services/namex-pay/Makefile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ install: clean ## Install python virtrual environment
5050
#################################################################################
5151
# COMMANDS - CI #
5252
#################################################################################
53-
ci: pylint flake8 test ## CI flow
53+
ci: docker-build-check ruff test ## CI flow
5454

55-
pylint: ## Linting with pylint
56-
. .venv/bin/activate && pylint --rcfile=setup.cfg src/$(PROJECT_NAME)
55+
docker-build-check: ## Check if Dockerfile builds successfully
56+
docker build -f Dockerfile -t namex-pay .
5757

58-
flake8: ## Linting with flake8 ## tests
59-
. .venv/bin/activate && flake8 src/$(PROJECT_NAME)
58+
ruff: ## ruff linter
59+
poetry run ruff check
6060

61-
test: ## Unit testing
62-
. .venv/bin/activate && pytest
61+
ruff-fix: ## auto fix lint issues with ruff
62+
poetry run ruff check --fix
6363

64-
mac-cov: test ## Run the coverage report and display in a browser window (mac)
65-
@open -a "Google Chrome" htmlcov/index.html
64+
test: ## unit testing with local db
65+
poetry run pytest
6666

6767
#################################################################################
6868
# COMMANDS - Local #

services/namex-pay/config.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
or by accessing this configuration directly.
2121
"""
2222
import os
23-
from dotenv import find_dotenv, load_dotenv
2423

24+
from dotenv import find_dotenv, load_dotenv
2525

2626
# this will load all the envars from a .env file located in the project root (api)
2727
load_dotenv(find_dotenv())
@@ -64,23 +64,25 @@ class Config(): # pylint: disable=too-few-public-methods
6464
PAYMENT_SVC_VERSION = os.getenv('PAY_API_VERSION', None)
6565

6666
# POSTGRESQL
67-
DB_USER = os.getenv('NAMEX_DATABASE_USERNAME', '')
68-
DB_PASSWORD = os.getenv('NAMEX_DATABASE_PASSWORD', '')
69-
DB_NAME = os.getenv('NAMEX_DATABASE_NAME', '')
70-
DB_HOST = os.getenv('NAMEX_DATABASE_HOST', '')
71-
DB_PORT = os.getenv('NAMEX_DATABASE_PORT', '5432')
72-
if DB_UNIX_SOCKET := os.getenv('NAMEX_DATABASE_UNIX_SOCKET', None):
73-
SQLALCHEMY_DATABASE_URI = f'postgresql+psycopg2://{DB_USER}:{DB_PASSWORD}@/{DB_NAME}?host={DB_UNIX_SOCKET}'
67+
DB_USER = os.getenv('DATABASE_USERNAME', 'postgres')
68+
DB_PASSWORD = os.getenv('DATABASE_PASSWORD', 'postgres')
69+
DB_NAME = os.getenv('DATABASE_NAME', 'unittesting')
70+
DB_HOST = os.getenv('DATABASE_HOST', 'localhost')
71+
DB_PORT = int(os.getenv('DATABASE_PORT', '5432'))
72+
73+
DB_SCHEMA = os.getenv('DATABASE_SCHEMA', 'public')
74+
DB_IP_TYPE = os.getenv('DATABASE_IP_TYPE', 'private')
75+
DB_OWNER = os.getenv('DATABASE_OWNER', 'postgres')
76+
77+
if DB_INSTANCE_CONNECTION_NAME := os.getenv('DATABASE_INSTANCE_CONNECTION_NAME', None):
78+
SQLALCHEMY_DATABASE_URI = 'postgresql+pg8000://'
7479
else:
75-
SQLALCHEMY_DATABASE_URI = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{int(DB_PORT)}/{DB_NAME}'
80+
SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
7681

77-
GCP_AUTH_KEY = os.getenv('BUSINESS_GCP_AUTH_KEY', None)
7882
EMAILER_TOPIC = os.getenv('NAMEX_MAILER_TOPIC', '')
7983
NAMEX_NR_STATE_TOPIC = os.getenv('NAMEX_NR_STATE_TOPIC', '')
8084
AUDIENCE = os.getenv('AUDIENCE', 'https://pubsub.googleapis.com/google.pubsub.v1.Subscriber')
8185
PUBLISHER_AUDIENCE = os.getenv('PUBLISHER_AUDIENCE', 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher')
82-
SUB_AUDIENCE = os.getenv('PAY_SUB_AUDIENCE', '')
83-
SUB_SERVICE_ACCOUNT = os.getenv('AUTHPAY_SERVICE_ACCOUNT', '')
8486
DEBUG_REQUEST = os.getenv('DEBUG_REQUEST', False)
8587

8688
ENVIRONMENT = os.getenv('ENVIRONMENT', 'prod')
@@ -104,14 +106,21 @@ class TestConfig(Config): # pylint: disable=too-few-public-methods
104106
# POSTGRESQL
105107
DB_USER = os.getenv('DATABASE_TEST_USERNAME', 'postgres')
106108
DB_PASSWORD = os.getenv('DATABASE_TEST_PASSWORD', 'postgres')
107-
DB_NAME = os.getenv('DATABASE_TEST_NAME', 'namex_pay')
108-
DB_HOST = os.getenv('DATABASE_TEST_HOST', '127.0.0.1')
109+
DB_NAME = os.getenv('DATABASE_TEST_NAME', 'unittesting')
110+
DB_HOST = os.getenv('DATABASE_TEST_HOST', 'localhost')
109111
DB_PORT = os.getenv('DATABASE_TEST_PORT', '5432')
110-
SQLALCHEMY_DATABASE_URI = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{int(DB_PORT)}/{DB_NAME}'
112+
SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{int(DB_PORT)}/{DB_NAME}'
111113
EMAILER_TOPIC = os.getenv('NAMEX_MAILER_TOPIC', '')
114+
NAMEX_NR_STATE_TOPIC = os.getenv('NAMEX_NR_STATE_TOPIC', '')
112115

113116
class ProdConfig(Config): # pylint: disable=too-few-public-methods
114117
"""Production environment configuration."""
115118

116119
TESTING = False
117120
DEBUG = False
121+
122+
class MigrationConfig(Config):
123+
"""Config for db migration."""
124+
125+
TESTING = False
126+
DEBUG = True

services/namex-pay/devops/gcp/clouddeploy.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ serialPipeline:
3232
container-name: "namex-pay-dev"
3333
service-account: "sa-api@a083gt-dev.iam.gserviceaccount.com"
3434
cloudsql-instances: "a083gt-dev:northamerica-northeast1:namex-db-dev"
35+
container-concurrency: "8"
3536
- targetId: a083gt-test
3637
profiles: [test]
3738
strategy:
@@ -45,6 +46,7 @@ serialPipeline:
4546
container-name: "namex-pay-test"
4647
service-account: "sa-api@a083gt-test.iam.gserviceaccount.com"
4748
cloudsql-instances: "a083gt-test:northamerica-northeast1:namex-db-test"
49+
container-concurrency: "8"
4850
- targetId: a083gt-prod
4951
profiles: [prod]
5052
strategy:
@@ -57,4 +59,5 @@ serialPipeline:
5759
service-name: "namex-pay-prod"
5860
container-name: "namex-pay-prod"
5961
service-account: "sa-api@a083gt-prod.iam.gserviceaccount.com"
60-
cloudsql-instances: "a083gt-prod:northamerica-northeast1:namex-db-prod"
62+
cloudsql-instances: "a083gt-prod:northamerica-northeast1:namex-db-prod"
63+
container-concurrency: "8"
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
NAMEX_DATABASE_UNIX_SOCKET="op://database/$APP_ENV/namex-db-gcp/DATABASE_UNIX_SOCKET"
2-
NAMEX_DATABASE_PORT="op://database/$APP_ENV/namex-db-gcp/DATABASE_PORT"
3-
NAMEX_DATABASE_NAME="op://database/$APP_ENV/namex-db-gcp/DATABASE_NAME"
4-
NAMEX_DATABASE_USERNAME="op://database/$APP_ENV/namex-db-gcp/DATABASE_USERNAME"
5-
NAMEX_DATABASE_PASSWORD="op://database/$APP_ENV/namex-db-gcp/DATABASE_PASSWORD"
1+
DATABASE_USERNAME="op://database/$APP_ENV/namex-db-gcp/DATABASE_USERNAME"
2+
DATABASE_NAME="op://database/$APP_ENV/namex-db-gcp/DATABASE_NAME"
3+
DATABASE_INSTANCE_CONNECTION_NAME="op://database/$APP_ENV/namex-db-gcp/DATABASE_INSTANCE_CONNECTION_NAME"
4+
DATABASE_SCHEMA="op://database/$APP_ENV/namex-db-gcp/DATABASE_SCHEMA"
65
PAY_API_URL="op://API/$APP_ENV/pay-api/PAY_API_URL"
76
PAY_API_VERSION="op://API/$APP_ENV/pay-api/PAY_API_VERSION"
87
AUDIENCE="op://gcp-queue/$APP_ENV/base/AUDIENCE"
98
PUBLISHER_AUDIENCE="op://gcp-queue/$APP_ENV/base/PUBLISHER_AUDIENCE"
109
NAMEX_MAILER_TOPIC="op://gcp-queue/$APP_ENV/topics/NAMEX_MAILER_TOPIC"
1110
NAMEX_NR_STATE_TOPIC="op://gcp-queue/$APP_ENV/topics/NAMEX_NR_STATE_TOPIC"
12-
BUSINESS_GCP_AUTH_KEY="op://gcp-queue/$APP_ENV/a083gt/BUSINESS_GCP_AUTH_KEY"
13-
PAY_SUB_AUDIENCE="op://gcp-queue/$APP_ENV/namex/PAY_SUB_AUDIENCE_GCP"
14-
AUTHPAY_SERVICE_ACCOUNT="op://gcp-queue/$APP_ENV/gtksf3/AUTHPAY_SERVICE_ACCOUNT"
1511
VPC_CONNECTOR="op://CD/$APP_ENV/namex-api/VPC_CONNECTOR"
Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,9 @@
1-
# Copyright © 2023 Province of British Columbia
2-
#
3-
# Licensed under the BSD 3 Clause License, (the "License");
4-
# you may not use this file except in compliance with the License.
5-
# The template for the license can be found here
6-
# https://opensource.org/license/bsd-3-clause/
7-
#
8-
# Redistribution and use in source and binary forms,
9-
# with or without modification, are permitted provided that the
10-
# following conditions are met:
11-
#
12-
# 1. Redistributions of source code must retain the above copyright notice,
13-
# this list of conditions and the following disclaimer.
14-
#
15-
# 2. Redistributions in binary form must reproduce the above copyright notice,
16-
# this list of conditions and the following disclaimer in the documentation
17-
# and/or other materials provided with the distribution.
18-
#
19-
# 3. Neither the name of the copyright holder nor the names of its contributors
20-
# may be used to endorse or promote products derived from this software
21-
# without specific prior written permission.
22-
#
23-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
24-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25-
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33-
# POSSIBILITY OF SUCH DAMAGE.
34-
"""The configuration for gunicorn, which picks up the
35-
runtime options from environment variables
36-
"""
37-
381
import os
392

40-
workers = int(os.environ.get("GUNICORN_PROCESSES", "1")) # pylint: disable=invalid-name
41-
threads = int(os.environ.get("GUNICORN_THREADS", "1")) # pylint: disable=invalid-name
42-
timeout = int(os.environ.get("GUNICORN_TIMEOUT", "600")) # pylint: disable=invalid-name
3+
workers = int(os.environ.get('GUNICORN_PROCESSES', '1')) # pylint: disable=invalid-name
4+
threads = int(os.environ.get('GUNICORN_THREADS', '8')) # pylint: disable=invalid-name
5+
timeout = int(os.environ.get('GUNICORN_TIMEOUT', '0')) # pylint: disable=invalid-name
6+
437

44-
forwarded_allow_ips = "*" # pylint: disable=invalid-name
45-
secure_scheme_headers = {"X-Forwarded-Proto": "https"} # pylint: disable=invalid-name
8+
forwarded_allow_ips = '*'
9+
secure_scheme_headers = {'X-Forwarded-Proto': 'https'}

0 commit comments

Comments
 (0)