diff --git a/.github/workflows/dev_deploy.yml b/.github/workflows/dev_deploy.yml new file mode 100644 index 000000000..fb71d3464 --- /dev/null +++ b/.github/workflows/dev_deploy.yml @@ -0,0 +1,78 @@ +name: CD (Development) + +on: + push: + branches: [dev] + +permissions: + contents: write + +jobs: + staging-deploy: + + runs-on: ubuntu-latest + environment: staging + + steps: + - name: Check out source repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install uv in container + uses: astral-sh/setup-uv@v6 + with: + version: "latest" + + - name: Generate requirements.txt + run: | + uv export -o requirements.txt + + - name: Authenticate to Google Cloud + uses: 'google-github-actions/auth@v2' + with: + credentials_json: ${{ secrets.CLOUD_DEPLOY_SERVICE_ACCOUNT_KEY }} + + # Uses Google Cloud Secret Manager to store secret credentials + - name: Create app.yaml + run: | + echo "service: dev-ocotillo-api" > app.yaml + echo "runtime: python313" >> app.yaml + echo "entrypoint: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app" >> app.yaml + echo "instance_class: F4" >> app.yaml + echo "" >> app.yaml + echo "env_variables:" >> app.yaml + echo " MODE: \"production\"" >> app.yaml + echo " DB_DRIVER: \"cloudsql\"" >> app.yaml + echo " CLOUD_SQL_INSTANCE_NAME: \"${{ secrets.CLOUD_SQL_INSTANCE_NAME }}\"" >> app.yaml + echo " CLOUD_SQL_DATABASE: \"${{ secrets.CLOUD_SQL_DATABASE }}\"" >> app.yaml + echo " CLOUD_SQL_USER: \"${{ secrets.CLOUD_SQL_USER }}\"" >> app.yaml + echo " CLOUD_SQL_PASSWORD: \"${{ secrets.CLOUD_SQL_PASSWORD }}\"" >> app.yaml + echo " GCS_SERVICE_ACCOUNT_KEY: \"${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}\"" >> app.yaml + echo " GCS_BUCKET_NAME: \"${{secrets.GCS_BUCKET_NAME}}\"" >> app.yaml + echo " AUTHENTIK_URL: \"${{secrets.AUTHENTIK_URL}}\"" >> app.yaml + echo " AUTHENTIK_CLIENT_ID: \"${{secrets.AUTHENTIK_CLIENT_ID}}\"" >> app.yaml + echo " AUTHENTIK_AUTHORIZE_URL: \"${{secrets.AUTHENTIK_AUTHORIZE_URL}}\"" >> app.yaml + echo " AUTHENTIK_TOKEN_URL: \"${{secrets.AUTHENTIK_TOKEN_URL}}\"" >> app.yaml + + + - name: Deploy to Google Cloud + run: | + gcloud app deploy app.yaml --quiet --project ${{ secrets.GCP_PROJECT_ID }} + + # Clean up old versions - delete only the oldest version, one created and one destroyed + - name: Clean up oldest version + run: | + OLDEST_VERSION=$(gcloud app versions list --service=dev-ocotillo-api --project=${{ secrets.GCP_PROJECT_ID}} --format="value(id)" --sort-by="version.createTime" | head -n 1) + if [ ! -z "$OLDEST_VERSION" ]; then + echo "Deleting oldest version: $OLDEST_VERSION" + gcloud app versions delete $OLDEST_VERSION --service=dev-ocotillo-api --project=${{ secrets.GCP_PROJECT_ID }} --quiet + echo "Deleted oldest version: $OLDEST_VERSION" + else + echo "No versions to delete" + fi + + - name: Remove app.yaml + run: | + rm app.yaml + diff --git a/.github/workflows/staging_deploy.yml b/.github/workflows/staging_deploy.yml index bf9a046a6..67853446c 100644 --- a/.github/workflows/staging_deploy.yml +++ b/.github/workflows/staging_deploy.yml @@ -48,7 +48,7 @@ jobs: echo " CLOUD_SQL_DATABASE: \"${{ secrets.CLOUD_SQL_DATABASE }}\"" >> app.yaml echo " CLOUD_SQL_USER: \"${{ secrets.CLOUD_SQL_USER }}\"" >> app.yaml echo " CLOUD_SQL_PASSWORD: \"${{ secrets.CLOUD_SQL_PASSWORD }}\"" >> app.yaml - echo " GCS_SERVICE_ACCOUNT_KEY: \"${{ secrets.GCS_SERVICE_ACCOUNT_KEY}}\"" >> app.yaml + echo " GCS_SERVICE_ACCOUNT_KEY: \"${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}\"" >> app.yaml echo " GCS_BUCKET_NAME: \"${{secrets.GCS_BUCKET_NAME}}\"" >> app.yaml echo " AUTHENTIK_URL: \"${{secrets.AUTHENTIK_URL}}\"" >> app.yaml echo " AUTHENTIK_CLIENT_ID: \"${{secrets.AUTHENTIK_CLIENT_ID}}\"" >> app.yaml @@ -63,7 +63,7 @@ jobs: # Clean up old versions - delete only the oldest version, one created and one destroyed - name: Clean up oldest version run: | - OLDEST_VERSION=$(gcloud app versions list --service=ocotillo-api --project=${{ secrets.GCP_PROJECT_ID }} --format="value(id)" --sort-by="version.createTime" | head -n 1) + OLDEST_VERSION=$(gcloud app versions list --service=ocotillo-api --project=${{ secrets.GCP_PROJECT_ID}} --format="value(id)" --sort-by="version.createTime" | head -n 1) if [ ! -z "$OLDEST_VERSION" ]; then echo "Deleting oldest version: $OLDEST_VERSION" gcloud app versions delete $OLDEST_VERSION --service=ocotillo-api --project=${{ secrets.GCP_PROJECT_ID }} --quiet diff --git a/db/thing.py b/db/thing.py index 7ebd20f30..3ec71919a 100644 --- a/db/thing.py +++ b/db/thing.py @@ -113,7 +113,7 @@ class WellScreen(Base, AutoBaseMixin): String(1000), nullable=True, info={"unit": "description of the screen"} ) # Define a relationship to well if needed - # well = relationship("Well") + thing = relationship("Thing") # ============= EOF ============================================= diff --git a/schemas/thing.py b/schemas/thing.py index 69fc0a7b7..a7504fab6 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -161,6 +161,7 @@ class WellScreenResponse(ORMBaseModel): """ thing_id: int + thing: WellResponse screen_depth_bottom: float screen_depth_top: float screen_type: str | None = None diff --git a/services/gcs_helper.py b/services/gcs_helper.py index 1ef8661c6..2e5c8ee36 100644 --- a/services/gcs_helper.py +++ b/services/gcs_helper.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # =============================================================================== +import base64 import json import os import datetime @@ -32,10 +33,12 @@ def get_storage_bucket() -> storage.Bucket: if settings.mode == "production": - key_json = os.environ.get("GCS_SERVICE_ACCOUNT_KEY") + key_base64 = os.environ.get("GCS_SERVICE_ACCOUNT_KEY") + decoded = base64.b64decode(key_base64).decode("utf-8") + # Load service account credentials creds = service_account.Credentials.from_service_account_info( - json.loads(key_json) + json.loads(decoded) ) # Create storage client