Skip to content

Commit

Permalink
Merge pull request #1 from CIMAC-CIDC/deploy-dummy-function
Browse files Browse the repository at this point in the history
Create + deploy function triggered by upload event
  • Loading branch information
jacoblurye authored Jul 26, 2019
2 parents dad5f81 + 9ed3ddc commit cdc6571
Show file tree
Hide file tree
Showing 16 changed files with 129 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .env.prod.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CLOUD_SQL_INSTANCE_NAME: 'cidc-dfci:us-central1:cidc-postgres'
CLOUD_SQL_DB_USER: 'postgres'
CLOUD_SQL_DB_NAME: 'cidc'
GOOGLE_PROJECT_ID: 'cidc-dfci'
GOOGLE_SECRETS_BUCKET: 'cidc-secrets-prod'
GOOGLE_UPLOAD_BUCKET: 'cidc-uploads-prod'
GOOGLE_UPLOAD_TOPIC: 'uploads'
2 changes: 1 addition & 1 deletion .env.staging.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CLOUD_SQL_INSTANCE_NAME: 'cidc-dfci-staging:us-central1:cidc-postgres'
CLOUD_SQL_DB_USER: 'postgres'
CLOUD_SQL_DB_NAME: 'cidc'
GOOGLE_PROJECT_ID: 'cidc-dfci-staging'
GOOGLE_SECRETS_BUCKET: 'cidc-secrets-staging'
GOOGLE_UPLOAD_BUCKET: 'cidc-uploads-staging'
GOOGLE_UPLOAD_TOPIC: 'uploads'
17 changes: 17 additions & 0 deletions .gcloudignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore

node_modules
#!include:.gitignore
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ script:

deploy:
- provider: script
script: echo "Deploy cloud functions to staging here..."
script: bash deploy/pubsub.sh ingest_upload uploads .env.staging.yaml
on:
branch: master
- provider: script
script: echo "Deploy cloud functions to production here..."
script: bash deploy/pubsub.sh ingest_upload uploads .env.prod.yaml
on:
branch: production
13 changes: 13 additions & 0 deletions deploy/pubsub.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# !/usr/bin/bash
# Deploy a cloud function to a topic

ENTRYPOINT=$1
TOPIC=$2
ENVFILE=$3
PROJECT=$(gcloud config get-value project)

gcloud functions deploy $ENTRYPOINT \
--runtime python37 \
--trigger-topic $TOPIC \
--env-vars-file $ENVFILE \
--project $PROJECT
4 changes: 2 additions & 2 deletions functions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Entrypoint for CIDC cloud functions."""
"""The CIDC cloud functions."""

from functions import *
from .uploads import ingest_upload
18 changes: 18 additions & 0 deletions functions/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Configuration for CIDC functions."""
import os

from cidc_api.config import get_sqlalchemy_database_uri

GOOGLE_CLOUD_PROJECT = os.environ.get("GOOGLE_CLOUD_PROJECT")

if not GOOGLE_CLOUD_PROJECT:
from dotenv import load_dotenv

# We're running locally, so load config from .env
load_dotenv()
GOOGLE_CLOUD_PROJECT = os.environ.get("GOOGLE_CLOUD_PROJECT")


SQLALCHEMY_DATABASE_URI = get_sqlalchemy_database_uri()
GOOGLE_UPLOAD_BUCKET = os.environ.get("GOOGLE_UPLOAD_BUCKET")
GOOGLE_UPLOAD_TOPIC = os.environ.get("GOOGLE_UPLOAD_TOPIC")
17 changes: 17 additions & 0 deletions functions/uploads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""A pub/sub triggered functions that respond to data upload events"""
import base64

from .util import BackgroundContext, extract_pubsub_data


def ingest_upload(event: dict, context: BackgroundContext):
"""
When a successful upload event is published, move the data associated
with the upload job into the download bucket and merge the upload metadata
into the appropriate clinical trial JSON.
TODO: actually implement the above functionality. Right now, the function
just logs the ID of the upload job.
"""
job_id = extract_pubsub_data(event)
print(f"Received upload success event for Job {job_id}")
24 changes: 24 additions & 0 deletions functions/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Helpers for working with Cloud Functions."""
import base64
from typing import NamedTuple


def extract_pubsub_data(event: dict):
"""Pull out and decode data from a pub/sub event."""
# Pub/sub event data is base64-encoded
b64data = event["data"]
data = base64.b64decode(b64data).decode("utf-8")
return data


class BackgroundContext(NamedTuple):
"""
Model of the context object passed to a background cloud function.
Based on: https://cloud.google.com/functions/docs/writing/background#function_parameters
"""

event_id: str
timestamp: str # ISO 8601
event_type: str # e.g., "google.pubsub.topic.publish"
resource: str
3 changes: 3 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Entrypoint for CIDC cloud functions."""

from functions import ingest_upload
1 change: 1 addition & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
black==19.3b0
python-dotenv==0.10.3
pytest==5.0.1
Empty file added tests/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions tests/functions/test_uploads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from tests.util import make_pubsub_event
from functions.uploads import ingest_upload


def test_ingest_upload():
"""Test stub event-processing functionality"""
job_id = "1"
successful_upload_event = make_pubsub_event(job_id)
ingest_upload(successful_upload_event, None)
9 changes: 9 additions & 0 deletions tests/functions/test_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from tests.util import make_pubsub_event
from functions.util import extract_pubsub_data


def test_extract_pubsub_data():
"""Ensure that extract_pubsub_data can do what it claims"""
data = "hello there"
event = make_pubsub_event(data)
assert extract_pubsub_data(event) == data
4 changes: 4 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
import pytest


@pytest.mark.skip("nothing to test for the top-level module, currently")
def test_main():
pass
8 changes: 8 additions & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import base64


def make_pubsub_event(data: str) -> dict:
"""Make pubsub event dictionary with base64-encoded data."""
b64data = base64.encodebytes(bytes(data, "utf-8"))
return {"data": b64data}

0 comments on commit cdc6571

Please sign in to comment.