From 92618317cb3253792dd177495dfcf60dca42147a Mon Sep 17 00:00:00 2001 From: Thomas Tacquet Date: Thu, 17 Apr 2025 17:17:26 +0200 Subject: [PATCH 1/3] feat(go): mongo db sample --- functions/go-mongo/README.md | 59 ++++++++++++++++++++++ functions/go-mongo/cmd/main.go | 12 +++++ functions/go-mongo/go.mod | 22 ++++++++ functions/go-mongo/go.sum | 60 ++++++++++++++++++++++ functions/go-mongo/main.go | 91 ++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 functions/go-mongo/README.md create mode 100644 functions/go-mongo/cmd/main.go create mode 100644 functions/go-mongo/go.mod create mode 100644 functions/go-mongo/go.sum create mode 100644 functions/go-mongo/main.go diff --git a/functions/go-mongo/README.md b/functions/go-mongo/README.md new file mode 100644 index 0000000..241222a --- /dev/null +++ b/functions/go-mongo/README.md @@ -0,0 +1,59 @@ +# Mongo + Go example + +Example to demonstrate the possibility to connect Serverless Functions to MongoDB. + +For this example, [Scaleway Console](https://console.scaleway.com/) will be used for deployment. + +> [!WARNING] +> This is a basic sample that does not use certificate for authentication, not recommended for production. + +## Requirements + +- Mongo DB created [documentation](https://www.scaleway.com/en/docs/managed-mongodb-databases/quickstart/#how-to-create-a-database-instance) + +## Step 1 - Mongo + +After Mongo DB creation, in the console find the public endpoint of the database, it should look lile: `.mgdb..scw.cloud` + +Once you get the endpoint, keep it somewhere for later use. + +## Step 2 - Function Creation + +Before creating a the Function, we need to package it into a zip file. + +> [!TIP] +> It's recommended to do it via command line tools, so the following example shows how to zip this current folder: +> +> ```sh +> cd ~/scaleway/serverless-examples/functions/go-mongo/ +> zip -r go-mongo.zip * +> ``` + +- Create a Serverless Function namespace. [Documentation](https://www.scaleway.com/en/docs/serverless-functions/how-to/create-manage-delete-functions-namespace/#creating-a-serverless-functions-namespace) +- In the created namespace, create Serverless Function +- Select the Go runtime +- Upload the previously created `go-mongo.zip` +- Ensure the handler is `Handle` +- Add required Secrets to the Function: + +| Key | Value | +| --------------------- | -------------------------------------------------------------------------------------------------------------- | +| MONGO_PUBLIC_ENDPOINT | (replace with required values): `.mgdb..scw.cloud` | +| MONGO_USER | user created during Mongo DB setup | +| MONGO_PASSWORD | password created during Mongo DB user setup | + +## Step 3 - Test + +Once your Serverless Function is in `ready` state, you can call it using the generated endpoint. + +Result should be similar to: + +```json +{ "ID": 2911126, "Name": "RandomName2911126" } +``` + +## Local testing + +For testing you can use [Go Offline Testing](https://github.com/scaleway/serverless-functions-go). + +To run locally, execute: `go run cmd/main.go`. \ No newline at end of file diff --git a/functions/go-mongo/cmd/main.go b/functions/go-mongo/cmd/main.go new file mode 100644 index 0000000..82b0c39 --- /dev/null +++ b/functions/go-mongo/cmd/main.go @@ -0,0 +1,12 @@ +package main + +import ( + scw "github.com/scaleway/serverless-examples/functions/go-mongo" + "github.com/scaleway/serverless-functions-go/local" +) + +// https://github.com/scaleway/serverless-functions-go +func main() { + // Replace "Handle" with your function handler name if necessary + local.ServeHandler(scw.Handle, local.WithPort(8080)) +} diff --git a/functions/go-mongo/go.mod b/functions/go-mongo/go.mod new file mode 100644 index 0000000..e260582 --- /dev/null +++ b/functions/go-mongo/go.mod @@ -0,0 +1,22 @@ +module github.com/scaleway/serverless-examples/functions/go-mongo + +go 1.24.1 + +require ( + github.com/scaleway/serverless-functions-go v0.1.2 + go.mongodb.org/mongo-driver v1.17.3 +) + +require ( + github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.17.0 // indirect +) diff --git a/functions/go-mongo/go.sum b/functions/go-mongo/go.sum new file mode 100644 index 0000000..1167870 --- /dev/null +++ b/functions/go-mongo/go.sum @@ -0,0 +1,60 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/scaleway/serverless-functions-go v0.1.2 h1:UUToB+XXpLDG9l6c9c0ALhAs1jvb6rV2Lkyj2kZEYCo= +github.com/scaleway/serverless-functions-go v0.1.2/go.mod h1:23Hj74DYzTsVY3QgvsM0MGnx0+0OAAabTC06BOMJE58= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= +go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/functions/go-mongo/main.go b/functions/go-mongo/main.go new file mode 100644 index 0000000..d288366 --- /dev/null +++ b/functions/go-mongo/main.go @@ -0,0 +1,91 @@ +package example + +import ( + "context" + "encoding/json" + "fmt" + "log/slog" + "math/rand" + "net/http" + "net/url" + "os" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +var client *mongo.Client + +type RandomDocument struct { + ID int `bson:"id"` + Name string `bson:"name"` +} + +func init() { + mongoPublicEndpoint := os.Getenv("MONGO_PUBLIC_ENDPOINT") + if mongoPublicEndpoint == "" { + panic("MONGO_PUBLIC_ENDPOINT is required") + } + + mongoUser := os.Getenv("MONGO_USER") + if mongoUser == "" { + panic("MONGO_USER is required") + } + + mongoPassword := url.PathEscape(os.Getenv("MONGO_PASSWORD")) + if mongoPassword == "" { + panic("MONGO_PASSWORD is required") + } + + // This is a basic sample that does not use certificate for authentication, not recommended for production. + mongo_uri := fmt.Sprintf(`mongodb+srv://%s:%s@%s/?tls=true&tlsInsecure=true`, + mongoUser, + mongoPassword, + mongoPublicEndpoint) + + var err error + client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI(mongo_uri)) + if err != nil { + panic(err) + } + + err = client.Ping(context.TODO(), nil) + if err != nil { + panic(err) + } + + slog.Info("Connected to MongoDB") +} + +func Handle(w http.ResponseWriter, r *http.Request) { + collection := client.Database("testdb").Collection("testcollection") + + randomID := rand.Intn(100000000) + + doc := RandomDocument{ + ID: randomID, + Name: fmt.Sprintf("RandomName%d", randomID), + } + + insertResult, err := collection.InsertOne(context.TODO(), doc) + if err != nil { + panic(err) + } + + slog.Info("Inserted document with ID:", insertResult.InsertedID) + + var result RandomDocument + + if err := collection.FindOne(context.TODO(), bson.M{"_id": insertResult.InsertedID}).Decode(&result); err != nil { + panic(err) + } + + slog.Info("Found document", result.Name, result.ID) + + w.Header().Set("Content-Type", "application/json") + + if err := json.NewEncoder(w).Encode(result); err != nil { + panic(err) + } +} From a61d2ee4d14838a8b8b4593a5eeddc59b49d7308 Mon Sep 17 00:00:00 2001 From: Thomas Tacquet Date: Thu, 17 Apr 2025 17:59:09 +0200 Subject: [PATCH 2/3] base readme update --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 807504c..e0bb753 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Table of Contents: | Example | Runtime | Deployment | -|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------------------| +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------------------- | | **[Badge PHP](functions/badge-php/README.md)**
A PHP function to generate repository badges. | php82 | [Serverless Framework] | | **[CORS Go](functions/cors-go/README.md)**
A Go function which allows CORS requests. | go122 | [Serverless Framework] | | **[CORS Node](functions/cors-node/README.md)**
A Node function which allows CORS requests. | node18 | [Serverless Framework] | @@ -61,11 +61,12 @@ Table of Contents: | **[Serverless Gateway Python Example](functions/serverless-gateway-python/README.md)**
A Python serverless API using Serverless Gateway. | python310 | [Python API Framework] | | **[Go and Transactional Email](functions/go-mail/README.md)**
A Go function that send emails using Scaleway SDK. | go121 | [Serverless Framework] | | **[Rotate RDB Credentials](functions/secret-manager-rotate-secret/README.md)**
A Go function that rotates RDB credentials stored in Secret Manager. | go120 | [Serverless Framework] | +| **[Connect to Mongo DB](functions/go-mongo/)**
A Go example to connect to Mongo DB | go124 | [Console] | ### 📦 Containers | Example | Language | Deployment | -|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|------------------------| +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ---------------------- | | **[Container Bash Script](containers/bash-scheduled-job/README.md)**
A Bash script runnning on a schedule using serverless containers. | Bash | [Serverless Framework] | | **[Function Handler Java](containers/function-handler-java/README.md)**
A Java function handler deployed on CaaS. | Java | [Serverless Framework] | | **[NGINX CORS Private](containers/nginx-cors-private-python/README.md)**
An NGINX proxy to allow CORS requests to a private container. | Python Flask | [Terraform] | @@ -79,7 +80,7 @@ Table of Contents: ### ⚙️ Jobs | Example | Language | Deployment | -|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------------------------| +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------- | | **[Serverless Jobs Hello World](jobs/terraform-hello-world/README.md)**
An example of building a container image and running it as a Serverless Job using Terraform. | N/A | [Terraform]-[Console] | | **[Serverless MLOps](jobs/ml-ops/README.md)**
An example of running a Serverless Machine Leaning workflow. | Python | [Terraform]-[Console]-[CLI] | | **[Auto Snapshot Instances](jobs/instances-snapshot/README.md)**
Use Serverless Jobs to create snapshots of your instances | Go | [Console] | @@ -90,7 +91,7 @@ Table of Contents: ### 💬 Messaging and Queueing | Example | Services | Language | Deployment | -|--------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------|-------------| +| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | -------- | ----------- | | **[Manage large message](mnq/large-messages/README.md)**
An example of infrastructure to manage large messages. | PaaS & S3 | Python | [Terraform] | | **[Serverless scraping](mnq/serverless-scraping/README.md)**
An example of infrastructure to scrape the hackernews website. | PaaS & RDB | Python | [Terraform] | | **[SNS Instances Notification System](mnq/sns-instances-notification-system/README.md)**
An example of infrastructure to use SNS with Instances. | PaaS & Instances | Golang | [Terraform] | @@ -98,7 +99,7 @@ Table of Contents: ### 💜 Projects | Example | Services | Language | Deployment | -|-------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------|------------------------| +| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- | ---------------------- | | **[Kong API Gateway](projects/kong-api-gateway/README.md)**
Deploying a Kong Gateway on containers to provide routing to functions. | CaaS & FaaS | Python | [Serverless Framework] | | **[Serverless Gateway](https://github.com/scaleway/serverless-gateway)**
Our serverless gateway for functions and containers. | API Gateway | Python | [Python API Framework] | | **[Monitoring Glaciers](projects/blogpost-glacier/README.md)**
A project to monitor glaciers and the impact of global warming. | S3 & RDB | Golang | [Serverless Framework] | From 22f6d59638058c34bd9ba7e4b23b9962eace4c94 Mon Sep 17 00:00:00 2001 From: Thomas Tacquet Date: Tue, 22 Apr 2025 10:49:48 +0200 Subject: [PATCH 3/3] format --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0bb753..1c30b2f 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Table of Contents: | **[Serverless Gateway Python Example](functions/serverless-gateway-python/README.md)**
A Python serverless API using Serverless Gateway. | python310 | [Python API Framework] | | **[Go and Transactional Email](functions/go-mail/README.md)**
A Go function that send emails using Scaleway SDK. | go121 | [Serverless Framework] | | **[Rotate RDB Credentials](functions/secret-manager-rotate-secret/README.md)**
A Go function that rotates RDB credentials stored in Secret Manager. | go120 | [Serverless Framework] | -| **[Connect to Mongo DB](functions/go-mongo/)**
A Go example to connect to Mongo DB | go124 | [Console] | +| **[Connect to Mongo DB](functions/go-mongo/)**
A Go example to connect to Mongo DB | go124 | [Console] | ### 📦 Containers