Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/business-bn-retry-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Business BN Retry Job CD

on:
push:
branches:
- main
- feature*
- hotfix*
paths:
- "gcp-jobs/bn-retry/**"
workflow_dispatch:
inputs:
target:
description: "Deploy To"
required: true
type: choice
options:
- "dev"
- "test"
- "prod"
redeploy:
description: "Redeploy Application"
required: true
type: choice
options:
- "false"
- "true"

jobs:
business-bn-retry-cd:
uses: bcgov/bcregistry-sre/.github/workflows/backend-job-cd.yaml@main
with:
target: ${{ inputs.target }}
app_name: "business-bn-retry"
working_directory: "./gcp-jobs/bn-retry"
redeploy: ${{ inputs.redeploy }}
secrets:
WORKLOAD_IDENTIFY_POOLS_PROVIDER: ${{ secrets.WORKLOAD_IDENTIFY_POOLS_PROVIDER }}
GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
24 changes: 24 additions & 0 deletions .github/workflows/business-bn-retry-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Business BN Retry Job CI

on:
pull_request:
branches:
- main
- feature*
- hotfix*
paths:
- "gcp-jobs/bn-retry/**"
workflow_dispatch:

defaults:
run:
shell: bash
working-directory: ./gcp-jobs/bn-retry

jobs:
business-bn-retry-ci:
uses: bcgov/bcregistry-sre/.github/workflows/backend-ci.yaml@main
with:
app_name: "business-bn-retry"
working_directory: "./gcp-jobs/bn-retry"
codecov_flag: "business-bn-retry"
34 changes: 34 additions & 0 deletions gcp-jobs/bn-retry/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Database Configuration
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_NAME=
DATABASE_HOST=
DATABASE_PORT=5432
DATABASE_UNIX_SOCKET=

# Colin API Configuration
COLIN_API_URL=
COLIN_API_VERSION=/api/v1
COLIN_API_TIMEOUT=20

# Service Account for Authentication
ACCOUNT_SVC_AUTH_URL=
ACCOUNT_SVC_CLIENT_ID=
ACCOUNT_SVC_CLIENT_SECRET=
ACCOUNT_SVC_TIMEOUT=20

# GCP Pub/Sub Configuration
GCP_AUTH_KEY=
AUDIENCE=https://pubsub.googleapis.com/google.pubsub.v1.Subscriber
PUBLISHER_AUDIENCE=https://pubsub.googleapis.com/google.pubsub.v1.Publisher
SUB_AUDIENCE=
SUB_SERVICE_ACCOUNT=
SBC_CONNECT_GCP_QUEUE_DEBUG=false

# Topics
BUSINESS_EVENTS_TOPIC=business-events
BUSINESS_EMAILER_TOPIC=business-emailer

# Application Configuration
DEPLOYMENT_ENV=production
SECRET_KEY=
85 changes: 85 additions & 0 deletions gcp-jobs/bn-retry/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
FROM python:3.13-bullseye AS development_build

USER root

ARG VCS_REF="missing"
ARG BUILD_DATE="missing"

ENV VCS_REF=${VCS_REF}
ENV BUILD_DATE=${BUILD_DATE}
ENV PORT=8080

LABEL org.label-schema.vcs-ref=${VCS_REF} \
org.label-schema.build-date=${BUILD_DATE}

ARG APP_ENV \
# Needed for fixing permissions of files created by Docker:
UID=1000 \
GID=1000

ENV APP_ENV=${APP_ENV} \
# python:
PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PYTHONDONTWRITEBYTECODE=1 \
# pip:
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_DEFAULT_TIMEOUT=100 \
PIP_ROOT_USER_ACTION=ignore \
# poetry:
POETRY_VERSION=2.1.1 \
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=false \
POETRY_CACHE_DIR='/var/cache/pypoetry' \
POETRY_HOME='/usr/local'

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

RUN apt-get update && apt-get upgrade -y \
&& apt-get install --no-install-recommends -y \
bash \
brotli \
build-essential \
curl \
gettext \
git \
libpq-dev \
wait-for-it \
&& curl -sSL 'https://install.python-poetry.org' | python - \
&& poetry --version \
# Cleaning cache:
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

WORKDIR /code

RUN groupadd -g "${GID}" -r web \
&& useradd -d '/code' -g web -l -r -u "${UID}" web \
&& chown web:web -R '/code'

# Copy only requirements, to cache them in docker layer
COPY --chown=web:web ./poetry.lock ./pyproject.toml /code/

COPY --chown=web:web ./src /code/src
COPY --chown=web:web ./README.md /code

# Project initialization:
RUN --mount=type=cache,target="$POETRY_CACHE_DIR" \
echo "$APP_ENV" \
&& poetry version \
# Install deps:
&& poetry run pip install -U pip \
&& poetry install \
$(if [ -z ${APP_ENV+x} ] | [ "$APP_ENV" = 'production' ]; then echo '--only main'; fi) \
--no-interaction --no-ansi

# Running as non-root user:
USER web

# The following stage is only for production:
FROM development_build AS production_build
COPY --chown=web:web . /code

CMD python /code/run.py
33 changes: 33 additions & 0 deletions gcp-jobs/bn-retry/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
DOCKER_NAME:=bn-retry

#################################################################################
# COMMANDS -- Setup #
#################################################################################

#################################################################################
# COMMANDS - CI #
#################################################################################
.PHONY: build

build: ## Build the docker container
docker build . -t $(DOCKER_NAME) \
--platform linux/amd64 \
--build-arg VCS_REF=$(shell git rev-parse --short HEAD) \
--build-arg BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")

