func (api *API) UpdateRoute(ctx context.Context, w http.ResponseWriter, req *http.Request) { log, _ := ctxhelper.LoggerFromContext(ctx) params, _ := ctxhelper.ParamsFromContext(ctx) var route *router.Route if err := json.NewDecoder(req.Body).Decode(&route); err != nil { log.Error(err.Error()) httphelper.Error(w, err) return } route.Type = params.ByName("route_type") route.ID = params.ByName("id") l := api.router.ListenerFor(route.Type) if l == nil { httphelper.ValidationError(w, "type", "Invalid route type") return } if err := l.UpdateRoute(route); err != nil { if err == ErrNotFound { w.WriteHeader(404) return } log.Error(err.Error()) httphelper.Error(w, err) return } httphelper.JSON(w, 200, route) }
func (c *controllerAPI) KillJob(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) job, err := c.jobRepo.Get(params.ByName("jobs_id")) if err != nil { respondWithError(w, err) return } else if job.HostID == "" { httphelper.ValidationError(w, "", "cannot kill a job which has not been placed on a host") return } client, err := c.clusterClient.Host(job.HostID) if err != nil { respondWithError(w, err) return } if err = client.StopJob(job.ID); err != nil { if _, ok := err.(ct.NotFoundError); ok { err = ErrNotFound } respondWithError(w, err) return } }
func (api *API) DeleteRoute(ctx context.Context, w http.ResponseWriter, req *http.Request) { log, _ := ctxhelper.LoggerFromContext(ctx) params, _ := ctxhelper.ParamsFromContext(ctx) l := api.router.ListenerFor(params.ByName("route_type")) if l == nil { w.WriteHeader(404) return } err := l.RemoveRoute(params.ByName("id")) if err != nil { switch err { case ErrNotFound: w.WriteHeader(404) return case ErrInvalid: httphelper.Error(w, httphelper.JSONError{ Code: httphelper.ValidationErrorCode, Message: "Route has dependent routes", }) return default: log.Error(err.Error()) httphelper.Error(w, err) return } } w.WriteHeader(200) }
func (c *controllerAPI) UpdateApp(ctx context.Context, rw http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) var data appUpdate if err := httphelper.DecodeJSON(req, &data); err != nil { respondWithError(rw, err) return } if v, ok := data["meta"]; ok && v == nil { // handle {"meta": null} delete(data, "meta") } if err := schema.Validate(data); err != nil { respondWithError(rw, err) return } app, err := c.appRepo.Update(params.ByName("apps_id"), data) if err != nil { respondWithError(rw, err) return } httphelper.JSON(rw, 200, app) }
func (c *controllerAPI) DeleteResource(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) id := params.ByName("resources_id") p, err := c.getProvider(ctx) if err != nil { respondWithError(w, err) return } res, err := c.resourceRepo.Get(id) if err != nil { respondWithError(w, err) return } if err := resource.Deprovision(p.URL, res.ExternalID); err != nil { respondWithError(w, err) return } if err := c.resourceRepo.Remove(res); err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, res) }
func (c *controllerAPI) PutResource(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) p, err := c.getProvider(ctx) if err != nil { respondWithError(w, err) return } var resource ct.Resource if err = httphelper.DecodeJSON(req, &resource); err != nil { respondWithError(w, err) return } resource.ID = params.ByName("resources_id") resource.ProviderID = p.ID if err := schema.Validate(resource); err != nil { respondWithError(w, err) return } if err := c.resourceRepo.Add(&resource); err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, &resource) }
func (c *controllerAPI) UpdateAppMeta(ctx context.Context, rw http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) var data appUpdate if err := httphelper.DecodeJSON(req, &data); err != nil { respondWithError(rw, err) return } if err := schema.Validate(data); err != nil { respondWithError(rw, err) return } if data["meta"] == nil { data["meta"] = make(map[string]interface{}) } app, err := c.appRepo.Update(params.ByName("apps_id"), data) if err != nil { respondWithError(rw, err) return } httphelper.JSON(rw, 200, app) }
func (c *controllerAPI) getRelease(ctx context.Context) (*ct.Release, error) { params, _ := ctxhelper.ParamsFromContext(ctx) data, err := c.releaseRepo.Get(params.ByName("releases_id")) if err != nil { return nil, err } return data.(*ct.Release), nil }
func (c *controllerAPI) getProvider(ctx context.Context) (*ct.Provider, error) { params, _ := ctxhelper.ParamsFromContext(ctx) data, err := c.providerRepo.Get(params.ByName("providers_id")) if err != nil { return nil, err } return data.(*ct.Provider), nil }
func (a *aggregatorAPI) GetLog(ctx context.Context, w http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithCancel(ctx) if cn, ok := w.(http.CloseNotifier); ok { ch := cn.CloseNotify() go func() { select { case <-ch: cancel() case <-ctx.Done(): } }() } defer cancel() params, _ := ctxhelper.ParamsFromContext(ctx) follow := false if strFollow := req.FormValue("follow"); strFollow == "true" { follow = true } var ( backlog bool lines int err error ) if strLines := req.FormValue("lines"); strLines != "" { if lines, err = strconv.Atoi(strLines); err != nil { httphelper.ValidationError(w, "lines", err.Error()) return } if lines < 0 || lines > 10000 { httphelper.ValidationError(w, "lines", "lines must be an integer between 0 and 10000") return } backlog = lines > 0 } filters := make(filterSlice, 0) if jobID := req.FormValue("job_id"); jobID != "" { filters = append(filters, filterJobID(jobID)) } if processTypeVals, ok := req.Form["process_type"]; ok && len(processTypeVals) > 0 { val := processTypeVals[len(processTypeVals)-1] filters = append(filters, filterProcessType(val)) } iter := &Iterator{ id: params.ByName("channel_id"), follow: follow, backlog: backlog, lines: lines, filter: filters, donec: ctx.Done(), } writeMessages(ctx, w, iter.Scan(a.agg)) }
func (c *controllerAPI) GetJob(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) job, err := c.jobRepo.Get(params.ByName("jobs_id")) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, job) }
func (c *controllerAPI) GetDeployment(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) deployment, err := c.deploymentRepo.Get(params.ByName("deployment_id")) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, deployment) }
func (c *controllerAPI) connectHost(ctx context.Context) (utils.HostClient, string, error) { params, _ := ctxhelper.ParamsFromContext(ctx) hostID, jobID, err := cluster.ParseJobID(params.ByName("jobs_id")) if err != nil { log.Printf("Unable to parse hostID from %q", params.ByName("jobs_id")) return nil, jobID, err } host, err := c.clusterClient.Host(hostID) return host, jobID, err }
func (c *controllerAPI) getRoute(ctx context.Context) (*router.Route, error) { params, _ := ctxhelper.ParamsFromContext(ctx) route, err := c.routerc.GetRoute(params.ByName("routes_type"), params.ByName("routes_id")) if err == routerc.ErrNotFound || err == nil && route.ParentRef != routeParentRef(c.getApp(ctx).ID) { err = ErrNotFound } if err != nil { return nil, err } return route, err }
func (api *API) GetCertRoutes(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) l := api.router.HTTP.(*HTTPListener) routes, err := l.GetCertRoutes(params.ByName("id")) if err != nil { httphelper.Error(w, err) return } httphelper.JSON(w, 200, routes) }
func (c *controllerAPI) connectHost(ctx context.Context) (utils.HostClient, *ct.Job, error) { params, _ := ctxhelper.ParamsFromContext(ctx) job, err := c.jobRepo.Get(params.ByName("jobs_id")) if err != nil { return nil, nil, err } else if job.HostID == "" { return nil, nil, errors.New("controller: cannot connect host, job has not been placed in the cluster") } host, err := c.clusterClient.Host(job.HostID) return host, job, err }
func (c *controllerAPI) GetFormation(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) app := c.getApp(ctx) formation, err := c.formationRepo.Get(app.ID, params.ByName("releases_id")) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, formation) }
func (c *controllerAPI) appLookup(handler httphelper.HandlerFunc) httphelper.HandlerFunc { return func(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) data, err := c.appRepo.Get(params.ByName("apps_id")) if err != nil { respondWithError(w, err) return } ctx = context.WithValue(ctx, "app", data.(*ct.App)) handler(ctx, w, req) } }
func (api *API) ServeAsset(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) path := params.ByName("path") if !strings.HasPrefix(path, "/assets/") { api.ServeTemplate(ctx, w, req) return } if strings.HasPrefix(path, "/assets/dashboard") && strings.HasSuffix(path, ".js") { api.ServeDashboardJs(ctx, w, req) return } api.ServeStatic(ctx, w, req, filepath.Join("app", "build", path)) }
func (c *controllerAPI) GetEvent(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) id, err := strconv.ParseInt(params.ByName("id"), 10, 64) if err != nil { respondWithError(w, err) return } event, err := c.eventRepo.GetEvent(id) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, event) }
func (a *aggregatorAPI) GetLog(ctx context.Context, w http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithCancel(ctx) if cn, ok := w.(http.CloseNotifier); ok { go func() { select { case <-cn.CloseNotify(): cancel() case <-ctx.Done(): } }() } defer cancel() params, _ := ctxhelper.ParamsFromContext(ctx) channelID := params.ByName("channel_id") follow := false if strFollow := req.FormValue("follow"); strFollow == "true" { follow = true } lines := -1 // default to all lines if strLines := req.FormValue("lines"); strLines != "" { var err error lines, err = strconv.Atoi(strLines) if err != nil || lines < 0 || lines > 10000 { httphelper.ValidationError(w, "lines", "lines must be an integer between 0 and 10000") return } } filters := make(filterSlice, 0) if jobID := req.FormValue("job_id"); jobID != "" { filters = append(filters, filterJobID(jobID)) } if processTypeVals, ok := req.Form["process_type"]; ok && len(processTypeVals) > 0 { val := processTypeVals[len(processTypeVals)-1] filters = append(filters, filterProcessType(val)) } w.WriteHeader(200) var msgc <-chan *rfc5424.Message if follow { msgc = a.agg.ReadLastNAndSubscribe(channelID, lines, filters, ctx.Done()) } else { msgc = a.agg.ReadLastN(channelID, lines, filters, ctx.Done()) } writeMessages(ctx, w, msgc) }
func (c *controllerAPI) GetResource(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) _, err := c.getProvider(ctx) if err != nil { respondWithError(w, err) return } res, err := c.resourceRepo.Get(params.ByName("resources_id")) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, res) }
func (c *controllerAPI) DeleteFormation(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) app := c.getApp(ctx) formation, err := c.formationRepo.Get(app.ID, params.ByName("releases_id")) if err != nil { respondWithError(w, err) return } err = c.formationRepo.Remove(app.ID, formation.ReleaseID) if err != nil { respondWithError(w, err) return } w.WriteHeader(200) }
func (api *API) GetCert(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) l := api.router.HTTP.(*HTTPListener) cert, err := l.GetCert(params.ByName("id")) if err == ErrNotFound { httphelper.ObjectNotFoundError(w, "certificate not found") return } if err != nil { httphelper.Error(w, err) return } httphelper.JSON(w, 200, cert) }
func (api *API) DeleteCert(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) l := api.router.HTTP.(*HTTPListener) err := l.RemoveCert(params.ByName("id")) if err != nil { switch err { case ErrNotFound: httphelper.ObjectNotFoundError(w, "certificate not found") return default: httphelper.Error(w, err) return } } w.WriteHeader(200) }
func (c *controllerAPI) GetFormation(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) app := c.getApp(ctx) releaseID := params.ByName("releases_id") if req.URL.Query().Get("expand") == "true" { formation, err := c.formationRepo.GetExpanded(app.ID, releaseID) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, formation) return } formation, err := c.formationRepo.Get(app.ID, releaseID) if err != nil { respondWithError(w, err) return } httphelper.JSON(w, 200, formation) }
func (c *controllerAPI) DeleteResource(ctx context.Context, w http.ResponseWriter, req *http.Request) { params, _ := ctxhelper.ParamsFromContext(ctx) id := params.ByName("resources_id") logger.Info("getting provider", "params", params) p, err := c.getProvider(ctx) if err != nil { logger.Error("getting provider error", "err", err) respondWithError(w, err) return } logger.Info("getting resource", "id", id) res, err := c.resourceRepo.Get(id) if err != nil { logger.Error("getting resource error", "err", err) respondWithError(w, err) return } logger.Info("deprovisioning", "url", p.URL, "external.id", res.ExternalID) if err := resource.Deprovision(p.URL, res.ExternalID); err != nil { logger.Error("error deprovisioning", "err", err) respondWithError(w, err) return } logger.Info("removing resource") if err := c.resourceRepo.Remove(res); err != nil { logger.Error("error removing resource", "err", err) respondWithError(w, err) return } logger.Info("completed resource removal") httphelper.JSON(w, 200, res) }
func (api *API) GetRoute(ctx context.Context, w http.ResponseWriter, req *http.Request) { log, _ := ctxhelper.LoggerFromContext(ctx) params, _ := ctxhelper.ParamsFromContext(ctx) l := api.router.ListenerFor(params.ByName("route_type")) if l == nil { w.WriteHeader(404) return } route, err := l.Get(params.ByName("id")) if err == ErrNotFound { w.WriteHeader(404) return } if err != nil { log.Error(err.Error()) httphelper.Error(w, err) return } httphelper.JSON(w, 200, route) }
func (a *aggregatorAPI) GetLog(ctx context.Context, w http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithCancel(ctx) if cn, ok := w.(http.CloseNotifier); ok { go func() { select { case <-cn.CloseNotify(): cancel() case <-ctx.Done(): } }() } defer cancel() params, _ := ctxhelper.ParamsFromContext(ctx) channelID := params.ByName("channel_id") follow := false if strFollow := req.FormValue("follow"); strFollow == "true" { follow = true } lines := -1 // default to all lines if strLines := req.FormValue("lines"); strLines != "" { var err error lines, err = strconv.Atoi(strLines) if err != nil || lines < 0 || lines > 10000 { httphelper.ValidationError(w, "lines", "lines must be an integer between 0 and 10000") return } } filters := make([]filter, 0) if strJobID := req.FormValue("job_id"); strJobID != "" { filters = append(filters, filterJobID{[]byte(strJobID)}) } if processTypeVals, ok := req.Form["process_type"]; ok && len(processTypeVals) > 0 { val := processTypeVals[len(processTypeVals)-1] filters = append(filters, filterProcessType{[]byte(val)}) } w.WriteHeader(200) var msgc <-chan *rfc5424.Message if follow { msgc = a.agg.ReadLastNAndSubscribe(channelID, lines, filters, ctx.Done()) go flushLoop(w.(http.Flusher), 50*time.Millisecond, ctx.Done()) } else { msgc = a.agg.ReadLastN(channelID, lines, filters, ctx.Done()) } enc := json.NewEncoder(w) for { select { case syslogMsg := <-msgc: if syslogMsg == nil { // channel is closed / done return } if err := enc.Encode(NewMessageFromSyslog(syslogMsg)); err != nil { log15.Error("error writing msg", "err", err) return } case <-ctx.Done(): return } } }
func crud(r *httprouter.Router, resource string, example interface{}, repo Repository) { resourceType := reflect.TypeOf(example) prefix := "/" + resource r.POST(prefix, httphelper.WrapHandler(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { thing := reflect.New(resourceType).Interface() if err := httphelper.DecodeJSON(req, thing); err != nil { respondWithError(rw, err) return } if err := schema.Validate(thing); err != nil { respondWithError(rw, err) return } if err := repo.Add(thing); err != nil { respondWithError(rw, err) return } httphelper.JSON(rw, 200, thing) })) lookup := func(ctx context.Context) (interface{}, error) { params, _ := ctxhelper.ParamsFromContext(ctx) return repo.Get(params.ByName(resource + "_id")) } singletonPath := prefix + "/:" + resource + "_id" r.GET(singletonPath, httphelper.WrapHandler(func(ctx context.Context, rw http.ResponseWriter, _ *http.Request) { thing, err := lookup(ctx) if err != nil { respondWithError(rw, err) return } httphelper.JSON(rw, 200, thing) })) r.GET(prefix, httphelper.WrapHandler(func(ctx context.Context, rw http.ResponseWriter, _ *http.Request) { list, err := repo.List() if err != nil { respondWithError(rw, err) return } httphelper.JSON(rw, 200, list) })) if remover, ok := repo.(Remover); ok { r.DELETE(singletonPath, httphelper.WrapHandler(func(ctx context.Context, rw http.ResponseWriter, _ *http.Request) { _, err := lookup(ctx) if err != nil { respondWithError(rw, err) return } params, _ := ctxhelper.ParamsFromContext(ctx) if err = remover.Remove(params.ByName(resource + "_id")); err != nil { respondWithError(rw, err) return } rw.WriteHeader(200) })) } }