Git Product home page Git Product logo

goblet's Introduction

GOBLET

PyPI PyPI - Python Version Tests codecov

Goblet is a framework for writing serverless rest apis in python in google cloud. It allows you to quickly create and deploy python apis backed by Cloud Functions and Cloud Run as well as other GCP serverless services.

It provides:

  • A command line tool for creating, deploying, and managing your api
  • A decorator based API for integrating with GCP API Gateway, Storage, Cloudfunctions, PubSub, Scheduler, Cloudrun Jobs, BQ remote functions, Redis, Monitoring alerts and other GCP services.
  • Local environment for testing and running your api endpoints
  • Dynamically generated openapispec
  • Support for multiple stages

You can create Rest APIs:

from goblet import Goblet, jsonify, goblet_entrypoint

app = Goblet(function_name="goblet_example")
goblet_entrypoint(app)

@app.route('/home')
def home():
    return {"hello": "world"}

@app.route('/home/{id}', methods=["POST"])
def post_example(id: int) -> List[int]:
    return jsonify([id])

You can also create other GCP resources that are related to your REST api:

from goblet import Goblet, jsonify, goblet_entrypoint

app = Goblet(function_name="goblet_example")
goblet_entrypoint(app)

# Scheduled job
@app.schedule("5 * * * *")
def scheduled_job():
    return jsonify("success")

# Pubsub subscription
@app.pubsub_subscription("test")
def pubsub_subscription(data):
    app.log.info(data)
    return

# Example Redis Instance
app.redis("redis-test")

# Example Metric Alert for the cloudfunction metric execution_count with a threshold of 10
app.alert("metric",conditions=[MetricCondition("test", metric="cloudfunctions.googleapis.com/function/execution_count", value=10)])

Once you've written your code, you just run goblet deploy and Goblet takes care of deploying your app.

$ goblet deploy -l us-central1
...
https://api.uc.gateway.dev

$ curl https://api.uc.gateway.dev/home
{"hello": "world"}

Note: Due to breaking changes in Cloudfunctions you will need to wrap your goblet class in a function. See issue #88. In the latest goblet version (0.5.0) there is a helper function goblet_entrypoint that can be used as well.

goblet_entrypoint(app)

Resources Supported

Infrastructure

  • vpc connector
  • redis
  • api gateway
  • cloudtaskqueue
  • pubsub topics
  • bq spark stored procedures

Backends

  • cloudfunction
  • cloudfunction V2
  • cloudrun

Routing

  • api gateway
  • http

Handlers

  • pubsub
  • scheduler
  • storage
  • eventarc
  • cloudrun jobs
  • bq remote functions
  • cloudtask target
  • uptime checks

Alerts

  • Backend Alerts
  • Uptime Alerts
  • PubSub DLQ Alerts

Data Typing Frameworks Supported

  • pydantic
  • marshmallow

Installation

To install goblet, open an interactive shell and run:

pip install goblet-gcp

Make sure to have the correct services enabled in your gcp project depending on what you want to deploy

api-gateway, cloudfunctions, storage, pubsub, scheduler

You will also need to install gcloud cli for authentication

QuickStart

In this tutorial, you'll use the goblet command line utility to create and deploy a basic REST API. This quickstart uses Python 3.10. You can find the latest versions of python on the Python download page.

To install Goblet, we'll first create and activate a virtual environment in python3.10:

$ python3 --version
Python 3.10.10
$ python3 -m venv venv310
$ . venv37/bin/activate

Next we'll install Goblet using pip:

python3 -m pip install goblet-gcp

You can verify you have goblet installed by running:

$ goblet --help
Usage: goblet [OPTIONS] COMMAND [ARGS]...
...

Credentials

Before you can deploy an application, be sure you have credentials configured. You should run gcloud auth application-default login and sign in to the desired project.

Creating Your Project

create your project directory, which should include an main.py and a requirements.txt. Make sure requirements.txt includes goblet-gcp

$ ls -la
drwxr-xr-x   .goblet
-rw-r--r--   main.py
-rw-r--r--   requirements.txt

You can ignore the .goblet directory for now, the two main files we'll focus on is app.py and requirements.txt.

Let's take a look at the main.py file:

from goblet import Goblet, goblet_entrypoint

app = Goblet(function_name="goblet_example")
goblet_entrypoint(app)

@app.route('/home')
def home():
    return {"hello": "world"}

This app will deploy an api with endpoint /home.

Running Locally

Running your functions locally for testing and debugging is easy to do with goblet.

from goblet import Goblet

app = Goblet(function_name="goblet_example")
goblet_entrypoint(app)

@app.route('/home')
def home():
    return {"hello": "world"}

Then run goblet local Now you can hit your functions endpoint at localhost:8080 with your routes. For example localhost:8080/home

Building and Running locally using Docker

