mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Removed a bunch of old examples. (#502)
* Removed a bunch of old examples. * moved grafana back. * Bumping, circle didn't do build... ?
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
FROM fnproject/go:dev
|
||||
|
||||
RUN mkdir -p /go/src/github.com/Masterminds
|
||||
ENV GOPATH=/go
|
||||
RUN cd /go/src/github.com/Masterminds && git clone https://github.com/Masterminds/glide.git && cd glide && go build
|
||||
RUN cp /go/src/github.com/Masterminds/glide/glide /bin
|
||||
|
||||
ENTRYPOINT ["glide"]
|
||||
1
examples/blog/.gitignore
vendored
1
examples/blog/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/func
|
||||
@@ -1,5 +0,0 @@
|
||||
FROM alpine
|
||||
|
||||
ADD func .
|
||||
|
||||
ENTRYPOINT ["./func"]
|
||||
@@ -1,144 +0,0 @@
|
||||
# Blog API Example
|
||||
|
||||
A simple serverless blog API
|
||||
|
||||
## Requirements
|
||||
|
||||
- Remote MongoDB instance (for example heroku)
|
||||
- Running Fn API
|
||||
|
||||
## Development
|
||||
|
||||
### Building image locally
|
||||
|
||||
```
|
||||
# SET BELOW TO YOUR DOCKER HUB USERNAME
|
||||
USERNAME=YOUR_DOCKER_HUB_USERNAME
|
||||
|
||||
# build it
|
||||
docker run --rm -v "$PWD":/go/src/github.com/fnproject/hello -w /go/src/github.com/fnproject/hello fnproject/go:dev go build -o function
|
||||
docker build -t $USERNAME/func-blog .
|
||||
```
|
||||
|
||||
### Publishing to DockerHub
|
||||
|
||||
```
|
||||
# tagging
|
||||
docker run --rm -v "$PWD":/app treeder/bump patch
|
||||
docker tag $USERNAME/func-blog:latest $USERNAME/func-blog:`cat VERSION`
|
||||
|
||||
# pushing to docker hub
|
||||
docker push $USERNAME/func-blog
|
||||
```
|
||||
|
||||
## Running it on Fn
|
||||
|
||||
First you need a running Fn API
|
||||
|
||||
### First, let's define this environment variables
|
||||
|
||||
```
|
||||
# Set your Function server address
|
||||
# Eg. 127.0.0.1:8080
|
||||
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
|
||||
|
||||
# Set your mongoDB server address
|
||||
# Eg. 127.0.0.1:27017/blog
|
||||
MONGODB=YOUR_MONGODB_ADDRESS
|
||||
```
|
||||
|
||||
### Testing image
|
||||
|
||||
```
|
||||
./test.sh
|
||||
```
|
||||
|
||||
### Running with Fn
|
||||
|
||||
With this command we are going to create an application with name `blog` and also defining the app configuration `DB`.
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"app": {
|
||||
"name": "blog",
|
||||
"config": { "DB": "'$MONGODB'" }
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps
|
||||
```
|
||||
|
||||
Now, we can create our blog routes:
|
||||
|
||||
- `/posts` - to create (authenticated) and list posts
|
||||
- `/posts/:id` - to read post
|
||||
- `/token` - to get a JWT
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-blog",
|
||||
"path": "/posts"
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/blog/routes
|
||||
```
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-blog",
|
||||
"path": "/posts/:id"
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/blog/routes
|
||||
```
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-blog",
|
||||
"path": "/token"
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/blog/routes
|
||||
```
|
||||
|
||||
#### Testing function
|
||||
|
||||
Now that we created our Fn route, let's test our routes
|
||||
|
||||
```
|
||||
curl -X POST http://$FUNCAPI/r/blog/posts
|
||||
```
|
||||
|
||||
This command should return `{"error":"Invalid authentication"}` because we aren't sending any token.
|
||||
|
||||
#### Authentication
|
||||
|
||||
##### Creating a blog user
|
||||
|
||||
First let's create our blog user. In this example an user `test` with password `test`.
|
||||
|
||||
```
|
||||
docker run --rm -e DB=$MONGODB -e NEWUSER='{ "username": "test", "password": "test" }' $USERNAME/functions-blog
|
||||
```
|
||||
|
||||
##### Getting authorization token
|
||||
|
||||
Now, to get authorized to post in our Blog API endpoints we must request a new token with a valid user.
|
||||
|
||||
```
|
||||
curl -X POST --data '{ "username": "test", "password": "test" }' http://$FUNCAPI/r/blog/token
|
||||
```
|
||||
|
||||
This will output a token like this:
|
||||
|
||||
```
|
||||
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMDE2LTA5LTAxVDAwOjQzOjMxLjQwNjY5NTIxNy0wMzowMCIsInVzZXIiOiJ0ZXN0In0.aPKdH3QPauutFsFbSdQyF6q1hqTAas_BCbSYi5mFiSU"}
|
||||
```
|
||||
|
||||
Let's save that token in the environment
|
||||
|
||||
```
|
||||
BLOG_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMDE2LTA5LTAxVDAwOjQzOjMxLjQwNjY5NTIxNy0wMzowMCIsInVzZXIiOiJ0ZXN0In0.aPKdH3QPauutFsFbSdQyF6q1hqTAas_BCbSYi5mFiSU
|
||||
```
|
||||
|
||||
##### Posting in your blog
|
||||
|
||||
curl -X POST --header "Authorization: Bearer $BLOG_TOKEN" --data '{ "title": "My New Post", "body": "Hello world!", "user": "test" }' http://$FUNCAPI/r/blog/posts
|
||||
@@ -1 +0,0 @@
|
||||
0.0.1
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
FUNCPKG=$(pwd | sed "s|$GOPATH/src/||")
|
||||
|
||||
# glide image to install dependencies
|
||||
../build-glide.sh
|
||||
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG glide up
|
||||
|
||||
# build image
|
||||
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG fnproject/go:dev go build -o func
|
||||
docker build -t username/func-blog .
|
||||
@@ -1,20 +0,0 @@
|
||||
package database
|
||||
|
||||
import "gopkg.in/mgo.v2"
|
||||
|
||||
type Database struct {
|
||||
Session *mgo.Session
|
||||
}
|
||||
|
||||
func New(uri string) *Database {
|
||||
session, err := mgo.Dial(uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
return &Database{
|
||||
Session: session,
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/fnproject/fn/examples/blog/models"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotObjectIdHex = errors.New("Invalid ID")
|
||||
)
|
||||
|
||||
func (db *Database) SavePost(post *models.Post) (*models.Post, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("post")
|
||||
|
||||
if post.ID.Hex() == "" {
|
||||
post.ID = bson.NewObjectId()
|
||||
}
|
||||
id := post.ID
|
||||
|
||||
change := mgo.Change{
|
||||
Update: bson.M{"$set": post},
|
||||
ReturnNew: true,
|
||||
Upsert: true,
|
||||
}
|
||||
|
||||
_, err := c.Find(bson.M{"_id": id}).Apply(change, &post)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return post, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetPost(id string) (*models.Post, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("post")
|
||||
|
||||
var post models.Post
|
||||
if !bson.IsObjectIdHex(id) {
|
||||
return nil, ErrNotObjectIdHex
|
||||
}
|
||||
|
||||
err := c.Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&post)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &post, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetPosts(query []bson.M) ([]*models.Post, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("post")
|
||||
|
||||
var posts []*models.Post
|
||||
|
||||
err := c.Pipe(query).All(&posts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return posts, nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"github.com/fnproject/fn/examples/blog/models"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
func (db *Database) SaveUser(user *models.User) (*models.User, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("user")
|
||||
id := user.Username
|
||||
user.Username = ""
|
||||
|
||||
if len(user.Password) > 0 {
|
||||
user.Password = models.UserPasswordEncrypt(user.Password)
|
||||
}
|
||||
|
||||
change := mgo.Change{
|
||||
Update: bson.M{"$set": user},
|
||||
ReturnNew: true,
|
||||
Upsert: true,
|
||||
}
|
||||
|
||||
_, err := c.Find(bson.M{"_id": id}).Apply(change, &user)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetUser(id string) (*models.User, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("user")
|
||||
|
||||
var user models.User
|
||||
|
||||
err := c.Find(bson.M{"_id": id}).One(&user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetUsers(query []bson.M) ([]*models.User, error) {
|
||||
s := db.Session.Copy()
|
||||
defer s.Close()
|
||||
|
||||
c := s.DB("").C("user")
|
||||
|
||||
var users []*models.User
|
||||
|
||||
err := c.Pipe(query).All(&users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
name: username/func-blog
|
||||
build:
|
||||
- ./build.sh
|
||||
@@ -1,90 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fnproject/fn/examples/blog/database"
|
||||
"github.com/fnproject/fn/examples/blog/models"
|
||||
"github.com/fnproject/fn/examples/blog/routes"
|
||||
)
|
||||
|
||||
var noAuth = map[string]interface{}{}
|
||||
|
||||
func main() {
|
||||
request := fmt.Sprintf("%s %s", os.Getenv("FN_METHOD"), os.Getenv("FN_PATH"))
|
||||
|
||||
dbURI := os.Getenv("DB")
|
||||
if dbURI == "" {
|
||||
dbURI = "127.0.0.1/blog"
|
||||
}
|
||||
db := database.New(dbURI)
|
||||
|
||||
if created := createUser(db); created {
|
||||
return
|
||||
}
|
||||
|
||||
// PUBLIC REQUESTS
|
||||
switch request {
|
||||
case "GET /posts":
|
||||
route.HandlePostList(db, noAuth)
|
||||
return
|
||||
case "GET /posts/:id":
|
||||
route.HandlePostRead(db, noAuth)
|
||||
return
|
||||
}
|
||||
|
||||
// GETTING TOKEN
|
||||
if os.Getenv("FN_PATH") == "/token" {
|
||||
route.HandleToken(db)
|
||||
return
|
||||
}
|
||||
|
||||
// AUTHENTICATION
|
||||
auth, valid := route.Authentication()
|
||||
if !valid {
|
||||
route.SendError("Invalid authentication")
|
||||
return
|
||||
}
|
||||
|
||||
// AUTHENTICATED ONLY REQUESTS
|
||||
if request == "POST /posts" {
|
||||
route.HandlePostCreate(db, auth)
|
||||
return
|
||||
}
|
||||
|
||||
route.SendError("Not found")
|
||||
}
|
||||
|
||||
func createUser(db *database.Database) bool {
|
||||
env := os.Getenv("NEWUSER")
|
||||
|
||||
if env == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
var user *models.User
|
||||
err := json.Unmarshal([]byte(env), &user)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return true
|
||||
}
|
||||
|
||||
if user.Username == "" || user.NewPassword == "" {
|
||||
fmt.Println("missing username or password")
|
||||
return true
|
||||
}
|
||||
|
||||
user.Password = []byte(user.NewPassword)
|
||||
user.NewPassword = ""
|
||||
|
||||
user, err = db.SaveUser(user)
|
||||
if err != nil {
|
||||
fmt.Println("couldn't create user")
|
||||
} else {
|
||||
fmt.Println("user created")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
18
examples/blog/glide.lock
generated
18
examples/blog/glide.lock
generated
@@ -1,18 +0,0 @@
|
||||
hash: 5ed6b2d92ab59777802bcfbd57690d5cfb128160bca6cfa799abeb28a8baad4d
|
||||
updated: 2016-11-01T02:15:49.751792317Z
|
||||
imports:
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: d2709f9f1f31ebcda9651b03077758c1f3a0018c
|
||||
- name: golang.org/x/crypto
|
||||
version: 9477e0b78b9ac3d0b03822fd95422e2fe07627cd
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- blowfish
|
||||
- name: gopkg.in/mgo.v2
|
||||
version: 3f83fa5005286a7fe593b055f0d7771a7dce4655
|
||||
subpackages:
|
||||
- bson
|
||||
- internal/json
|
||||
- internal/sasl
|
||||
- internal/scram
|
||||
testImports: []
|
||||
@@ -1,10 +0,0 @@
|
||||
package: github.com/fnproject/functions/examples/blog
|
||||
import:
|
||||
- package: github.com/dgrijalva/jwt-go
|
||||
version: ^3.0.0
|
||||
- package: golang.org/x/crypto
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- package: gopkg.in/mgo.v2
|
||||
subpackages:
|
||||
- bson
|
||||
@@ -1,10 +0,0 @@
|
||||
package models
|
||||
|
||||
import "gopkg.in/mgo.v2/bson"
|
||||
|
||||
type Post struct {
|
||||
ID bson.ObjectId `json:"id" bson:"_id,omitempty"`
|
||||
Title string `json:"title" bson:"title"`
|
||||
Body string `json:"body" bson:"body"`
|
||||
User string `json:"user" bsom:"user"`
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package models
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username" bson:"_id,omitempty"`
|
||||
Password []byte `json:"-" bson:"password"`
|
||||
NewPassword string `json:"password" bson:"-"`
|
||||
}
|
||||
|
||||
func UserPasswordEncrypt(pass []byte) []byte {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword(pass, bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return hashedPassword
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fnproject/fn/examples/blog/database"
|
||||
"github.com/fnproject/fn/examples/blog/models"
|
||||
)
|
||||
|
||||
func HandlePostCreate(db *database.Database, auth map[string]interface{}) {
|
||||
var post *models.Post
|
||||
|
||||
if err := json.NewDecoder(os.Stdin).Decode(&post); err != nil {
|
||||
fmt.Printf("Couldn't decode post JSON: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
post, err := db.SavePost(post)
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't save that post")
|
||||
return
|
||||
}
|
||||
|
||||
post.User = auth["user"].(string)
|
||||
|
||||
SendResponse(Response{
|
||||
"post": post,
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/fnproject/fn/examples/blog/database"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
func HandlePostList(db *database.Database, auth map[string]interface{}) {
|
||||
posts, err := db.GetPosts([]bson.M{})
|
||||
if err != nil {
|
||||
SendError("Couldn't retrieve posts")
|
||||
return
|
||||
}
|
||||
|
||||
SendResponse(Response{
|
||||
"posts": posts,
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/fnproject/fn/examples/blog/database"
|
||||
)
|
||||
|
||||
func HandlePostRead(db *database.Database, auth map[string]interface{}) {
|
||||
id := os.Getenv("FN_PARAM_ID")
|
||||
|
||||
if id == "" {
|
||||
SendError("Missing post ID")
|
||||
return
|
||||
}
|
||||
|
||||
post, err := db.GetPost(id)
|
||||
if err != nil {
|
||||
SendError("Couldn't retrieve that post")
|
||||
return
|
||||
}
|
||||
|
||||
SendResponse(Response{
|
||||
"post": post,
|
||||
})
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/fnproject/fn/examples/blog/database"
|
||||
"github.com/fnproject/fn/examples/blog/models"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var jwtSignKey = []byte("mysecretblog")
|
||||
|
||||
type Response map[string]interface{}
|
||||
|
||||
func SendResponse(resp Response) {
|
||||
data, _ := json.Marshal(resp)
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
|
||||
func SendError(err interface{}) {
|
||||
SendResponse(Response{
|
||||
"error": err,
|
||||
})
|
||||
}
|
||||
|
||||
func HandleToken(db *database.Database) {
|
||||
var login *models.User
|
||||
|
||||
if err := json.NewDecoder(os.Stdin).Decode(&login); err != nil {
|
||||
fmt.Printf("Couldn't decode login JSON: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.GetUser(login.Username)
|
||||
if err != nil {
|
||||
SendError("Couldn't create a token")
|
||||
return
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(login.NewPassword)); err != nil {
|
||||
SendError("Couldn't create a token")
|
||||
return
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"user": login.Username,
|
||||
"exp": time.Now().Add(1 * time.Hour),
|
||||
})
|
||||
|
||||
// Sign and get the complete encoded token as a string using the secret
|
||||
tokenString, err := token.SignedString(jwtSignKey)
|
||||
if err != nil {
|
||||
SendError("Couldn't create a token")
|
||||
return
|
||||
}
|
||||
|
||||
SendResponse(Response{"token": tokenString})
|
||||
}
|
||||
|
||||
func Authentication() (map[string]interface{}, bool) {
|
||||
authorization := os.Getenv("FN_HEADER_AUTHORIZATION")
|
||||
|
||||
p := strings.Split(authorization, " ")
|
||||
if len(p) <= 1 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
token, err := jwt.Parse(p[1], func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return jwtSignKey, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
return claims, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
./build.sh
|
||||
|
||||
# test it
|
||||
docker stop test-mongo-func
|
||||
docker rm test-mongo-func
|
||||
|
||||
docker run -p 27017:27017 --name test-mongo-func -d mongo
|
||||
|
||||
echo '{ "title": "My New Post", "body": "Hello world!", "user": "test" }' | docker run --rm -i -e FN_METHOD=POST -e FN_PATH=/posts -e DB=mongo:27017 --link test-mongo-func:mongo -e TEST=1 username/func-blog
|
||||
docker run --rm -i -e FN_METHOD=GET -e FN_PATH=/posts -e DB=mongo:27017 --link test-mongo-func:mongo -e TEST=1 username/func-blog
|
||||
|
||||
docker stop test-mongo-func
|
||||
docker rm test-mongo-func
|
||||
@@ -1,5 +0,0 @@
|
||||
EXAMPLE=`pwd`
|
||||
|
||||
cd ..
|
||||
docker build -f Dockerfile.glide -t glide .
|
||||
cd $EXAMPLE
|
||||
@@ -1,5 +0,0 @@
|
||||
:9000 {
|
||||
proxy / {$LB_HOST01} {$LB_HOST02} {$LB_HOST03} {
|
||||
policy least_conn
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
# Fn Load Balance example using Caddy
|
||||
|
||||
Simple example of Fn load balancer using Caddy Server
|
||||
|
||||
|
||||
## Run Fn
|
||||
|
||||
Start the Fn instances
|
||||
|
||||
Ref: https://github.com/fnproject/functions/blob/master/README.md#start-the-functions-api
|
||||
|
||||
|
||||
## Configure environment variable
|
||||
|
||||
Pass the host and port of Fn instances in environment variables,
|
||||
this example uses three Fn instances.
|
||||
|
||||
```sh
|
||||
export LB_HOST01="172.17.0.1:8080"
|
||||
export LB_HOST02="172.17.0.1:8081"
|
||||
export LB_HOST03="172.17.0.1:8082"
|
||||
```
|
||||
|
||||
Note: Caddy doesn't support multiple hosts in only one variable.
|
||||
|
||||
|
||||
## Run Caddy
|
||||
|
||||
```sh
|
||||
docker run --rm \
|
||||
-v $PWD/Caddyfile:/etc/Caddyfile \
|
||||
-e LB_HOST01=$LB_HOST01 -e LB_HOST02=$LB_HOST02 -e LB_HOST03=$LB_HOST03 \
|
||||
-p 9000:9000 \
|
||||
abiosoft/caddy
|
||||
```
|
||||
|
||||
## Execute a function
|
||||
|
||||
Follow the Quick-Start steps replacing the example hosts by the Caddy host (localhost:9000)
|
||||
|
||||
https://github.com/fnproject/functions/blob/master/README.md#quick-start
|
||||
|
||||
|
||||
## Docker Compose example
|
||||
|
||||
This is an additional example.
|
||||
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
|
||||
## Caddy Reference:
|
||||
|
||||
* https://github.com/mholt/caddy
|
||||
* https://caddyserver.com/
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
0.0.1
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
docker-compose up
|
||||
@@ -1,23 +0,0 @@
|
||||
functions01:
|
||||
restart: always
|
||||
image: fnproject/functions
|
||||
functions02:
|
||||
restart: always
|
||||
image: fnproject/functions
|
||||
functions03:
|
||||
restart: always
|
||||
image: fnproject/functions
|
||||
caddy:
|
||||
image: abiosoft/caddy
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/Caddyfile
|
||||
ports:
|
||||
- "9000:9000"
|
||||
environment:
|
||||
- LB_HOST01=functions01:8080
|
||||
- LB_HOST02=functions02:8080
|
||||
- LB_HOST03=functions03:8080
|
||||
links:
|
||||
- functions01
|
||||
- functions02
|
||||
- functions03
|
||||
@@ -1,3 +0,0 @@
|
||||
name: username/func-caddy-lb
|
||||
build:
|
||||
- ./build.sh
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
2
examples/checker/.gitignore
vendored
2
examples/checker/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
bundle/
|
||||
.bundle/
|
||||
@@ -1,9 +0,0 @@
|
||||
FROM fnproject/ruby:dev
|
||||
|
||||
WORKDIR /function
|
||||
ADD Gemfile* /function/
|
||||
RUN bundle install
|
||||
|
||||
ADD . /function/
|
||||
|
||||
ENTRYPOINT ["ruby", "function.rb"]
|
||||
@@ -1,3 +0,0 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'json', '> 1.8.2'
|
||||
@@ -1,78 +0,0 @@
|
||||
# Environment Checker Function Image
|
||||
|
||||
This images compares the payload info with the header.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Fn API
|
||||
|
||||
## Development
|
||||
|
||||
### Building image locally
|
||||
|
||||
```
|
||||
# SET BELOW TO YOUR DOCKER HUB USERNAME
|
||||
USERNAME=YOUR_DOCKER_HUB_USERNAME
|
||||
|
||||
# build it
|
||||
./build.sh
|
||||
```
|
||||
|
||||
### Publishing to DockerHub
|
||||
|
||||
```
|
||||
# tagging
|
||||
docker run --rm -v "$PWD":/app treeder/bump patch
|
||||
docker tag $USERNAME/func-checker:latest $USERNAME/func-checker:`cat VERSION`
|
||||
|
||||
# pushing to docker hub
|
||||
docker push $USERNAME/func-checker
|
||||
```
|
||||
|
||||
### Testing image
|
||||
|
||||
```
|
||||
./test.sh
|
||||
```
|
||||
|
||||
## Running it on Fn
|
||||
|
||||
### Let's define some environment variables
|
||||
|
||||
```
|
||||
# Set your Function server address
|
||||
# Eg. 127.0.0.1:8080
|
||||
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
|
||||
```
|
||||
|
||||
### Running with Fn
|
||||
|
||||
With this command we are going to create an application with name `checker`.
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"app": {
|
||||
"name": "checker",
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps
|
||||
```
|
||||
|
||||
Now, we can create our route
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-checker",
|
||||
"path": "/check",
|
||||
"config": { "TEST": "1" }
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/checker/routes
|
||||
```
|
||||
|
||||
#### Testing function
|
||||
|
||||
Now that we created our Fn route, let's test our new route
|
||||
|
||||
```
|
||||
curl -X POST --data '{ "env_vars": { "test": "1" } }' http://$FUNCAPI/r/checker/check
|
||||
```
|
||||
@@ -1,4 +0,0 @@
|
||||
name: username/func-checker
|
||||
version: 0.0.1
|
||||
entrypoint: ruby function.rb
|
||||
runtime: ruby
|
||||
@@ -1,41 +0,0 @@
|
||||
require 'json'
|
||||
require 'uri'
|
||||
|
||||
puts "Running checker..."
|
||||
|
||||
payload = STDIN.read
|
||||
puts "payload #{payload}"
|
||||
p ENV
|
||||
if payload != ""
|
||||
payload = JSON.parse(payload)
|
||||
|
||||
# payload contains checks
|
||||
if payload["env_vars"]
|
||||
payload["env_vars"].each do |k,v|
|
||||
if ENV[k] != v
|
||||
raise "Env var #{k} does not match"
|
||||
end
|
||||
end
|
||||
end
|
||||
puts "all good"
|
||||
end
|
||||
|
||||
# Also check for expected env vars: https://github.com/fnproject/fn/blob/master/docs/writing.md#inputs
|
||||
e = ENV["FN_REQUEST_URL"]
|
||||
puts e
|
||||
uri = URI.parse(e)
|
||||
if !uri.scheme.start_with?('http')
|
||||
raise "invalid REQUEST_URL, does not start with http"
|
||||
end
|
||||
e = ENV["FN_METHOD"]
|
||||
if !(e == "GET" || e == "POST" || e == "DELETE" || e == "PATCH" || e == "PUT")
|
||||
raise "Invalid METHOD: #{e}"
|
||||
end
|
||||
e = ENV["FN_APP_NAME"]
|
||||
if e == nil || e == ''
|
||||
raise "No APP_NAME found"
|
||||
end
|
||||
e = ENV["FN_PATH"]
|
||||
if e == nil || e == ''
|
||||
raise "No ROUTE found"
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
PAYLOAD='{"env_vars": {"FOO": "bar"}}'
|
||||
|
||||
# test it
|
||||
: ${FN:="fn"}
|
||||
echo $PAYLOAD | $FN run -e FOO=bar
|
||||
2
examples/echo/.gitignore
vendored
2
examples/echo/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
bundle/
|
||||
.bundle/
|
||||
@@ -1,9 +0,0 @@
|
||||
FROM fnproject/ruby:dev
|
||||
|
||||
WORKDIR /function
|
||||
ADD Gemfile /function/
|
||||
RUN bundle install
|
||||
|
||||
ADD . /function/
|
||||
|
||||
ENTRYPOINT ["ruby", "function.rb"]
|
||||
@@ -1,3 +0,0 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'json', '> 1.8.2'
|
||||
@@ -1,77 +0,0 @@
|
||||
# Echo Function Image
|
||||
|
||||
This images compares the payload info with the header.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Fn API
|
||||
|
||||
## Development
|
||||
|
||||
### Building image locally
|
||||
|
||||
```
|
||||
# SET BELOW TO YOUR DOCKER HUB USERNAME
|
||||
USERNAME=YOUR_DOCKER_HUB_USERNAME
|
||||
|
||||
# build it
|
||||
./build.sh
|
||||
```
|
||||
|
||||
### Publishing to DockerHub
|
||||
|
||||
```
|
||||
# tagging
|
||||
docker run --rm -v "$PWD":/app treeder/bump patch
|
||||
docker tag $USERNAME/func-echo:latest $USERNAME/func-echo:`cat VERSION`
|
||||
|
||||
# pushing to docker hub
|
||||
docker push $USERNAME/func-echo
|
||||
```
|
||||
|
||||
### Testing image
|
||||
|
||||
```
|
||||
./test.sh
|
||||
```
|
||||
|
||||
## Running it on Fn
|
||||
|
||||
### Let's define some environment variables
|
||||
|
||||
```
|
||||
# Set your Function server address
|
||||
# Eg. 127.0.0.1:8080
|
||||
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
|
||||
```
|
||||
|
||||
### Running with Fn
|
||||
|
||||
With this command we are going to create an application with name `echo`.
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"app": {
|
||||
"name": "echo",
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps
|
||||
```
|
||||
|
||||
Now, we can create our route
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-echo",
|
||||
"path": "/echo",
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/echo/routes
|
||||
```
|
||||
|
||||
#### Testing function
|
||||
|
||||
Now that we created our Fn route, let's test our new route
|
||||
|
||||
```
|
||||
curl -X POST --data '{"input": "yoooo"}' http://$FUNCAPI/r/echo/echo
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
0.0.1
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
# build image
|
||||
docker build -t username/func-echo .
|
||||
@@ -1,3 +0,0 @@
|
||||
name: username/func-echo
|
||||
build:
|
||||
- ./build.sh
|
||||
@@ -1,11 +0,0 @@
|
||||
require 'json'
|
||||
|
||||
payload = STDIN.read
|
||||
if payload != ""
|
||||
payload = JSON.parse(payload)
|
||||
|
||||
# payload contains checks
|
||||
if payload["input"]
|
||||
puts payload["input"]
|
||||
end
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
./build.sh
|
||||
|
||||
PAYLOAD='{"input": "yoooo"}'
|
||||
|
||||
# test it
|
||||
echo $PAYLOAD | docker run --rm -i -e TEST=1 username/func-echo
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM fnproject/go:dev as build-stage
|
||||
WORKDIR /function
|
||||
ADD . /src
|
||||
RUN cd /src && go build -o func
|
||||
FROM fnproject/go
|
||||
WORKDIR /function
|
||||
COPY --from=build-stage /src/func /function/
|
||||
ENTRYPOINT ["./func"]
|
||||
@@ -1,28 +0,0 @@
|
||||
# Hot Function Example
|
||||
|
||||
This is an example of a hot function. The [hot function documentation](/docs/hot-functions.md) contains an analysis of how this example works.
|
||||
|
||||
Note that you should probably be using the [fdk](https://github.com/fnproject/fdk-go) but this serves
|
||||
as a good example of how to do a hot functions raw without the fdk.
|
||||
|
||||
### How to run the example
|
||||
|
||||
Install the CLI tool, start a Fn server and run `docker login` to login to DockerHub. See the [front page](/README.md) for instructions.
|
||||
|
||||
Set your Docker Hub username
|
||||
|
||||
```sh
|
||||
export FN_REGISTRY=<DOCKERHUB_USERNAME>
|
||||
```
|
||||
|
||||
Build and deploy the function to the Fn server (default localhost:8080)
|
||||
|
||||
```sh
|
||||
fn deploy --app hot-app
|
||||
```
|
||||
|
||||
Now call your function:
|
||||
|
||||
```sh
|
||||
curl -X POST -d "World" http://localhost:8080/r/hot-app/hotfn-go
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for {
|
||||
res := http.Response{
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
StatusCode: 200,
|
||||
Status: "OK",
|
||||
}
|
||||
|
||||
r := bufio.NewReader(os.Stdin)
|
||||
req, err := http.ReadRequest(r)
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err != nil {
|
||||
res.StatusCode = 500
|
||||
res.Status = http.StatusText(res.StatusCode)
|
||||
fmt.Fprintln(&buf, err)
|
||||
} else {
|
||||
l, _ := strconv.Atoi(req.Header.Get("Content-Length"))
|
||||
p := make([]byte, l)
|
||||
r.Read(p)
|
||||
fmt.Fprintf(&buf, "Hello %s\n", p)
|
||||
for k, vs := range req.Header {
|
||||
fmt.Fprintf(&buf, "ENV: %s %#v\n", k, vs)
|
||||
}
|
||||
}
|
||||
|
||||
res.Body = ioutil.NopCloser(&buf)
|
||||
res.ContentLength = int64(buf.Len())
|
||||
res.Write(os.Stdout)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
name: fnproject/hot-http-go
|
||||
version: 0.0.1
|
||||
runtime: docker
|
||||
type: sync
|
||||
memory: 521
|
||||
format: http
|
||||
path: /hot-http-go
|
||||
@@ -1,21 +0,0 @@
|
||||
import fdk
|
||||
|
||||
|
||||
@fdk.coerce_http_input_to_content_type
|
||||
def app(context, data=None, loop=None):
|
||||
"""
|
||||
User's request body handler
|
||||
:param context: request context
|
||||
:type context: hotfn.http.request.RequestContext
|
||||
:param data: request body, it's type depends on request Content-Type header
|
||||
:type data: object
|
||||
:param loop: asyncio event loop
|
||||
:type loop asyncio.AbstractEventLoop
|
||||
:return: echo of data
|
||||
:rtype: object
|
||||
"""
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fdk.handle(app)
|
||||
@@ -1,7 +0,0 @@
|
||||
name: fnproject/hot-http-python
|
||||
version: 0.0.1
|
||||
runtime: python3.6.2
|
||||
type: sync
|
||||
memory: 521
|
||||
format: http
|
||||
path: /hot-http-python
|
||||
@@ -1,2 +0,0 @@
|
||||
fdk==0.0.1
|
||||
uvloop==0.8.1
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM fnproject/go:dev as build-stage
|
||||
WORKDIR /function
|
||||
ADD . /src
|
||||
RUN cd /src && go build -o func
|
||||
FROM fnproject/go
|
||||
WORKDIR /function
|
||||
COPY --from=build-stage /src/func /function/
|
||||
ENTRYPOINT ["./func"]
|
||||
@@ -1,3 +0,0 @@
|
||||
# Go using JSON format
|
||||
|
||||
This example uses the `json` input format.
|
||||
@@ -1,69 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type JSON struct {
|
||||
Headers http.Header `json:"headers"`
|
||||
Body string `json:"body,omitempty"`
|
||||
StatusCode int `json:"status,omitempty"`
|
||||
QueryParameters string `json:"query_parameters,omitempty"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
stdin := json.NewDecoder(os.Stdin)
|
||||
stdout := json.NewEncoder(os.Stdout)
|
||||
stderr := json.NewEncoder(os.Stderr)
|
||||
for {
|
||||
in := &JSON{}
|
||||
|
||||
err := stdin.Decode(in)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to decode incoming data: %s", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
}
|
||||
person := Person{}
|
||||
stderr.Encode(in.Body)
|
||||
if len(in.Body) != 0 {
|
||||
if err := json.NewDecoder(bytes.NewReader([]byte(in.Body))).Decode(&person); err != nil {
|
||||
log.Fatalf("Unable to decode Person object data: %s", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
if person.Name == "" {
|
||||
person.Name = "World"
|
||||
}
|
||||
|
||||
mapResult := map[string]string{"message": fmt.Sprintf("Hello %s", person.Name)}
|
||||
b, err := json.Marshal(mapResult)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to marshal JSON response body: %s", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
}
|
||||
h := http.Header{}
|
||||
h.Set("Content-Type", "application/json")
|
||||
h.Set("Content-Length", strconv.Itoa(len(b)))
|
||||
out := &JSON{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: string(b),
|
||||
Headers: h,
|
||||
}
|
||||
stderr.Encode(out)
|
||||
if err := stdout.Encode(out); err != nil {
|
||||
log.Fatalf("Unable to encode JSON response: %s", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
name: fnproject/hot-json-go
|
||||
version: 0.0.1
|
||||
runtime: docker
|
||||
type: sync
|
||||
memory: 256
|
||||
format: json
|
||||
path: /hot-json-go
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"name": "Johnny"
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"body": {
|
||||
"name": "Johnny"
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"body": {
|
||||
"message": "Hello Johnny"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"body": ""
|
||||
},
|
||||
"output": {
|
||||
"body": {
|
||||
"message": "Hello World"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import fdk
|
||||
|
||||
|
||||
def handler(context, data=None, loop=None):
|
||||
"""
|
||||
This is just an echo function
|
||||
:param context: request context
|
||||
:type context: hotfn.http.request.RequestContext
|
||||
:param data: request body
|
||||
:type data: object
|
||||
:param loop: asyncio event loop
|
||||
:type loop: asyncio.AbstractEventLoop
|
||||
:return: echo of request body
|
||||
:rtype: object
|
||||
"""
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
fdk.handle(handler)
|
||||
@@ -1,7 +0,0 @@
|
||||
name: fnproject/hot-json-python
|
||||
version: 0.0.1
|
||||
runtime: python3.6.2
|
||||
type: sync
|
||||
memory: 256
|
||||
format: json
|
||||
path: /hot-json-python
|
||||
@@ -1 +0,0 @@
|
||||
fdk==0.0.1
|
||||
@@ -1,6 +1,6 @@
|
||||
# Tutorial 1: Go Function w/ Input (3 minutes)
|
||||
|
||||
Example for putting required vars into the func.yaml file.
|
||||
Example for using required and optional environment variables defined in the func.yaml file.
|
||||
|
||||
Try running the following:
|
||||
|
||||
|
||||
4
examples/postgres/.gitignore
vendored
4
examples/postgres/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
/func
|
||||
vendor
|
||||
|
||||
func.yaml
|
||||
@@ -1,25 +0,0 @@
|
||||
# Postgres INSERT/SELECT Function Image
|
||||
|
||||
This function executes an INSERT or SELECT against a table in a given postgres server.
|
||||
|
||||
```
|
||||
# Create your func.yaml file
|
||||
fn init --name func-postgres
|
||||
# Build the function
|
||||
fn build
|
||||
# Test it
|
||||
./test.sh
|
||||
# Push it to Docker Hub
|
||||
fn push
|
||||
# Create routes to this function on Fn
|
||||
fn apps create <YOUR_APP> --config SERVER=<POSTGRES>
|
||||
fn routes create --config TABLE=<TABLE_NAME> --config COMMAND=INSERT <YOUR_APP> /<TABLE_NAME>/insert
|
||||
fn routes create --config TABLE=<TABLE_NAME> --config COMMAND=SELECT <YOUR_APP> /<TABLE_NAME>/select
|
||||
```
|
||||
|
||||
Now you can call your function on Fn:
|
||||
|
||||
```
|
||||
echo <JSON_RECORD> | fn call /<YOUR_APP>/<TABLE_NAME>/insert
|
||||
echo <JSON_QUERY> | fn call /<YOUR_APP>/<TABLE_NAME>/select
|
||||
```
|
||||
@@ -1,103 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
var (
|
||||
// command to execute, 'SELECT' or 'INSERT'
|
||||
command = os.Getenv("FN_HEADER_COMMAND")
|
||||
// postgres host:port, e.g. 'postgres:5432'
|
||||
server = os.Getenv("FN_HEADER_SERVER")
|
||||
// postgres table name
|
||||
table = os.Getenv("FN_HEADER_TABLE")
|
||||
)
|
||||
|
||||
func main() {
|
||||
req, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
log.Fatal(errors.Wrap(err, "failed to read stdin"))
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", "postgres://postgres@"+server+"?sslmode=disable")
|
||||
if err != nil {
|
||||
log.Println("Failed to connect to postgres server")
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch command {
|
||||
case "SELECT":
|
||||
if resp, err := selectCommand(req, db); err != nil {
|
||||
log.Fatal(errors.Wrap(err, "select command failed"))
|
||||
} else {
|
||||
log.Println(resp)
|
||||
}
|
||||
case "INSERT":
|
||||
if err := insertCommand(req, db); err != nil {
|
||||
log.Fatal(errors.Wrap(err, "insert command failed"))
|
||||
}
|
||||
default:
|
||||
log.Fatalf("invalid command: %q", command)
|
||||
}
|
||||
}
|
||||
|
||||
func selectCommand(req []byte, db *sql.DB) (string, error) {
|
||||
// Parse request JSON
|
||||
var params map[string]interface{}
|
||||
if err := json.Unmarshal(req, ¶ms); err != nil {
|
||||
return "", errors.Wrap(err, "failed to parse json")
|
||||
}
|
||||
|
||||
// Build query and gather arguments
|
||||
var query bytes.Buffer
|
||||
var args []interface{}
|
||||
|
||||
query.WriteString("SELECT json_agg(t) FROM (SELECT * FROM ")
|
||||
query.WriteString(table)
|
||||
query.WriteString(" WHERE")
|
||||
first := true
|
||||
arg := 1
|
||||
for k, v := range params {
|
||||
args = append(args, v)
|
||||
|
||||
if !first {
|
||||
query.WriteString(" AND")
|
||||
}
|
||||
query.WriteString(" ")
|
||||
query.WriteString(k)
|
||||
query.WriteString("=$")
|
||||
query.WriteString(strconv.Itoa(arg))
|
||||
arg += 1
|
||||
first = false
|
||||
}
|
||||
query.WriteString(") AS t")
|
||||
|
||||
// Execute query
|
||||
r := db.QueryRow(query.String(), args...)
|
||||
var resp string
|
||||
if err := r.Scan(&resp); err != nil {
|
||||
return "", errors.Wrap(err, "failed to execute select query")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func insertCommand(req []byte, db *sql.DB) error {
|
||||
q := "INSERT INTO " + table + " SELECT * FROM json_populate_record(null::" + table + ", $1)"
|
||||
_, err := db.Exec(q, req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to execute insert query")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
10
examples/postgres/glide.lock
generated
10
examples/postgres/glide.lock
generated
@@ -1,10 +0,0 @@
|
||||
hash: 12ce0fe3e599891c7aeb6d5a99ff107b4f979e88ff5da7a6d5b1cf5cac8b1ad7
|
||||
updated: 2017-01-20T22:48:30.561728713Z
|
||||
imports:
|
||||
- name: github.com/lib/pq
|
||||
version: 67c3f2a8884c9b1aac5503c8d42ae4f73a93511c
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/pkg/errors
|
||||
version: 248dadf4e9068a0b3e79f02ed0a610d935de5302
|
||||
testImports: []
|
||||
@@ -1,4 +0,0 @@
|
||||
package: github.com/fnproject/functions/examples/postgres
|
||||
import:
|
||||
- package: github.com/lib/pq
|
||||
- package: github.com/pkg/errors
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
docker stop test-postgres-func
|
||||
docker rm test-postgres-func
|
||||
|
||||
docker run -p 5432:5432 --name test-postgres-func -d postgres
|
||||
sleep 5s
|
||||
|
||||
docker run --rm -i --link test-postgres-func:postgres postgres psql -h postgres -U postgres -c 'CREATE TABLE people (first TEXT, last TEXT, age INTEGER);'
|
||||
|
||||
RECORD1='{
|
||||
"first": "John",
|
||||
"last": "Smith",
|
||||
"age": 30
|
||||
}'
|
||||
echo $RECORD1 | fn run -e SERVER=postgres:5432 -e COMMAND=INSERT -e TABLE=people --link test-postgres-func:postgres
|
||||
QUERY1='{
|
||||
"last": "Smith"
|
||||
}'
|
||||
echo $QUERY1 | fn run -e SERVER=postgres:5432 -e COMMAND=SELECT -e TABLE=people --link test-postgres-func:postgres
|
||||
|
||||
RECORD2='{
|
||||
"first": "Bob",
|
||||
"last": "Smith",
|
||||
"age": 43
|
||||
}'
|
||||
echo $RECORD2 | fn run -e SERVER=postgres:5432 -e COMMAND=INSERT -e TABLE=people --link test-postgres-func:postgres
|
||||
|
||||
echo $QUERY1 | fn run -e SERVER=postgres:5432 -e COMMAND=SELECT -e TABLE=people --link test-postgres-func:postgres
|
||||
|
||||
QUERY2='{
|
||||
"first": "John",
|
||||
"last": "Smith"
|
||||
}'
|
||||
echo $QUERY2 | fn run -e SERVER=postgres:5432 -e COMMAND=SELECT -e TABLE=people --link test-postgres-func:postgres
|
||||
|
||||
docker stop test-postgres-func
|
||||
docker rm test-postgres-func
|
||||
2
examples/redis/.gitignore
vendored
2
examples/redis/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
/func
|
||||
vendor
|
||||
@@ -1,5 +0,0 @@
|
||||
FROM fnproject/go
|
||||
|
||||
ADD func .
|
||||
|
||||
ENTRYPOINT ["./func"]
|
||||
@@ -1,111 +0,0 @@
|
||||
# Redis GET/SET Function Image
|
||||
|
||||
This function basically executes a GET/SET in a given redis server.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Redis Server
|
||||
- Functions API
|
||||
|
||||
## Development
|
||||
|
||||
### Building image locally
|
||||
|
||||
```
|
||||
# SET BELOW TO YOUR DOCKER HUB USERNAME
|
||||
USERNAME=YOUR_DOCKER_HUB_USERNAME
|
||||
|
||||
# build it
|
||||
./build.sh
|
||||
```
|
||||
|
||||
### Publishing to DockerHub
|
||||
|
||||
```
|
||||
# tagging
|
||||
docker run --rm -v "$PWD":/app treeder/bump patch
|
||||
docker tag $USERNAME/func-redis:latest $USERNAME/func-redis:`cat VERSION`
|
||||
|
||||
# pushing to docker hub
|
||||
docker push $USERNAME/func-redis
|
||||
```
|
||||
|
||||
### Testing image
|
||||
|
||||
```
|
||||
./test.sh
|
||||
```
|
||||
|
||||
## Running it on Fn
|
||||
|
||||
### Let's define some environment variables
|
||||
|
||||
```
|
||||
# Set your Function server address
|
||||
# Eg. 127.0.0.1:8080
|
||||
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
|
||||
|
||||
# Set your Redis server address
|
||||
# Eg. redis:6379
|
||||
REDIS=YOUR_REDIS_ADDRESS
|
||||
|
||||
# Set your Redis server auth (if required)
|
||||
REDIS_AUTH=REDIS_AUTH_KEY
|
||||
```
|
||||
|
||||
### Running with Fn
|
||||
|
||||
With this command we are going to create an application with name `redis`.
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"app": {
|
||||
"name": "redis",
|
||||
"config": {
|
||||
"server": "'$REDIS'"
|
||||
"redis_auth": "'$REDIS_AUTH'"
|
||||
}
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps
|
||||
```
|
||||
|
||||
Now, we can create our routes
|
||||
|
||||
#### Route for set value
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-redis",
|
||||
"path": "/redis",
|
||||
"config": {
|
||||
"command": "SET"
|
||||
}
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/redis/routes
|
||||
```
|
||||
|
||||
#### Route for get value
|
||||
|
||||
```
|
||||
curl -X POST --data '{
|
||||
"route": {
|
||||
"image": "'$USERNAME'/func-redis",
|
||||
"path": "/redis",
|
||||
"config": {
|
||||
"command": "GET"
|
||||
}
|
||||
}
|
||||
}' http://$FUNCAPI/v1/apps/redis/routes
|
||||
```
|
||||
|
||||
#### Testing function
|
||||
|
||||
Now that we created our Fn route, let's test our new route
|
||||
|
||||
```
|
||||
curl -X POST --data '{"key": "name", "value": "Johnny"}' http://$FUNCAPI/r/redis/set
|
||||
// "OK"
|
||||
curl -X POST --data '{"key": "name"}' http://$FUNCAPI/r/redis/get
|
||||
// "Johnny"
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
0.0.1
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
FUNCPKG=$(pwd | sed "s|$GOPATH/src/||")
|
||||
|
||||
# glide image to install dependencies
|
||||
../build-glide.sh
|
||||
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG glide up
|
||||
|
||||
# build image
|
||||
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG fnproject/go:dev go build -o func
|
||||
docker build -t username/func-redis .
|
||||
@@ -1,3 +0,0 @@
|
||||
name: username/func-redis
|
||||
build:
|
||||
- ./build.sh
|
||||
@@ -1,76 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type payload struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Getting stdin
|
||||
plStdin, _ := ioutil.ReadAll(os.Stdin)
|
||||
|
||||
// Transforming JSON to a *payload
|
||||
var pl payload
|
||||
err := json.Unmarshal(plStdin, &pl)
|
||||
if err != nil {
|
||||
log.Println("Invalid payload")
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Dialing redis server
|
||||
c, err := redis.Dial("tcp", os.Getenv("SERVER"))
|
||||
if err != nil {
|
||||
log.Println("Failed to dial redis server")
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Authenticate to redis server if exists the password
|
||||
if os.Getenv("REDIS_AUTH") != "" {
|
||||
if _, err := c.Do("AUTH", os.Getenv("REDIS_AUTH")); err != nil {
|
||||
log.Println("Failed to authenticate to redis server")
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check if payload command is valid
|
||||
if os.Getenv("COMMAND") != "GET" && os.Getenv("COMMAND") != "SET" {
|
||||
log.Println("Invalid command")
|
||||
return
|
||||
}
|
||||
|
||||
// Execute command on redis server
|
||||
var r interface{}
|
||||
if os.Getenv("COMMAND") == "GET" {
|
||||
r, err = c.Do("GET", pl.Key)
|
||||
} else if os.Getenv("COMMAND") == "SET" {
|
||||
r, err = c.Do("SET", pl.Key, pl.Value)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Println("Failed to execute command on redis server")
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert reply to string
|
||||
res, err := redis.String(r, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Print reply
|
||||
fmt.Println(res)
|
||||
}
|
||||
9
examples/redis/glide.lock
generated
9
examples/redis/glide.lock
generated
@@ -1,9 +0,0 @@
|
||||
hash: 8c667282524602aac09a157244397d581f19d256b95a725a4782ab3c67ebb08a
|
||||
updated: 2016-11-01T02:56:55.36346607Z
|
||||
imports:
|
||||
- name: github.com/garyburd/redigo
|
||||
version: 8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13
|
||||
subpackages:
|
||||
- internal
|
||||
- redis
|
||||
testImports: []
|
||||
@@ -1,6 +0,0 @@
|
||||
package: github.com/fnproject/functions/examples/redis
|
||||
import:
|
||||
- package: github.com/garyburd/redigo
|
||||
version: ^1.0.0
|
||||
subpackages:
|
||||
- redis
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
./build.sh
|
||||
|
||||
PAYLOAD='{
|
||||
"key": "test",
|
||||
"value": "123"
|
||||
}'
|
||||
|
||||
# test it
|
||||
docker stop test-redis-func
|
||||
docker rm test-redis-func
|
||||
|
||||
docker run -p 6379:6379 --name test-redis-func -d redis
|
||||
|
||||
echo $PAYLOAD | docker run --rm -i -e SERVER=redis:6379 -e COMMAND=SET --link test-redis-func:redis username/func-redis
|
||||
echo $PAYLOAD | docker run --rm -i -e SERVER=redis:6379 -e COMMAND=GET --link test-redis-func:redis username/func-redis
|
||||
|
||||
docker stop test-redis-func
|
||||
docker rm test-redis-func
|
||||
@@ -1,5 +0,0 @@
|
||||
FROM username/lambda-nodejs
|
||||
|
||||
ADD example.js ./example.js
|
||||
|
||||
CMD ["example.run"]
|
||||
@@ -1,7 +0,0 @@
|
||||
IMAGE=username/lambda-node-aws-example
|
||||
|
||||
create: Dockerfile
|
||||
docker build -t $(IMAGE) .
|
||||
|
||||
test:
|
||||
docker run --rm -it -e PAYLOAD_FILE=/mnt/example-payload.json -e AWS_ACCESS_KEY_ID=change-here -e AWS_SECRET_ACCESS_KEY=change-here -v `pwd`:/mnt $(IMAGE)
|
||||
@@ -1,2 +0,0 @@
|
||||
Example on how to use AWS S3 in a lambda function.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"bucket": "iron-lambda-demo-images",
|
||||
"srcKey": "waterfall.jpg",
|
||||
"dstKey": "waterfall-1024.jpg"
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
var im = require('imagemagick');
|
||||
var fs = require('fs');
|
||||
var AWS = require('aws-sdk');
|
||||
|
||||
// cb(err, resized) is called with true if resized.
|
||||
function resizeIfRequired(err, features, fileSrc, fileDst, cb) {
|
||||
if (err) {
|
||||
cb(err, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var targetWidth = 1024;
|
||||
if (features.width > targetWidth)
|
||||
{
|
||||
im.resize({
|
||||
srcPath : fileSrc,
|
||||
dstPath : fileDst,
|
||||
width : targetWidth,
|
||||
format: 'jpg'
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
cb(err, false);
|
||||
} else {
|
||||
cb(null, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cb(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
exports.run = function(event, context) {
|
||||
var bucketName = event['bucket']
|
||||
var srcImageKey = event['srcKey']
|
||||
var dstImageKey = event['dstKey']
|
||||
|
||||
var s3 = new AWS.S3();
|
||||
|
||||
s3.getObject({
|
||||
Bucket: bucketName,
|
||||
Key: srcImageKey
|
||||
}, function (err, data) {
|
||||
|
||||
if (err) throw err;
|
||||
|
||||
var fileSrc = '/tmp/image-src.dat';
|
||||
var fileDst = '/tmp/image-dst.dat'
|
||||
fs.writeFileSync(fileSrc, data.Body)
|
||||
|
||||
im.identify(fileSrc, function(err, features) {
|
||||
resizeIfRequired(err, features, fileSrc, fileDst, function(err, resized) {
|
||||
if (err) throw err;
|
||||
if (resized) {
|
||||
s3.putObject({
|
||||
Bucket:bucketName,
|
||||
Key: dstImageKey,
|
||||
Body: fs.createReadStream(fileDst),
|
||||
ContentType: 'image/jpeg',
|
||||
ACL: 'public-read',
|
||||
}, function (err, data) {
|
||||
if (err) throw err;
|
||||
context.succeed("Image updated");
|
||||
});
|
||||
} else {
|
||||
context.succeed("Image not updated");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'httparty', '~> 0.14.0'
|
||||
gem 'slack_webhooks'
|
||||
gem 'json', '> 1.8.2'
|
||||
@@ -1,32 +0,0 @@
|
||||
## Quick Example for a SlackBot command in Ruby
|
||||
|
||||
This example will show you how to test and deploy a SlackBot command to Fn.
|
||||
|
||||
```sh
|
||||
# create your func.yaml file
|
||||
fn init
|
||||
# build the function - install dependencies from json gem
|
||||
fn build
|
||||
# test it
|
||||
cat slack.payload | fn run
|
||||
# push it to Docker Hub
|
||||
fn push
|
||||
# Create a route to this function on Fn
|
||||
fn routes create slackbot /guppy
|
||||
# Change the route response header content-type to application/json
|
||||
fn routes headers set slackbot /guppy Content-Type application/json
|
||||
# test it remotely
|
||||
cat slack.payload | fn call slackbot /guppy
|
||||
```
|
||||
|
||||
## Create a Slash Command integration in Slack
|
||||
|
||||
In Slack, go to Integrations, find Slash Commands, click Add, type in / as the command then click Add again. On the next page, take the Fn route URL and paste it into the URL field then click Save Integration.
|
||||
|
||||
If running in localhost, use [ngrok](https://github.com/inconshreveable/ngrok).
|
||||
|
||||
# Try it out!
|
||||
|
||||
In slack, type /<COMMAND> [options] and you'll see the magic!
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"tableflip": {"image_url": "http://i.imgur.com/oGwPRux.png"},
|
||||
"shrug": {"image_url": "http://www.theblaze.com/wp-content/uploads/2015/03/Google-comment-gif.gif"},
|
||||
"forlorn": {"image_url": "https://lh4.googleusercontent.com/-Jp85Ek_5jJc/UdEYqhHzuLI/AAAAAAACF3s/U708yywLDCQ/w700-h412-no/forlorn%2Bcat.gif"},
|
||||
"beardscratch": {"image_url": "https://lh5.googleusercontent.com/-gfUwQSvd1bs/UjjHeU-b6HI/AAAAAAAC81o/xtMpBn1F87E/w958-h539-no/beardman.gif"},
|
||||
"atlast": {"image_url": "https://lh4.googleusercontent.com/-jzywmNWCPps/UdEYqnq2ECI/AAAAAAACF3w/eNnS_KXHzN0/w480-h226-no/morpheus-at-last.gif"},
|
||||
"ohyeah": {"image_url": "https://lh4.googleusercontent.com/-IqiWUKEzd_U/UnmdxBZp-bI/AAAAAAADFf4/l7dyXzMTdDs/w245-h285-no/code-05.gif"},
|
||||
"facepalm": {"image_url": "https://lh4.googleusercontent.com/-kbD1OZrG7kI/UnmdupWzP1I/AAAAAAADFfg/g3SXEo1JXIs/s300-no/cQEBX.gif"},
|
||||
"peak": {"image_url": "https://lh4.googleusercontent.com/-V9zKyTXHrD4/Unmdzpnb1UI/AAAAAAADFgc/-61luVxML_M/w500-h320-no/efuITnY.gif"},
|
||||
"right": {"image_url": "https://lh6.googleusercontent.com/-vPkV8r6Mhy0/UnmdtC490bI/AAAAAAADFfM/Hil5QyuTX78/w500-h221-no/HuVXfMb.gif"},
|
||||
"sup": {"image_url": "https://lh3.googleusercontent.com/-iqoKtA72rIo/Unmd7o17ZUI/AAAAAAADFhM/7-MLxTAXU7Q/w470-h248-no/yC5BsCS.gif"},
|
||||
"nod": {"image_url": "https://lh4.googleusercontent.com/-byviKRrwH5c/Unny4gWkMqI/AAAAAAADFkc/OckIZqXDCY4/w500-h225-no/iPOS6.gif"},
|
||||
"thumbsup": {"image_url": "https://lh4.googleusercontent.com/-1l8KOia5vis/Unny3Jw851I/AAAAAAADFkY/bRLzh5VyPbc/w312-h176-no/ZCGrZ.gif"},
|
||||
"dance1": {"image_url": "https://lh5.googleusercontent.com/-5sN8WVo6Myc/Unny6ZsWZGI/AAAAAAADFk8/JssUbaDRG_M/w250-h303-no/mbjD3.gif"},
|
||||
"dance2": {"image_url": "https://lh5.googleusercontent.com/-2aPDr_v7Jgc/Unny3pXSfvI/AAAAAAADFkI/KyloHLe5DaM/w400-h234-no/gary.gif"},
|
||||
"dance3": {"image_url": "https://lh5.googleusercontent.com/-rqM2JLfd2xg/Unny2Pvpy1I/AAAAAAADFjY/Zx6D93XEws4/w480-h340-no/1tumblr_lgp6q5NhE21qcjtu8o1_500.gif"},
|
||||
"sidepunch": {"image_url": "https://lh6.googleusercontent.com/-HZYoVvXWc_s/UnmfpjqTbiI/AAAAAAADFic/q3dGlwfxV2w/w500-h247-no/code-27.gif"},
|
||||
"tyrionbird": {"image_url": "https://lh5.googleusercontent.com/-6frbpEP6M3g/Unmfl9i3fcI/AAAAAAADFh8/SOpKxwyOk3k/w300-h149-no/code-19.gif"},
|
||||
"obiwan": {"image_url": "http://i.giphy.com/2vERRTu559XQk.gif"},
|
||||
"wat": {"image_url": "http://i.giphy.com/qxtxlL4sFFle.gif"},
|
||||
"ivan": {"image_url": "http://i.giphy.com/2OMHmoFMiJjfq.gif"},
|
||||
"freakout": {"image_url": "http://i.giphy.com/FwpecpDvcu7vO.gif"},
|
||||
"boom-chuck": {"image_url": "http://i.giphy.com/10PkQyXWagNrqg.gif"},
|
||||
"boom-drake": {"image_url": "http://i.giphy.com/8vW915bv0DqXC.gif"},
|
||||
"boom-dany": {"image_url": "http://i.giphy.com/LrN9NbJNp9SWQ.gif"},
|
||||
"boom-moon": {"image_url": "http://i.giphy.com/ydMNTWYVjSEFi.gif"},
|
||||
"boom-franco": {"image_url": "http://i.giphy.com/b3u8anVaWFQ9G.gif"},
|
||||
"boom-starcraft": {"image_url": "http://i.giphy.com/5xtDarxQ05ee2ktRA5i.gif"},
|
||||
"boom-anime": {"image_url": "http://i.giphy.com/fMNNDKtOVbxSM.gif"},
|
||||
"boom-denzel":{"image_url":"http://i.imgur.com/1LXMDns.gif"},
|
||||
"boom-ump":{"image_url":"http://cdn0.sbnation.com/imported_assets/1160455/umpboom.gif"},
|
||||
"fun": {"image_url": "http://s-ak.buzzfed.com/static/imagebuzz/web04/2011/3/14/10/anigif_fun-fun-fun-29834-1300112565-20.gif"},
|
||||
"fthis": {"image_url": "http://i.giphy.com/iICCUuGJOhOnK.gif"},
|
||||
"disappear": {"image_url": "http://i.giphy.com/4pMX5rJ4PYAEM.gif"},
|
||||
"cry": {"image_url": "http://i.giphy.com/10tIjpzIu8fe0.gif"},
|
||||
"micdrop":{"image_url":"http://i.imgur.com/9XHl18c.gif"}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
require_relative 'bundle/bundler/setup'
|
||||
require 'slack_webhooks'
|
||||
|
||||
payload = STDIN.read
|
||||
#STDERR.puts "PAYLOAD: #{payload}"
|
||||
|
||||
images = JSON.load(File.open('commands.json'))
|
||||
|
||||
response = {}
|
||||
attachment = {
|
||||
"fallback" => "wat?!",
|
||||
"text" => "",
|
||||
"image_url" => "http://i.imgur.com/7kZ562z.jpg"
|
||||
}
|
||||
|
||||
help = "Available options are:\n"
|
||||
images.each_key { |k| help << "* #{k}\n" }
|
||||
|
||||
response = {}
|
||||
a = []
|
||||
response[:attachments] = a
|
||||
|
||||
if payload.nil? || payload.strip == ""
|
||||
response[:text] = help
|
||||
a << attachment
|
||||
puts response.to_json
|
||||
exit
|
||||
end
|
||||
|
||||
sh = SlackWebhooks::Hook.new('guppy', payload, "")
|
||||
r = images[sh.text]
|
||||
if r
|
||||
a << {image_url: r['image_url'], text: ""}
|
||||
response[:response_type] = "in_channel"
|
||||
response[:text] = "guppy #{sh.text}"
|
||||
else
|
||||
response[:text] = help
|
||||
a << attachment
|
||||
end
|
||||
|
||||
puts response.to_json
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
token=somerandomtoken&team_id=someteamid&team_domain=somename&channel_id=somechannelid&channel_name=directmessage&user_id=someid&user_name=someuser&command=%2Fguppy&text=freakout
|
||||
@@ -1,16 +0,0 @@
|
||||
# Example of Fn test framework - running functions locally
|
||||
|
||||
This example will show you how to run a test suite on a function.
|
||||
|
||||
```sh
|
||||
# build the test image (testframework:0.0.1)
|
||||
fn build
|
||||
# test it
|
||||
fn test
|
||||
```
|
||||
|
||||
Alternatively, you can force a rebuild before the test suite with:
|
||||
```sh
|
||||
# build and test it
|
||||
fn test -b
|
||||
```
|
||||
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
envvar := os.Getenv("FN_HEADER_ENVVAR")
|
||||
if envvar != "" {
|
||||
fmt.Println("FN_HEADER_ENVVAR:", envvar)
|
||||
}
|
||||
fmt.Println("hw")
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
name: testframework
|
||||
version: 0.0.1
|
||||
runtime: go
|
||||
entrypoint: ./func
|
||||
path: /tests
|
||||
tests:
|
||||
- name: simple
|
||||
out: |
|
||||
hw
|
||||
- name: envvar
|
||||
out: |
|
||||
FN_HEADER_ENVVAR: trololo
|
||||
hw
|
||||
env:
|
||||
envvar: trololo
|
||||
@@ -1,14 +0,0 @@
|
||||
# Example of Fn test framework - running functions remotely
|
||||
|
||||
This example will show you how to run a test suite on a function.
|
||||
|
||||
```sh
|
||||
# build the test image (username/functions-testframework:0.0.1)
|
||||
fn build
|
||||
# push it
|
||||
fn push
|
||||
# create a route for the testframework
|
||||
fn routes create testframework
|
||||
# test it
|
||||
fn test --remote testframework
|
||||
```
|
||||
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
envvar := os.Getenv("HEADER_ENVVAR")
|
||||
if envvar != "" {
|
||||
fmt.Println("HEADER_ENVVAR:", envvar)
|
||||
}
|
||||
fmt.Println("hw")
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
name: treeder/functions-testframework
|
||||
version: 0.0.1
|
||||
runtime: go
|
||||
entrypoint: ./func
|
||||
path: /tests
|
||||
tests:
|
||||
- name: simple
|
||||
out: |
|
||||
hw
|
||||
- name: envvar
|
||||
out: |
|
||||
FN_HEADER_ENVVAR: trololo
|
||||
hw
|
||||
env:
|
||||
envvar: trololo
|
||||
2
examples/twitter/.gitignore
vendored
2
examples/twitter/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
/func
|
||||
vendor
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user