API for environments
Environments for functions. For now this is just the image URL for the function run container. In the future, Environments will also have build container image URLs, and perhaps parameters to those containers. Create/read/update/delete/list. Versioning will be added later. For now, only the latest update is stored.
This commit is contained in:
+5
-5
@@ -90,11 +90,11 @@ func (api *API) serve(port int) {
|
|||||||
r.HandleFunc("/triggers/http/{httpTrigger}", api.HTTPTriggerApiUpdate).Methods("PUT")
|
r.HandleFunc("/triggers/http/{httpTrigger}", api.HTTPTriggerApiUpdate).Methods("PUT")
|
||||||
r.HandleFunc("/triggers/http/{httpTrigger}", api.HTTPTriggerApiDelete).Methods("DELETE")
|
r.HandleFunc("/triggers/http/{httpTrigger}", api.HTTPTriggerApiDelete).Methods("DELETE")
|
||||||
|
|
||||||
// r.HandleFunc("/environments", api.EnvironmentApiList).Methods("GET")
|
r.HandleFunc("/environments", api.EnvironmentApiList).Methods("GET")
|
||||||
// r.HandleFunc("/environments", api.EnvironmentApiCreate).Methods("POST")
|
r.HandleFunc("/environments", api.EnvironmentApiCreate).Methods("POST")
|
||||||
// r.HandleFunc("/environments/{environment}", api.EnvironmentApiGet).Methods("GET")
|
r.HandleFunc("/environments/{environment}", api.EnvironmentApiGet).Methods("GET")
|
||||||
// r.HandleFunc("/environments/{environment}", api.EnvironmentApiUpdate).Methods("PUT")
|
r.HandleFunc("/environments/{environment}", api.EnvironmentApiUpdate).Methods("PUT")
|
||||||
// r.HandleFunc("/environments/{environment}", api.EnvironmentApiDelete).Methods("DELETE")
|
r.HandleFunc("/environments/{environment}", api.EnvironmentApiDelete).Methods("DELETE")
|
||||||
|
|
||||||
address := fmt.Sprintf(":%v", port)
|
address := fmt.Sprintf(":%v", port)
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,51 @@ func TestHTTPTriggerApi(t *testing.T) {
|
|||||||
assert(len(ts) == 2, "created two triggers, but didn't find them")
|
assert(len(ts) == 2, "created two triggers, but didn't find them")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnvironmentApi(t *testing.T) {
|
||||||
|
testEnv := &fission.Environment{
|
||||||
|
Metadata: fission.Metadata{
|
||||||
|
Name: "xxx",
|
||||||
|
Uid: "yyy",
|
||||||
|
},
|
||||||
|
RunContainerImageUrl: "gcr.io/xyz",
|
||||||
|
}
|
||||||
|
uid, err := g.client.EnvironmentCreate(testEnv)
|
||||||
|
panicIf(err)
|
||||||
|
m := &fission.Metadata{
|
||||||
|
Name: testEnv.Metadata.Name,
|
||||||
|
Uid: uid,
|
||||||
|
}
|
||||||
|
defer g.client.EnvironmentDelete(m)
|
||||||
|
|
||||||
|
tr, err := g.client.EnvironmentGet(m)
|
||||||
|
panicIf(err)
|
||||||
|
testEnv.Metadata.Uid = m.Uid
|
||||||
|
assert(*testEnv == *tr, "env should match after reading")
|
||||||
|
|
||||||
|
testEnv.RunContainerImageUrl = "/hi"
|
||||||
|
uid2, err := g.client.EnvironmentUpdate(testEnv)
|
||||||
|
panicIf(err)
|
||||||
|
|
||||||
|
m.Uid = uid2
|
||||||
|
tr, err = g.client.EnvironmentGet(m)
|
||||||
|
panicIf(err)
|
||||||
|
testEnv.Metadata.Uid = m.Uid
|
||||||
|
assert(*testEnv == *tr, "env should match after reading")
|
||||||
|
|
||||||
|
testEnv.Metadata.Name = "yyy"
|
||||||
|
uid, err = g.client.EnvironmentCreate(testEnv)
|
||||||
|
panicIf(err)
|
||||||
|
m = &fission.Metadata{
|
||||||
|
Name: testEnv.Metadata.Name,
|
||||||
|
Uid: uid,
|
||||||
|
}
|
||||||
|
defer g.client.EnvironmentDelete(m)
|
||||||
|
|
||||||
|
ts, err := g.client.EnvironmentList()
|
||||||
|
panicIf(err)
|
||||||
|
assert(len(ts) == 2, "created two envs, but didn't find them")
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -167,6 +212,7 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
ks.Delete(context.Background(), "Function", &etcdClient.DeleteOptions{Recursive: true})
|
ks.Delete(context.Background(), "Function", &etcdClient.DeleteOptions{Recursive: true})
|
||||||
ks.Delete(context.Background(), "HTTPTrigger", &etcdClient.DeleteOptions{Recursive: true})
|
ks.Delete(context.Background(), "HTTPTrigger", &etcdClient.DeleteOptions{Recursive: true})
|
||||||
|
ks.Delete(context.Background(), "Environment", &etcdClient.DeleteOptions{Recursive: true})
|
||||||
|
|
||||||
go api.serve(8888)
|
go api.serve(8888)
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|||||||
+110
-10
@@ -318,13 +318,113 @@ func (c *Client) HTTPTriggerList() ([]fission.HTTPTrigger, error) {
|
|||||||
return triggers, nil
|
return triggers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (c *Client) EnvironmentCreate(f *fission.Environment) (string, error) {
|
func (c *Client) EnvironmentCreate(env *fission.Environment) (string, error) {
|
||||||
// }
|
reqbody, err := json.Marshal(env)
|
||||||
// func (c *Client) EnvironmentGet(m *fission.Metadata) (*fission.Environment, error) {
|
if err != nil {
|
||||||
// }
|
return "", err
|
||||||
// func (c *Client) EnvironmentUpdate(f *fission.Environment) (string, error) {
|
}
|
||||||
// }
|
|
||||||
// func (c *Client) EnvironmentDelete(m *fission.Metadata) error {
|
resp, err := http.Post(c.url("environments"), "application/json", bytes.NewReader(reqbody))
|
||||||
// }
|
if err != nil {
|
||||||
// func (c *Client) EnvironmentList() ([]fission.Environment, error) {
|
return "", err
|
||||||
// }
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := c.handleResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"name": env.Metadata.Name,
|
||||||
|
"err": err,
|
||||||
|
}).Error("Failed to create environment")
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m fission.Metadata
|
||||||
|
err = json.Unmarshal(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.Uid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EnvironmentGet(m *fission.Metadata) (*fission.Environment, error) {
|
||||||
|
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
|
||||||
|
if len(m.Uid) > 0 {
|
||||||
|
relativeUrl += fmt.Sprintf("?uid=%v", m.Uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(c.url(relativeUrl))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := c.handleResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var env fission.Environment
|
||||||
|
err = json.Unmarshal(body, &env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EnvironmentUpdate(env *fission.Environment) (string, error) {
|
||||||
|
reqbody, err := json.Marshal(env)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
relativeUrl := fmt.Sprintf("environments/%v", env.Metadata.Name)
|
||||||
|
|
||||||
|
resp, err := c.put(relativeUrl, "application/json", reqbody)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := c.handleResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m fission.Metadata
|
||||||
|
err = json.Unmarshal(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return m.Uid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EnvironmentDelete(m *fission.Metadata) error {
|
||||||
|
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
|
||||||
|
if len(m.Uid) > 0 {
|
||||||
|
relativeUrl += fmt.Sprintf("?uid=%v", m.Uid)
|
||||||
|
}
|
||||||
|
err := c.delete(relativeUrl)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EnvironmentList() ([]fission.Environment, error) {
|
||||||
|
resp, err := http.Get(c.url("environments"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := c.handleResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
envs := make([]fission.Environment, 0)
|
||||||
|
err = json.Unmarshal(body, &envs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return envs, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Fission Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"github.com/platform9/fission"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (api *API) EnvironmentApiList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
envs, err := api.EnvironmentStore.List()
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := json.Marshal(envs)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.respondWithSuccess(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) EnvironmentApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var env fission.Environment
|
||||||
|
err = json.Unmarshal(body, &env)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, err := api.EnvironmentStore.Create(&env)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &fission.Metadata{Name: env.Metadata.Name, Uid: uid}
|
||||||
|
resp, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.respondWithSuccess(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) EnvironmentApiGet(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var m fission.Metadata
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
m.Name = vars["environment"]
|
||||||
|
m.Uid = r.FormValue("uid") // empty if uid is absent
|
||||||
|
|
||||||
|
env, err := api.EnvironmentStore.Get(&m)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := json.Marshal(env)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.respondWithSuccess(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) EnvironmentApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
name := vars["environment"]
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var env fission.Environment
|
||||||
|
err = json.Unmarshal(body, &env)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != env.Metadata.Name {
|
||||||
|
err = fission.MakeError(fission.ErrorInvalidArgument, "Environment name doesn't match URL")
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, err := api.EnvironmentStore.Update(&env)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &fission.Metadata{Name: env.Metadata.Name, Uid: uid}
|
||||||
|
resp, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api.respondWithSuccess(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) EnvironmentApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
var m fission.Metadata
|
||||||
|
m.Name = vars["environment"]
|
||||||
|
|
||||||
|
m.Uid = r.FormValue("uid") // empty if uid is absent
|
||||||
|
if len(m.Uid) == 0 {
|
||||||
|
log.WithFields(log.Fields{"httpTrigger": m.Name}).Info("Deleting all versions")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := api.EnvironmentStore.Delete(m)
|
||||||
|
if err != nil {
|
||||||
|
api.respondWithError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.respondWithSuccess(w, []byte(""))
|
||||||
|
}
|
||||||
@@ -26,12 +26,12 @@ type EnvironmentStore struct {
|
|||||||
resourceStore
|
resourceStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvironmentStore) create(e *fission.Environment) error {
|
func (es *EnvironmentStore) Create(e *fission.Environment) (string, error) {
|
||||||
e.Metadata.Uid = uuid.NewV4().String()
|
e.Metadata.Uid = uuid.NewV4().String()
|
||||||
return es.resourceStore.create(e)
|
return e.Metadata.Uid, es.resourceStore.create(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvironmentStore) read(m fission.Metadata) (*fission.Environment, error) {
|
func (es *EnvironmentStore) Get(m *fission.Metadata) (*fission.Environment, error) {
|
||||||
var e fission.Environment
|
var e fission.Environment
|
||||||
err := es.resourceStore.read(m.Name, &e)
|
err := es.resourceStore.read(m.Name, &e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,12 +40,12 @@ func (es *EnvironmentStore) read(m fission.Metadata) (*fission.Environment, erro
|
|||||||
return &e, nil
|
return &e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvironmentStore) update(e *fission.Environment) error {
|
func (es *EnvironmentStore) Update(e *fission.Environment) (string, error) {
|
||||||
e.Metadata.Uid = uuid.NewV4().String()
|
e.Metadata.Uid = uuid.NewV4().String()
|
||||||
return es.resourceStore.update(e)
|
return e.Metadata.Uid, es.resourceStore.update(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvironmentStore) delete(m fission.Metadata) error {
|
func (es *EnvironmentStore) Delete(m fission.Metadata) error {
|
||||||
typeName, err := getTypeName(fission.Environment{})
|
typeName, err := getTypeName(fission.Environment{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -53,7 +53,7 @@ func (es *EnvironmentStore) delete(m fission.Metadata) error {
|
|||||||
return es.resourceStore.delete(typeName, m.Name)
|
return es.resourceStore.delete(typeName, m.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *EnvironmentStore) list() ([]fission.Environment, error) {
|
func (es *EnvironmentStore) List() ([]fission.Environment, error) {
|
||||||
typeName, err := getTypeName(fission.Environment{})
|
typeName, err := getTypeName(fission.Environment{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -64,7 +64,7 @@ func (es *EnvironmentStore) list() ([]fission.Environment, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
triggers := make([]fission.Environment, 0, len(bufs))
|
envs := make([]fission.Environment, 0, len(bufs))
|
||||||
js := JsonSerializer{}
|
js := JsonSerializer{}
|
||||||
for _, buf := range bufs {
|
for _, buf := range bufs {
|
||||||
var e fission.Environment
|
var e fission.Environment
|
||||||
@@ -72,8 +72,8 @@ func (es *EnvironmentStore) list() ([]fission.Environment, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
triggers = append(triggers, e)
|
envs = append(envs, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return triggers, nil
|
return envs, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (api *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &fission.Metadata{Name: t.Name, Uid: uid}
|
m := &fission.Metadata{Name: t.Metadata.Name, Uid: uid}
|
||||||
resp, err := json.Marshal(m)
|
resp, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.respondWithError(w, err)
|
api.respondWithError(w, err)
|
||||||
@@ -122,7 +122,7 @@ func (api *API) HTTPTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &fission.Metadata{Name: t.Name, Uid: uid}
|
m := &fission.Metadata{Name: t.Metadata.Name, Uid: uid}
|
||||||
resp, err := json.Marshal(m)
|
resp, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.respondWithError(w, err)
|
api.respondWithError(w, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user