Make sure Docker Desktop and Docker CLI is installed, more information located here: https://docs.docker.com/desktop/

Refresh local credentials by running: gcloud auth application-default login

Set the GOOGLE_APPLICATION_CREDENTIALS variable by running: export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/application_default_credentials.json

To build container run: docker build . -t <tag>

To start container run:

    docker run -p 8080:8080 \
        -v ~/.config/gcloud/application_default_credentials.json:/tmp/application_default_credentials.json:ro \
        -e GOOGLE_APPLICATION_CREDENTIALS=/tmp/application_default_credentials.json \
        -e GCLOUD_PROJECT=<gcp-project> <tag>:latest

Installing private packages during Docker Build

To install a private package located with GCP Artifact Registry, credentials will need to be mounted during the build process. Add this line to Dockerfile before requirements install:

RUN --mount=type=secret,id=gcloud_creds,target=/app/google_adc.json export GOOGLE_APPLICATION_CREDENTIALS=/app/google_adc.json \  
    && pip install -r requirements.txt

To build container run: docker build . --secret id=gcloud_creds,src="$GOOGLE_APPLICATION_CREDENTIALS" -t <tag>

Deploying

Let's deploy this app. Make sure you're in the app directory and run goblet deploy making sure to specify the desired location:

$ goblet deploy -l us-central1
INFO:goblet.deployer:zipping function......
INFO:goblet.deployer:uploading function zip to gs......
INFO:goblet.deployer:function code uploaded
INFO:goblet.deployer:creating cloudfunction......
INFO:goblet.deployer:deploying api......
INFO:goblet.deployer:api successfully deployed...
INFO:goblet.deployer:api endpoint is goblet-example-yol8sbt.uc.gateway.dev

You now have an API up and running using API Gateway and cloudfunctions:

$ curl https://goblet-example-yol8sbt.uc.gateway.dev/home
{"hello": "world"}

Try making a change to the returned dictionary from the home() function. You can then redeploy your changes by running golet deploy.

Next Steps

You've now created your first app using goblet. You can make modifications to your main.py file and rerun goblet deploy to redeploy your changes.

At this point, there are several next steps you can take.

Docs - Goblet Documentation

If you're done experimenting with Goblet and you'd like to cleanup, you can use the goblet destroy command making sure to specify the desired location, and Goblet will delete all the resources it created when running the goblet deploy command.

$ goblet destroy -l us-central1
INFO:goblet.deployer:destroying api gateway......
INFO:goblet.deployer:api configs destroying....
INFO:goblet.deployer:apis successfully destroyed......
INFO:goblet.deployer:deleting google cloudfunction......
INFO:goblet.deployer:deleting storage bucket......

Docs

Goblet Documentation

Blog Posts

Building Python Serverless Applications on GCP

Serverless APIs made simple on GCP with Goblet backed by Cloud Functions and Cloud Run

Tutorial: Publishing GitHub Findings to Security Command Center

Tutorial: Cost Spike Alerting

Tutorial: Setting Up Approval Processes with Slack Apps

Tutorial: API Deployments with Traffic Revisions and Centralized Artifact Registries in Google Cloud Run

Tutorial: Deploying Cloud Run Jobs

Tutorial: Connecting Cloudrun and Cloudfunctions to Redis and other Private Services using Goblet

Tutorial: Deploying BigQuery Remote Functions

GCP Alerts the Easy Way: Alerting for Cloudfunctions and Cloudrun using Goblet

Tutorial: Deploy CloudTaskQueues, enqueue CloudTasks and handle CloudTasks

Tutorial: Low Usage Alerting On Slack for Google Cloud Platform

Easily Manage IAM Policies for Serverless REST Applications in GCP with Goblet

Serverless Data Pipelines in GCP using Dataform and BigQuery Remote Functions

Examples

Goblet Examples

Issues

Please file any issues, bugs or feature requests as an issue on our GitHub page.

Github Action

Goblet Github Action

Roadmap

☑ Integration Tests
Api Gateway Auth
☑ Configuration Options (function names, ...)
☑ Use checksum for updates
☑ Cloudrun Backend
Scheduler trigger
Pub Sub trigger
Cloud Storage trigger
Cloudrun Jobs trigger
Firestore trigger
Firebase trigger
CloudTask and CloudTask Queues
Cloud Endpoints trigger
EventArc trigger
Redis infrastructure
BQ Remote Functions
☑ Deploy API Gateway from existing openapi spec
☑ Deploy arbitrary Dockerfile to Cloudrun
Multi Container Deployments
☑ Create Deployment Service Accounts
☑ Automatically add IAM invoker bindings on the backend based on deployed handlers
Uptime Checks

Want to Contribute

If you would like to contribute to the library (e.g. by improving the documentation, solving a bug or adding a cool new feature) please follow the contribution guide and submit a pull request.

