I would like to use a Google Cloud Function to quickly transfer data from a CSV file in GCS to a Postgres table in Cloud SQL.
Ideally I would use the GCP SDK to perform this action, but the official documentation suggests that the only way to perform the import is 1) console, 2) gcloud command, or 3) curl. I've adopted the curl approach using requests
in Python. The code I've written below (I've omitted the Cloud Function requests wrapper) works on my laptop but doesn't work in Cloud Function. The Cloud Function completes without acknowledging an error but my data is never loaded into the table, unlike when I run the code from my laptop.
import google.auth.transport.requests
import json
import requests
credentials, project = google.auth.default()
"""
According to the docs, hitting the REST endpoint requires an
access token to be passed in the request header. It was not
clear how to obtain an access token without resorting to
gcloud commands, but I finally stumbled across a solution
here: https://stackoverflow.com/a/55804230/554481
At this point in the code credentials.valid is False, and
credentials.token is None, so I need to perform a refresh
to populate them.
"""
auth_req = google.auth.transport.requests.Request()
credentials.refresh(auth_req)
# Now you can use credentials.token
access_token = credentials.token
# Removed business details for SO post
instance_name = '<removed>'
bucket_name = '<removed>'
project_id = '<removed>'
gcs_path = '<removed>'
database = '<removed>'
table_name = '<removed>''
headers = {
'Content-Type':'application/json',
'Authorization':'Bearer '+str(access_token)
}
endpoint = 'https://www.googleapis.com/sql/v1beta4/projects/{project_id}/instances/{instance_name}/import'.format(
project_id=project_id,
instance_name=instance_name
)
gcs_location = 'gs://{bucket_name}/{gcs_path}'.format(
bucket_name=bucket_name,
gcs_path=gcs_path
)
json_payload = {
"importContext": {
"fileType": "CSV",
"uri": gcs_location,
"database": database,
"csvImportOptions":{
"table":table_name
}
}
}
requests.post(
url=endpoint,
data=json.dumps(json_payload),
headers=headers
)
cloudsql.instances.import
which is part of the Cloud SQL Admin role. Double check the roles assigned to the service account that Cloud Functions is using (the default is the App Engine service account). – John Hanley