faas/gateway/handlers/update_handler.go
John McCabe 89878f0c8a Migrate from alexellis org to openfaas
Note, not all `alexellis/github` references should be changed, there are
a number of repos which are not part of the openfaas org, this commit
excludes those.

Signed-off-by: John McCabe <john@johnmccabe.net>
2017-10-04 09:18:06 +01:00

120 lines
3.3 KiB
Go

package handlers
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/openfaas/faas/gateway/metrics"
"github.com/openfaas/faas/gateway/requests"
)
// MakeUpdateFunctionHandler request to update an existing function with new configuration such as image, envvars etc.
func MakeUpdateFunctionHandler(metricsOptions metrics.MetricOptions, c *client.Client, maxRestarts uint64, restartDelay time.Duration) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body)
request := requests.CreateFunctionRequest{}
err := json.Unmarshal(body, &request)
if err != nil {
log.Println("Error parsing request:", err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
serviceInspectopts := types.ServiceInspectOptions{
InsertDefaults: true,
}
service, _, err := c.ServiceInspectWithRaw(ctx, request.Service, serviceInspectopts)
if err != nil {
log.Println("Error inspecting service", err)
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
}
updateSpec(&request, &service.Spec, maxRestarts, restartDelay)
updateOpts := types.ServiceUpdateOptions{}
updateOpts.RegistryAuthFrom = types.RegistryAuthFromSpec
if len(request.RegistryAuth) > 0 {
auth, err := BuildEncodedAuthConfig(request.RegistryAuth, request.Image)
if err != nil {
log.Println("Error building registry auth configuration:", err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid registry auth"))
return
}
updateOpts.EncodedRegistryAuth = auth
}
response, err := c.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, updateOpts)
if err != nil {
log.Println("Error updating service:", err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Update error: " + err.Error()))
return
}
log.Println(response.Warnings)
}
}
func updateSpec(request *requests.CreateFunctionRequest, spec *swarm.ServiceSpec, maxRestarts uint64, restartDelay time.Duration) {
constraints := []string{}
if request.Constraints != nil && len(request.Constraints) > 0 {
constraints = request.Constraints
} else {
constraints = linuxOnlyConstraints
}
nets := []swarm.NetworkAttachmentConfig{
{Target: request.Network},
}
spec.TaskTemplate.RestartPolicy.MaxAttempts = &maxRestarts
spec.TaskTemplate.RestartPolicy.Condition = swarm.RestartPolicyConditionAny
spec.TaskTemplate.RestartPolicy.Delay = &restartDelay
spec.TaskTemplate.ContainerSpec.Image = request.Image
spec.TaskTemplate.ContainerSpec.Labels = map[string]string{
"function": "true",
"uid": fmt.Sprintf("%d", time.Now().Nanosecond()),
}
spec.TaskTemplate.Networks = nets
spec.TaskTemplate.Placement = &swarm.Placement{
Constraints: constraints,
}
spec.Annotations = swarm.Annotations{
Name: request.Service,
}
spec.RollbackConfig = &swarm.UpdateConfig{
FailureAction: "pause",
}
spec.UpdateConfig = &swarm.UpdateConfig{
Parallelism: 1,
FailureAction: "rollback",
}
env := buildEnv(request.EnvProcess, request.EnvVars)
if len(env) > 0 {
spec.TaskTemplate.ContainerSpec.Env = env
}
}