Want to Support

Buy Me A Coffee


Based on chalice

goblet's People

Contributors

abmazhr avatar adeelk93 avatar alissonpelizaro avatar anovis avatar avukich avatar brianhlee avatar davidyum avatar dennismutia avatar dependabot[bot] avatar diegoandresdiazespinoza avatar ethanwlo avatar jissac avatar jward-premise avatar kylejohnson514 avatar ljanecki avatar luke-xue avatar mauriciowittenberg avatar mmyoussef avatar nthings avatar piusnig avatar quajones avatar samdevo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

goblet's Issues

[Cloudrun] Websockets

Offer support for websockets using cloudrun behind the scenes similar to chalice websockets.

@app.on_ws_connect()
def connect(event):
    print('New connection: %s' % event.connection_id)


@app.on_ws_message()
def message(event):
    app.websocket_api.send(event.connection_id, 'I got your message!')
    print('%s: %s' % (event.connection_id, event.body))


@app.on_ws_disconnect()
def disconnect(event):
    print('%s disconnected' % event.connection_id)
  • Note this would require dockerizing the goblet app and deploying to cloudrun

Error when running goblet local when config.json is empty

Got error when running goblet local when config.json was empty.

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Incorrect argument. Make sure you set the local param in your Goblet class and that it matches the arg used in goblet local```

Add optional argument to keep last version of archive + delete archive in Cloud Storage when deleting the function

Hello,

I noticed that the bucket used to store Cloud Function archives contains all the versions of all cloud functions deployed in the project. The number of objets is quite big after a couple of dev/try/test deployments.

Feature request :

  • add an optional argument to goblet deploy to delete the previous version of the archive in Cloud Storage
  • add an optional argument to goblet destroy to delete the archive of the function in Cloud Storage

Thanks !

`TypeError: main_handler() takes 1 positional argument but 2 were given` with `@app.topic('mytopic')`

Hello,

I created a topic in PubSub called mytopic and I tried to create a function triggered by a message in this topic. The deployment is successful but after I publish a message, I get a TypeError: dbt_handler() takes 1 positional argument but 2 were given. Here is the code of my function and the error traceback :

Function code

from goblet import Goblet

app = Goblet(function_name="goblet-pubsub")


@app.topic('mytopic')
def main_handler(data):
    app.log.info(data)
    return 

Error traceback

2021-11-11T15:20:13.051Z goblet-pubsub-topic-mytopic6gbe9k87mz0j 
Exception on / [POST] Traceback (most recent call last): 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 2073, in wsgi_app response
    = self.full_dispatch_request() 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1518, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1516, in full_dispatch_request 
    rv = self.dispatch_request() 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1502, in dispatch_request 
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/functions_framework/__init__.py", line 171, in view_func 
    function(data, context) TypeError: main_handler() takes 1 positional argument but 2 were given

Exception on / [POST] Traceback (most recent call last): 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 2073, in wsgi_app response 
    = self.full_dispatch_request() 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1518, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1516, in full_dispatch_request 
    rv = self.dispatch_request() 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/flask/app.py", line 1502, in dispatch_request 
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) 
File "/layers/google.python.pip/pip/lib/python3.7/site-packages/functions_framework/__init__.py", line 171, in view_func 
    function(data, context) 

TypeError: main_handler() takes 1 positional argument but 2 were given

What am I supposed to provided to main_handler ?

Thank you !

Use environment variables in `config.json`

Hello

I start to have a lot of environment variables hard-coded in the config.json ; some are more sensitive than the others 🔒 . Would it be possible to allow the use of environment variable, and interpolate on run time, like the GIT_TOKEN and EXAMPLE_ENV_VAR here :

{
    "cloudfunction": {
        "runtime":"python37",
        "environmentVariables": {
            "KEY":"$EXAMPLE_ENV_VAR"
        },
        "buildEnvironmentVariables": {
            "GIT_TOKEN":"$GIT_TOKEN"
        },
        "availableMemoryMb": 256,
        "timeout": "30s"
    }
}

This could be particularly useful for local development, CI/CD and a light solution while waiting for the powerful [Secret Manager] Secret Manager Integration #58.

[Routes] Improve get_event_type handling for routes and http events

I would like to remove the request.headers.get('X-Envoy-Original-Path') which denotes a request coming from api gateway vs the cloudfunction being directly called via http. The one point that they overlap is for the route '/' so will just need to add logic for that route.

if request.path and request.headers.get('X-Envoy-Original-Path'):
            return "route"
return 'http'

[Secret Manager] Secret Manager Integration

A built in integration with Secret Manager to inject secrets into cloudfunctions. Currently the options are to supply env variable, or to write the secret manager logic yourself.

example config.json

"secrets": {
  "GH_TOKEN": projects/{project_id}/secrets/GH_TOKEN/versions/2",
  "OTHER_TOKEN"
}

with default being projects/{project_id}/secrets/{secret_name}/versions/latest

then in your code you would use config.secrets to access

from goblet.config import Config

config = Config()
@app.route("/reveal")
def reveal_secret():
    return config.secrets.GH_TOKEN

[Cloudfunction] Error `type <class 'goblet.app.Goblet'>` during deployment

getting error while deploying to us-east1 . working in other regions. seems to be a recent change just to that region. following up with gcp whether it is a bug and/or will be deployed out to other regions

The function defined in file /workspace/main.py as app needs to be of type function. Got: invalid type <class 'goblet.app.Goblet'>

workaround would be to define a new entrypoint and call goblet app inside. this would require the user to set the entrypoint since now it is automatically set by goblet during deploy.

def entrypoint(request, context=None):
   app(request,context)

[Routes] Api Gateway support all backends

Api gateway allows for different backends such as cloudrun, apigateway, compute engine or gke in addition to cloudfunctions, which should be configurable in goblet.

@app.route_backend("/cloudrun/{id}", CLOUDRUN_URL)
def cloudrun(id: string) -> string:
    return # wouldn't be called since in cloudrun, but needed for type_hints 


@app.route_backend("/app_engine/{id}", APP_ENGINE_URL)
def app_engine(id: string) -> string:
    return # wouldn't be called since in app engine, but needed for type_hints 

@app.route("/cloudfunction/{id}")
def regular_cloudfunction(id: string) -> string:
    return id  

could also be following where types returns the input and output types needed to create the openapi spec correctly.

app.route_backend("/app_engine/{id}", APP_ENGINE_URL, types)

Create multiple cloud scheduler to call the same function

Hello,

I am working on a simple use case : I have a cloud function that accepts a 'URl' parameter, calls that URl (which is a public API endpoint) and saves the data in a JSON file stored in Cloud Storage. I want to be able to set multiple cloud scheduler to call different endpoints on different schedules, but I only need 1 function.

Question : My guess is that @app.schedule('5 * * * *') creates both a Cloud Scheduler and a Cloud Function. Is there a possibility to only create a (or multiple) Cloud Scheduler and define parameters to use in the call to the Cloud Function ?

split out cloudfunction into its own class

currently there is a some logic for deploying cloudfunctions in deployer, but it is also needed in some of the resource classes as well. might be good to move it all into one cloudfunction class.

functions that should be included

  • zip
  • upload
  • create
  • destroy
  • patch
  • check_diff

HttpError 400 when using goblet delete

googleapiclient.errors.HttpError: HttpError 400 when requesting "Resource" has nested resources

for some reason there is some delay between deleting the config and then trying to delete the api so there is this error for nested resource.

you can currently just run the command again since the config resource is deleted in the first command. I will work on a fix going forward.

[CLI] Multi region deployment

cli command to deploy the same functions in multiple regions

goblet deploy --regions region1,region2,region3 --project x

[Scheduler] Get default app engine region

use api equivalent gcloud app describe --project PROJECT to get the default app engine region since this is the only region allowed in a project for cloud schedulers

error was
"Location must equal us-east1 because the App Engine app that is associated with this project is located in us-east1. Creating and editing resources in non-App Engine region is not allowed."

[Openapispec] Generate boilerplate app based on Openapispec

generate a boilerplate app with routes based on an openapispec file.

goblet generate -f openapispec.yml

/pets:
  get:
    description: Returns all pets from the system that the user has access to
    produces:
    - application/json
    responses:
      '200':
        description: A list of pets.
        schema:
          type: array
          items:
            $ref: '#/definitions/pet'

would yield in main.py

@app.route('/pets')
def pets() -> List[pet]
    raiseNotImplimented('/pets')

generic http endpoint

allow goblet to deploy a regular http cloudfunction without apigateway.

app = Goblet()

@app.http()
def http_endpoint(event):
    return "http_endpoint"

Create multiple cloud functions with 1 goblet project

Hello,

Is it possible to define multiple cloud functions in the .goblet/config.json ?
I plan to create multiple cloud functions using goblet and I don't want to maintain them in separate folders/projects.
Thank you in advance.

[Http] Trigger different functions based on header values

Trigger different functions based on header values similar to pubsub attributes. Allows for routing basic http requests without having to deploy pull apigateway

@app.http(headers={"X-GitHub-Event"})
def github(request):
return 

or

@app.http(headers={"X-GitHub-Event":"issues"})
def issues(request):
   return issues

@app.http(headers={"X-GitHub-Event":"pull_requests"})
def prs(request):
   return prs

goblet init cli command

would be nice to have a cli command to init all required pieces to deploy a function which would be an example main.py, requirements.txt with goblet-gcp incuded and a .goblet folder with a sample config.json

goblet init or goblet init NAME

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.