Skip to content

Commit

Permalink
feat: Python SDK Example: Gsheet / Cloud Functions / Looker SDK integ…
Browse files Browse the repository at this point in the history
…ration (#874)

completed integration Gsheet / Cloud Functions / Looker Python SDK for use provision
  • Loading branch information
lanlooker authored Nov 2, 2021
1 parent 59faaab commit 0ec156a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 18 deletions.
19 changes: 10 additions & 9 deletions examples/python/cloud-function-user-provision/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,38 @@

This repository contains a [Google Cloud Function](https://cloud.google.com/functions) that leverages Looker Python SDK. The repository can be used as a starter template to build serverless microservices that interact with Looker through the following workflow:

1. Send a POST request to trigger an HTTP-based Cloud Function
1. Trigger an HTTP-based Cloud Function
2. Initialize the Looker Python SDK
3. Call Looker SDK methods and build custom logic to manage users, content, queries, etc.

In this repository, the `main.py` file takes an email address as an input and checks if this email has been registered with an existing Looker user. If an exisiting user is found, an email to reset the password will be sent to the user. Otherwise, a new user will be created, and a setup email will be sent.
In this repository, the `main.py` file takes an email address as an input and checks if this email has been registered with an existing Looker user. If a current user is found, an email to reset the password will be sent to the user. Otherwise, a new user will be created, and a setup email will be sent.

For more use cases and Python examples, check out [Looker's Python SDK examples](https://github.com/looker-open-source/sdk-codegen/tree/main/examples/python).
Check out [Looker's Python SDK examples](https://github.com/looker-open-source/sdk-codegen/tree/main/examples/python) for more code examples.

## Demo

<p align="center">
<img src="https://storage.googleapis.com/tutorials-img/Cloud%20Function%20Demo%20-%20SD%20480p.gif" alt="Demo">
</p>


## Setup

The following steps assume deployment using Google Cloud UI Console. Check out ["Your First Function: Python"](https://cloud.google.com/functions/docs/first-python) for steps to deploy using the `gcloud` command line tool
The following steps assume deployment using Google Cloud UI Console. Check out ["Your First Function: Python"](https://cloud.google.com/functions/docs/first-python) for steps to deploy using the `gcloud` command-line tool

1. Obtain a [Looker API3 Key](https://docs.looker.com/admin-options/settings/users#api3_keys)

2. Follow the steps [provided here](https://cloud.google.com/functions/docs/quickstart-python) to create a new Google Cloud Function

3. Configure runtime environment variables using the Cloud Function UI: Edit > Configuration > Runtime, build, connections and security settings > Runtime environment variables. Alternatively, environtment variables can be configured through the `os` module or a `.ini`. Check out [Configuring Looker Python SDK](https://github.com/looker-open-source/sdk-codegen/tree/main/python#configuring-the-sdk) to learn more
3. If using Google Sheet: Grant "Viewer" permission to the email address associated with the "Runtime service account" in Cloud Functions. The recommendation is to use the [Default App Engine Service Account](https://cloud.google.com/appengine/docs/standard/python/service-account) and share its email (`YOUR_PROJECT_ID@appspot.gserviceaccount.com`) to the Google Sheet.

4. Configure runtime environment variables using the Cloud Function UI: Edit > Configuration > Runtime, build, connections and security settings > Runtime environment variables. Alternatively, environment variables can be configured through the `os` module or a `.ini` file. Check [Configuring Looker Python SDK](https://github.com/looker-open-source/sdk-codegen/tree/main/python#configuring-the-sdk) for more information

<p align="center">
<img src="https://storage.googleapis.com/tutorials-img/Cloud%20Function_env%20-%20SD%20480p.gif" alt="Setting environmental variables in Cloud Function UI">
</p>

4. Copy and paste the contents of `main.py` in this repository into `main.py` file once inside Cloud Function's inline editor. Change the "Entry point" in the top right to `main`. `main.py` is executed once the function is triggered
5. Copy and paste the contents of `main.py` in this repository into the `main.py` file once inside Cloud Function's inline editor. Change the "Entry point" in the top right to the main function. `main.py` is executed once the function is triggered

5. Copy and paste the contents of `requirements.txt` in this repository to the `requirements.txt` file once inside Cloud Function's inline editor. This file is used to install neccessary libraries to execute the function
6. Copy and paste the contents of `requirements.txt` in this repository to the `requirements.txt` file once inside Cloud Function's inline editor. This file is used to install necessary libraries to execute the function

6. Deploy and test the function. Check out [this article](https://cloud.google.com/functions/docs/quickstart-python#test_the_function) for instruction
7. Deploy and test the function. Check out [this article](https://cloud.google.com/functions/docs/quickstart-python#test_the_function) for instruction
69 changes: 61 additions & 8 deletions examples/python/cloud-function-user-provision/main.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
"""This Cloud Function leverages Looker Python SDK to manage user provision. The
`main` function is used as the entry point to the code. It takes an email address
as an input through a POST request, then checks if this email has been associated
with an existing Looker user. If an exisiting user is found, then an email to
reset password will be sent. Otherwise, a new user will be created, and a setup email
will be sent.
"""This Cloud Function leverages Looker Python SDK to manage user provision.
It takes an email address as an input, then checks if this email has been
associated with an existing Looker user. If a current user is found, then an
email to reset the password will be sent. Otherwise, a new user will be created,
and a setup email will be sent.
The `main` function is triggered through an HTTP request. Two example approaches
are provided below:
main(request): take a POST request in form of {"email":"test@test.com"},
and read the email value from the request body
main_gsheet(request): take a GET request and read the email value from a cell
inside an existing Google sheet.
HTTP Cloud Functions: https://cloud.google.com/functions/docs/writing/http#sample_usage"""

# If not using Google Sheet, removing Google modules here and in `requirements.txt`
from googleapiclient.discovery import build
import google.auth

import looker_sdk
sdk = looker_sdk.init40()

# [START main(request)]
def main(request):
"""Take email from JSON body of a POST request, and use the email value
as an input for looker_user_provision() function"""
try:
request_json = request.get_json()
email = request_json["email"]
result = looker_user_provision(email=email)
return result
except:
return 'Please provide JSON in the format of {"email":"test@test.com"}'
# [END main(request)]

# [START main_gsheet(request)]
def main_gsheet(request):
"""Take email from a cell inside an existing Google Sheet"""
try:
email = get_email_from_sheet()
result = looker_user_provision(email=email)
return result
except:
return 'An error occurred.'

def get_email_from_sheet():
""" Authenticate to an existing Google Sheet using the default runtime
service account and extract the email address from a cell inside the sheet.
Refer to Google Sheet API Python Quickstart for details:
https://developers.google.com/sheets/api/quickstart/python
"""
# Get the key of an existing Google Sheet from the URL.
# Example: https://docs.google.com/spreadsheets/d/[KEY HERE]/edit#gid=111
SAMPLE_SPREADSHEET_ID = "foo"

# Google Sheet Range: https://developers.google.com/sheets/api/samples/reading
SAMPLE_RANGE_NAME = "Sheet1!A:A"

creds, _proj_id = google.auth.default()
service = build("sheets", "v4", credentials=creds)
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
range=SAMPLE_RANGE_NAME).execute()

# `values` will be a list of lists (i.e.: [['email1'], ['email2']])
# and we can access value 'email' using index
values = result.get('values', [])
email = values[0][0]
return email
# [END main_gsheet(request)]

# [START looker_user_provision]
def looker_user_provision(email):
user_id = search_users_by_email(email=email)
if user_id is not None:
Expand Down Expand Up @@ -49,15 +101,16 @@ def create_users(email):
models_dir_validated=False
)
)

# Create email credentials for the new user
sdk.create_user_credentials_email(
user_id=new_user.id,
body=looker_sdk.models40.WriteCredentialsEmail(
email=email,
forced_password_reset_at_next_login=False
))

# Send a welcome/setup email
sdk.send_user_credentials_email_password_reset(user_id=new_user["id"])

# [END looker_user_provision]
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Function dependencies, for example:
# package>=version
looker_sdk
requests
google-api-python-client==1.7.9
google-auth-httplib2==0.0.3
google-auth-oauthlib==0.4.0

0 comments on commit 0ec156a

Please sign in to comment.