39
loading...
This website collects cookies to deliver better user experience
run()
inside a main.py
module at the other end, waiting to be instantiated and do its thing.main.py
to be the endpoint. Which meant my run()
function now had to become a relay function, calling other functions according to the message's payload. A preview of that is visible in the cover image.os
module, like so:BAMBOO_API_TOKEN = os.environ.get('BAMBOO_API_TOKEN')
BIGQUERY_PROJECT = os.environ.get('BIGQUERY_PROJECT')
local-source-1-daily
, local-source-1-weekly
, local-source-2-all
etc. A bit tedious, but it works as it should, as long as there are no environment variables. For some reason, you can't simply set up environment variables locally and then retrieve them inside the CF once it is run. The solution is to generate a file, simply called .env
, that stores the variables you want. Thankfully, this also has been packaged for you in python.setup-functions-fmwk.py
, that takes in positional arguments and generates a .env
file.from sys import argv
import json
# Arguments check
if len(argv) < 4:
print("Not all arguments entered.")
print("Args: ", ' '.join(argv))
print("Exiting function.")
exit()
# Some additional checks...
project = argv[1]
environment = argv[2]
runMessage = argv[3]
# Get API key
fp = 'api-key.json'
try:
with open(fp) as f:
j = json.load(f)
except FileNotFoundError:
print("File `{}` not found.".format(fp))
print("Exiting function.")
exit()
apiKey = j['apiKey']
# Set up environment variables
with open('.env', 'w') as env:
env.write('GOOGLE_APPLICATION_CREDENTIALS="service-account.json"\n')
env.write('PROJECT="{}"\n'.format(project))
env.write('API_KEY="{}"\n'.format(apiKey))
env.write('ENVIRONMENT="{}"\n'.format(environment))
env.write('RUN_MESSAGE="{}"\n'.format(runMessage))
print("Setup complete.")
exit()
def run(event, context):
'''
Endpoint function triggered by Pub/Sub that runs a specified API.
Args:
event (dict) - The dictionary with data specific to this type of event.
context (google.cloud.functions.Context) - The Cloud Functions event metadata.
'''
import base64
import bambooAPI
import pipedriveAPI
import hnbAPI
import gscostAPI
from dotenv import load_dotenv
import os
print("This cloud function was triggered by messageId {} published at {}.".format(context.event_id, context.timestamp))
if 'data' in event:
pubsubMessage = base64.b64decode(event['data']).decode('utf-8')
print("Cloud function trigerred with payload `{}`.".format(pubsubMessage))
if pubsubMessage == 'pipedrive-legacy-run-hourly':
print("Starting `pipedriveAPI.run_legacy_mode('hourly')`")
pipedriveAPI.run_legacy_mode('hourly')
# Other run options ...
elif pubsubMessage == 'local':
print("Loading local environment.")
load_dotenv()
env_run_msg = os.getenv("RUN_MESSAGE")
if env_run_msg == 'pipedrive-legacy-run-hourly':
pipedriveAPI.run_legacy_mode('hourly')
# Other run options ...
else:
print("Unknown payload. Terminating cloud function.")
else:
print("No payload in the Pub/Sub message. Terminating cloud function.")
.evn
has been written with key=value
pairs, it is loaded simply with load_dotenv()
module. You can then use os
, as we did above, to load the variables.curl
, but it's a messy statement, certainly not something you will remember unless you test your CF 20+ times a day, so why not do a python function to generate the message? I called mine run-functions-fmwk.py
:from sys import argv
import requests
import base64
import datetime
# Set up curl call
# Check endpoint
msg = 'local'
ts = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
data = base64.b64encode(msg.encode('utf-8')).decode('utf-8')
print("Encoded message: {}".format(data))
d = {
"context": {
"eventId":"1144231683168617",
"timestamp":"{}".format(ts),
"eventType":"google.pubsub.topic.publish",
"resource": {
"service":"pubsub.googleapis.com",
"name":"projects/bornfight-projects/topics/gcf-test",
"type":"type.googleapis.com/google.pubsub.v1.PubsubMessage"
}
},
"data": {
"@type": "type.googleapis.com/google.pubsub.v1.PubsubMessage",
"attributes": {
"attr1":"attr1-value"
},
"data":"{}".format(str(data))
}
}
url = 'http://127.0.0.1:8080'
h = {"Content-Type": "application/json"}
r = requests.post(url, headers=h, json=d)
print("Response {}".format(r.status_code))
exit()
functions-framework
listens to port 8080 at your localhost, so if you need to change the port, you can pass it in as an argument to the function call.python3 setup-functions-fmwk.py bi-project test-environment pipedrive-legacy-run-hourly
functions-framework --target run --signature-type event
target
is the name of the endpoint, signature-type
is event
, unless your function is dealing with webhooks, then it's http
, but you also need to change the way your function consumes the data. There are some other options, such as the port which is used to listen to incoming requests, but I will not go into those.python3 run-functions-fmwk.py
functions-framework
doesn't stop running when the function finishes, so you need to interrupt it with Ctrl+C
back in terminal 1.