build-nc: ## Build the docker container without caching
docker build --no-cache -t $(DOCKER_NAME) .

#################################################################################
# COMMANDS - Local #
#################################################################################

#################################################################################
# Self Documenting Commands #
#################################################################################
.PHONY: help

.DEFAULT_GOAL := help

help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
55 changes: 55 additions & 0 deletions gcp-jobs/bn-retry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# BN Retry

BN15 retry GCP job for firms created in LEAR.

## Overview

This job checks BN15 status for businesses firms:
- Queries businesses with identifiers not starting with 'FM0' that don't have a valid BN15 (FM0's are old, created in colin)
- Checks BN15 status via Colin API `/program_account/<identifier>` endpoint
- Updates LEAR database with BN15 when received
- Sends email notification via BUSINESS_EMAILER_TOPIC
- Publishes business change event to BUSINESS_EVENTS_TOPIC

## Poetry

You may prefer to have the vitrual-environment in the project home. To do that, tell poetry to use a local .venv before
installing.

```shell
poetry config virtualenvs.in-project true
```

```shell
poetry install
```

You can issue any command in the current environment, via poetry's shell

```shell
source $(poetry env activate)
```

### Run the job

```bash
python run.py
```

### Run Linting

```bash
ruff check
```

### Run unit tests

```
pytest
```

## Deployment

The job is deployed to GCP Cloud Run and scheduled to run daily at 6AM via Cloud Scheduler.

See `devops/gcp-cloudbuild.yaml` for build configuration and `schedules/bn-retry-schedule.yaml` for scheduler configuration.
60 changes: 60 additions & 0 deletions gcp-jobs/bn-retry/devops/gcp/clouddeploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
name: business-bn-retry-pipeline
description: Deployment pipeline
serialPipeline:
stages:
- targetId: a083gt-dev
profiles: [dev]
strategy:
standard:
verify: false
deployParameters:
- values:
deploy-env: "development"
deploy-project-id: "a083gt-dev"
job-name: "business-bn-retry-dev"
cloudsql-instances: "a083gt-dev:northamerica-northeast1:businesses-db-dev"
run-command: "./run.sh"
service-account: "sa-job@a083gt-dev.iam.gserviceaccount.com"
- targetId: a083gt-test
profiles: [test]
strategy:
standard:
verify: false
deployParameters:
- values:
deploy-env: "development"
deploy-project-id: "a083gt-test"
job-name: "business-bn-retry-test"
cloudsql-instances: "a083gt-test:northamerica-northeast1:businesses-db-test"
run-command: "./run.sh"
service-account: "sa-job@a083gt-test.iam.gserviceaccount.com"
- targetId: a083gt-prod
profiles: [prod]
strategy:
standard:
verify: false
deployParameters:
- values:
deploy-env: "production"
deploy-project-id: "a083gt-prod"
job-name: "business-bn-retry-prod"
cloudsql-instances: "a083gt-prod:northamerica-northeast1:businesses-db-prod"
run-command: "./run.sh"
service-account: "sa-job@a083gt-prod.iam.gserviceaccount.com"
25 changes: 25 additions & 0 deletions gcp-jobs/bn-retry/devops/vaults.gcp.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Account Service
ACCOUNT_SVC_AUTH_URL="op://keycloak/$APP_ENV/base/KEYCLOAK_AUTH_TOKEN_URL"
ACCOUNT_SVC_CLIENT_ID="op://keycloak/$APP_ENV/entity-service-account/ENTITY_SERVICE_ACCOUNT_CLIENT_ID"
ACCOUNT_SVC_CLIENT_SECRET="op://keycloak/$APP_ENV/entity-service-account/ENTITY_SERVICE_ACCOUNT_CLIENT_SECRET"
ACCOUNT_SVC_TIMEOUT="op://keycloak/$APP_ENV/entity-service-account/ENTITY_SERVICE_ACCOUNT_SVC_TIMEOUT"

# Colin API
COLIN_API_URL="op://API/$APP_ENV/colin-api-entity/COLIN_API_URL"
COLIN_API_VERSION="op://API/$APP_ENV/colin-api-entity/COLIN_API_VERSION"

# Database
DATABASE_USERNAME="op://database/$APP_ENV/business-db/DATABASE_USERNAME"
DATABASE_PASSWORD="op://database/$APP_ENV/business-db/DATABASE_PASSWORD"
DATABASE_NAME="op://database/$APP_ENV/business-db/DATABASE_NAME"
DATABASE_PORT="op://database/$APP_ENV/business-db/DATABASE_PORT"
DATABASE_UNIX_SOCKET="op://database/$APP_ENV/business-db/DATABASE_UNIX_SOCKET"

# GCP Queue
GCP_AUTH_KEY="op://gcp-queue/$APP_ENV/a083gt/BUSINESS_GCP_AUTH_KEY"
AUDIENCE="op://gcp-queue/$APP_ENV/base/AUDIENCE"
PUBLISHER_AUDIENCE="op://gcp-queue/$APP_ENV/base/PUBLISHER_AUDIENCE"
BUSINESS_EMAILER_TOPIC="op://gcp-queue/$APP_ENV/topics/BUSINESS_EMAILER_TOPIC"
BUSINESS_EVENTS_TOPIC="op://gcp-queue/$APP_ENV/topics/BUSINESS_EVENTS_TOPIC"

VPC_CONNECTOR="op://CD/$APP_ENV/base/VPC_CONNECTOR"
Loading