func SSLCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { a := mux.Vars(r)["app"] process := GetForm(r, "process") port := GetForm(r, "port") body := GetForm(r, "body") key := GetForm(r, "key") secure := GetForm(r, "secure") if process == "" { return httperr.Errorf(403, "must specify a process") } portn, err := strconv.Atoi(port) if err != nil { return httperr.Errorf(403, "port must be numeric") } ssl, err := models.CreateSSL(a, process, portn, body, key, (secure == "true")) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "%s", err) } if err != nil { return httperr.Server(err) } return RenderJson(rw, ssl) }
func ReleasePromote(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] release := vars["release"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } rr, err := models.GetRelease(app, release) if err != nil && strings.HasPrefix(err.Error(), "no such release") { return httperr.Errorf(404, "no such release: %s", release) } if err != nil { return httperr.Server(err) } err = rr.Promote() if awsError(err) == "ValidationError" { return httperr.Errorf(403, err.(awserr.Error).Message()) } if err != nil { return httperr.Server(err) } return RenderJson(rw, rr) }
// BuildDelete deletes a build. Makes sure not to delete a build that is contained in the active release func BuildDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) appName := vars["app"] buildID := vars["build"] active, err := isBuildActive(appName, buildID) if err != nil { return httperr.Errorf(404, err.Error()) } if active { return httperr.Errorf(400, "cannot delete build contained in active release") } err = models.Provider().ReleaseDelete(appName, buildID) if err != nil { return httperr.Server(err) } build, err := models.Provider().BuildDelete(appName, buildID) if err != nil { return httperr.Server(err) } return RenderJson(rw, build) }
func FormationSet(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] process := vars["process"] count := GetForm(r, "count") memory := GetForm(r, "memory") _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } err = models.SetFormation(app, process, count, memory) if ae, ok := err.(awserr.Error); ok { if ae.Code() == "ValidationError" { switch { case strings.Index(ae.Error(), "No updates are to be performed") > -1: return httperr.Errorf(403, "no updates are to be performed: %s", app) case strings.Index(ae.Error(), "can not be updated") > -1: return httperr.Errorf(403, "app is already updating: %s", app) } } } if err != nil { return httperr.Server(err) } return RenderSuccess(rw) }
func BuildGet(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] build := vars["build"] b, err := models.Provider().BuildGet(app, build) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil && strings.HasPrefix(err.Error(), "no such build") { return httperr.Errorf(404, err.Error()) } if err != nil { return httperr.Server(err) } l, err := models.Provider().BuildLogs(app, build) if err != nil { return httperr.Server(err) } b.Logs = l return RenderJson(rw, b) }
func BuildList(rw http.ResponseWriter, r *http.Request) *httperr.Error { app := mux.Vars(r)["app"] l := r.URL.Query().Get("limit") var err error var limit int if l == "" { limit = 20 } else { limit, err = strconv.Atoi(l) if err != nil { return httperr.Errorf(400, err.Error()) } } builds, err := models.Provider().BuildList(app, int64(limit)) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } return RenderJson(rw, builds) }
func AppCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { name := r.FormValue("name") if name == os.Getenv("RACK") { return httperr.Errorf(403, "application name cannot match rack name (%s). Please choose a different name for your app.", name) } // Early check for unbound app only. if app, err := models.GetAppUnbound(name); err == nil { return httperr.Errorf(403, "there is already a legacy app named %s (%s). We recommend you delete this app and create it again.", name, app.Status) } // If unbound check fails this will result in a bound app. app := &models.App{Name: name} err := app.Create() if awsError(err) == "AlreadyExistsException" { app, err := models.GetApp(name) if err != nil { return httperr.Server(err) } return httperr.Errorf(403, "there is already an app named %s (%s)", name, app.Status) } if err != nil { return httperr.Server(err) } app, err = models.GetApp(name) if err != nil { return httperr.Server(err) } return RenderJson(rw, app) }
func AppDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { name := mux.Vars(r)["app"] app, err := models.GetApp(name) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", name) } if err != nil { return httperr.Server(err) } if app.Tags["Type"] != "app" || app.Tags["System"] != "convox" || app.Tags["Rack"] != os.Getenv("RACK") { return httperr.Errorf(404, "invalid app: %s", name) } err = app.Delete() if err != nil { return httperr.Server(err) } return RenderSuccess(rw) }
func SSLUpdate(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) a := vars["app"] process := vars["process"] port := vars["port"] id := GetForm(r, "id") if process == "" { return httperr.Errorf(403, "must specify a process") } portn, err := strconv.Atoi(port) if err != nil { return httperr.Errorf(403, "port must be numeric") } ssl, err := models.UpdateSSL(a, process, portn, id) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "%s", err) } if err != nil { return httperr.Server(err) } return RenderJson(rw, ssl) }
func ProcessRunDetached(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] process := vars["process"] command := GetForm(r, "command") release := GetForm(r, "release") a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } err = a.RunDetached(process, command, release) if err != nil { if strings.HasPrefix(err.Error(), "no such release") { return httperr.Errorf(404, err.Error()) } return httperr.Server(err) } return RenderSuccess(rw) }
func ReleaseShow(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] release := vars["release"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } rr, err := models.GetRelease(app, release) if err != nil && strings.HasPrefix(err.Error(), "no such release") { return httperr.Errorf(404, "no such release: %s", release) } fmt.Printf("err %+v\n", err) if err != nil { return httperr.Server(err) } return RenderJson(rw, rr) }
func ProcessStop(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] process := vars["process"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } ps, err := models.GetProcess(app, process) if err != nil { return httperr.Server(err) } if ps == nil { return httperr.Errorf(404, "no such process: %s", process) } err = ps.Stop() if err != nil { return httperr.Server(err) } return RenderJson(rw, ps) }
func SSLDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] process := vars["process"] port := vars["port"] if process == "" { return httperr.Errorf(403, "must specify a process") } portn, err := strconv.Atoi(port) if err != nil { return httperr.Errorf(403, "port must be numeric") } ssl, err := models.DeleteSSL(app, process, portn) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } return RenderJson(rw, ssl) }
func SystemUpdate(rw http.ResponseWriter, r *http.Request) *httperr.Error { rack, err := models.GetSystem() if err != nil { return httperr.Server(err) } notifyData := map[string]string{} if count := GetForm(r, "count"); count != "" { count, err := strconv.Atoi(count) if err != nil { return httperr.Server(err) } rack.Count = count notifyData["count"] = strconv.Itoa(count) } if t := GetForm(r, "type"); t != "" { rack.Type = t notifyData["type"] = t } if version := GetForm(r, "version"); version != "" { rack.Version = version notifyData["version"] = version } err = rack.Save() if awsError(err) == "ValidationError" { switch { case strings.Index(err.Error(), "No updates are to be performed") > -1: return httperr.Errorf(403, "no system updates are to be performed") case strings.Index(err.Error(), "can not be updated") > -1: return httperr.Errorf(403, "system is already updating") } } if err != nil { return httperr.Server(err) } rack, err = models.GetSystem() if err != nil { return httperr.Server(err) } models.NotifySuccess("system:update", notifyData) return RenderJson(rw, rack) }
func ServiceCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { err := r.ParseForm() if err != nil { return httperr.Server(err) } // get the last set value for all form values // ie: foo=1&foo=2 sets foo to "2" params := make(map[string]string) for key, values := range r.Form { val := values[len(values)-1] params[key] = val } name := params["name"] delete(params, "name") kind := params["type"] delete(params, "type") // Early check for unbound service only. service, err := models.GetServiceUnbound(name) if err == nil { return httperr.Errorf(403, "there is already a legacy service named %s (%s). We recommend you delete this service and create it again.", name, service.Status) } if awsError(err) == "ValidationError" { // If unbound check fails this will result in a bound service. service = &models.Service{ Name: name, Type: kind, Parameters: models.CFParams(params), } } err = service.Create() if err != nil && strings.HasSuffix(err.Error(), "not found") { return httperr.Errorf(403, "invalid service type: %s", kind) } if err != nil && awsError(err) == "ValidationError" { e := err.(awserr.Error) return httperr.Errorf(403, convoxifyCloudformationError(e.Message())) } if err != nil { return httperr.Server(err) } service, err = models.GetService(name) if err != nil { return httperr.Server(err) } return RenderJson(rw, service) }
func FormationSet(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] process := vars["process"] _, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } // initialize to invalid values that indicate no change var count, memory int64 = -1, -1 // update based on form input if cc := GetForm(r, "count"); cc != "" { if c, err := strconv.ParseInt(cc, 10, 64); err != nil { return httperr.Errorf(403, "count must be numeric") } else { count = c } } if mm := GetForm(r, "memory"); mm != "" { if m, err := strconv.ParseInt(mm, 10, 64); err != nil { return httperr.Errorf(403, "memory must be numeric") } else { memory = m } } err = models.SetFormation(app, process, count, memory) if ae, ok := err.(awserr.Error); ok { if ae.Code() == "ValidationError" { switch { case strings.Index(ae.Error(), "No updates are to be performed") > -1: return httperr.Errorf(403, "no updates are to be performed: %s", app) case strings.Index(ae.Error(), "can not be updated") > -1: return httperr.Errorf(403, "app is already updating: %s", app) } } } if err != nil { return httperr.Server(err) } return RenderSuccess(rw) }
func LinkCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { service := mux.Vars(r)["service"] s, err := models.GetService(service) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such service: %s", service) } if err != nil { return httperr.Server(err) } if s.Status != "running" { return httperr.Errorf(403, "can not link service with status: %s", s.Status) } // new services should use the provider interfaces if s.Type == "syslog" { s, err := provider.ServiceLink(service, GetForm(r, "app"), GetForm(r, "process")) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) } if s.Type != "papertrail" { return httperr.Errorf(403, "linking is not yet implemented for service type: %s", s.Type) } app := GetForm(r, "app") a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } err = s.LinkPapertrail(*a) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) }
func ServiceDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { service := mux.Vars(r)["service"] s, err := models.GetService(service) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such service: %s", service) } if err != nil { return httperr.Server(err) } // new services should use the provider interfaces if s.Type == "syslog" { s, err := provider.ServiceDelete(service) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) } err = s.Delete() if err != nil { return httperr.Server(err) } s, err = models.GetService(service) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) }
func RegistryDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { // server := mux.Vars(r)["server"] server := r.FormValue("server") env, acs, err := models.GetPrivateRegistriesAuth() if err != nil { return httperr.Server(err) } ac, ok := acs[server] if !ok { return httperr.Errorf(404, "no such registry: %s", server) } models.DockerLogout(ac) delete(acs, server) dat, err := json.Marshal(acs) if err != nil { return httperr.Server(err) } env["DOCKER_AUTH_DATA"] = string(dat) err = models.PutRackSettings(env) if err != nil { return httperr.Server(err) } return RenderJson(rw, ac) }
func ServiceDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { service := mux.Vars(r)["service"] s, err := models.GetService(service) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such service: %s", service) } if err != nil { return httperr.Server(err) } err = s.Delete() if err != nil { return httperr.Server(err) } s, err = models.GetService(service) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) }
func ParametersSet(rw http.ResponseWriter, r *http.Request) *httperr.Error { app := mux.Vars(r)["app"] a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } r.ParseMultipartForm(2048) params := map[string]string{} for key, values := range r.Form { params[key] = values[0] } err = a.UpdateParams(params) if err != nil { return httperr.Server(err) } return RenderSuccess(rw) }
func AppLogs(ws *websocket.Conn) *httperr.Error { app := mux.Vars(ws.Request())["app"] header := ws.Request().Header var err error follow := true if header.Get("Follow") == "false" { follow = false } since := 2 * time.Minute if s := header.Get("Since"); s != "" { since, err = time.ParseDuration(s) if err != nil { return httperr.Errorf(403, "Invalid duration %s", s) } } err = models.Provider().LogStream(app, ws, structs.LogStreamOptions{ Filter: header.Get("Filter"), Follow: follow, Since: time.Now().Add(-1 * since), }) if err != nil { if strings.HasSuffix(err.Error(), "write: broken pipe") { return nil } return httperr.Server(err) } return nil }
// SystemLogs returns the logs for the Rack func SystemLogs(ws *websocket.Conn) *httperr.Error { header := ws.Request().Header var err error follow := true if header.Get("Follow") == "false" { follow = false } since := 2 * time.Minute if s := header.Get("Since"); s != "" { since, err = time.ParseDuration(s) if err != nil { return httperr.Errorf(403, "Invalid duration %s", s) } } err = models.Provider().SystemLogs(ws, structs.LogStreamOptions{ Filter: header.Get("Filter"), Follow: follow, Since: time.Now().Add(-1 * since), }) if err != nil { return httperr.Server(err) } return nil }
func AppLogs(ws *websocket.Conn) *httperr.Error { app := mux.Vars(ws.Request())["app"] a, err := models.GetApp(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } logs := make(chan []byte) done := make(chan bool) a.SubscribeLogs(logs, done) go signalWsClose(ws, done) for data := range logs { ws.Write(data) } return nil }
func BuildCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] cache := !(r.FormValue("cache") == "false") manifest := r.FormValue("manifest") description := r.FormValue("description") repo := r.FormValue("repo") index := r.FormValue("index") source, _, err := r.FormFile("source") if err != nil && err != http.ErrMissingFile && err != http.ErrNotMultipart { helpers.TrackError("build", err, map[string]interface{}{"at": "FormFile"}) return httperr.Server(err) } // Log into private registries that we might pull from // TODO: move to prodiver BuildCreate err = models.LoginPrivateRegistries() if err != nil { return httperr.Server(err) } a, err := models.GetApp(app) if err != nil { return httperr.Server(err) } // Log into registry that we will push to _, err = models.AppDockerLogin(*a) if err != nil { return httperr.Server(err) } var b *structs.Build // if source file was posted, build from tar if source != nil { b, err = models.Provider().BuildCreateTar(app, source, r.FormValue("manifest"), r.FormValue("description"), cache) } else if repo != "" { b, err = models.Provider().BuildCreateRepo(app, repo, r.FormValue("manifest"), r.FormValue("description"), cache) } else if index != "" { var i structs.Index err := json.Unmarshal([]byte(index), &i) if err != nil { return httperr.Server(err) } b, err = models.Provider().BuildCreateIndex(app, i, manifest, description, cache) } else { return httperr.Errorf(403, "no source, repo or index") } if err != nil { return httperr.Server(err) } return RenderJson(rw, b) }
func EnvironmentSet(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] _, err := models.GetEnvironment(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } body, err := ioutil.ReadAll(r.Body) if err != nil { return httperr.Server(err) } releaseId, err := models.PutEnvironment(app, models.LoadEnvironment(body)) if err != nil { return httperr.Server(err) } rw.Header().Set("Release-Id", releaseId) env, err := models.GetEnvironment(app) if err != nil { return httperr.Server(err) } return RenderJson(rw, env) }
func EnvironmentDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error { vars := mux.Vars(r) app := vars["app"] name := vars["name"] env, err := models.GetEnvironment(app) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such app: %s", app) } if err != nil { return httperr.Server(err) } delete(env, name) releaseId, err := models.PutEnvironment(app, env) if err != nil { return httperr.Server(err) } rw.Header().Set("Release-Id", releaseId) env, err = models.GetEnvironment(app) if err != nil { return httperr.Server(err) } return RenderJson(rw, env) }
func AppCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { name := r.FormValue("name") app := &models.App{ Name: name, } err := app.Create() if awsError(err) == "AlreadyExistsException" { app, err := models.GetApp(name) if err != nil { return httperr.Server(err) } return httperr.Errorf(403, "there is already an app named %s (%s)", name, app.Status) } if err != nil { return httperr.Server(err) } app, err = models.GetApp(name) if err != nil { return httperr.Server(err) } return RenderJson(rw, app) }
func ServiceCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error { err := r.ParseForm() if err != nil { return httperr.Server(err) } // get the last set value for all form values // ie: foo=1&foo=2 sets foo to "2" params := make(map[string]string) for key, values := range r.Form { val := values[len(values)-1] params[key] = val } name := params["name"] delete(params, "name") kind := params["type"] delete(params, "type") service := &models.Service{ Name: name, Type: kind, Parameters: models.CFParams(params), } err = service.Create() if err != nil && strings.HasSuffix(err.Error(), "not found") { return httperr.Errorf(403, "invalid service type: %s", kind) } if err != nil && awsError(err) == "ValidationError" { e := err.(awserr.Error) return httperr.Errorf(403, convoxifyCloudformationError(e.Message())) } if err != nil { return httperr.Server(err) } service, err = models.GetService(name) if err != nil { return httperr.Server(err) } return RenderJson(rw, service) }
func ServiceUpdate(rw http.ResponseWriter, r *http.Request) *httperr.Error { service := mux.Vars(r)["service"] s, err := models.GetService(service) if awsError(err) == "ValidationError" { return httperr.Errorf(404, "no such service: %s", service) } if err != nil { return httperr.Server(err) } err = r.ParseForm() if err != nil { return httperr.Server(err) } // get the last set value for all form values // ie: foo=1&foo=2 sets foo to "2" params := make(map[string]string) for key, values := range r.Form { val := values[len(values)-1] params[key] = val } err = s.Update(models.CFParams(params)) if err != nil && awsError(err) == "ValidationError" { e := err.(awserr.Error) return httperr.Errorf(403, convoxifyCloudformationError(e.Message())) } if err != nil { return httperr.Server(err) } s, err = models.GetService(service) if err != nil { return httperr.Server(err) } return RenderJson(rw, s) }