func setEnv(w http.ResponseWriter, r *http.Request, t *auth.Token) error { msg := "You must provide the environment variables in a JSON object" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables map[string]string err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") rec.Log(u.Email, "set-env", "app="+appName, variables) app, err := getApp(appName, u) if err != nil { return err } envs := make([]bind.EnvVar, 0, len(variables)) for k, v := range variables { envs = append(envs, bind.EnvVar{Name: k, Value: v, Public: true}) } return app.SetEnvs(envs, true) }
func serviceUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) error { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } var y serviceYaml err = yaml.Unmarshal(body, &y) if err != nil { return err } err = y.validate() if err != nil { return err } u, err := t.User() if err != nil { return err } rec.Log(u.Email, "update-service", y.Id, y.Endpoint) s, err := getServiceByOwner(y.Id, u) if err != nil { return err } s.Endpoint = y.Endpoint s.Password = y.Password s.Username = y.Username if err = s.Update(); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func revokeServiceAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } serviceName := r.URL.Query().Get(":service") teamName := r.URL.Query().Get(":team") rec.Log(u.Email, "revoke-service-access", "service="+serviceName, "team="+teamName) service, team, err := getServiceAndTeam(serviceName, teamName, u) if err != nil { return err } if len(service.Teams) < 2 { msg := "You can not revoke the access from this team, because it is the unique team with access to this service, and a service can not be orphaned" return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = service.RevokeAccess(team) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } conn, err := db.Conn() if err != nil { return err } defer conn.Close() return conn.Services().Update(bson.M{"_id": service.Name}, service) }
func removeUserFromTeam(w http.ResponseWriter, r *http.Request, t auth.Token) error { email := r.URL.Query().Get(":user") teamName := r.URL.Query().Get(":team") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "remove-user-from-team", "team="+teamName, "user="******"Team not found"} } if !team.ContainsUser(u) { msg := fmt.Sprintf("You are not authorized to remove a member from the team %s", team.Name) return &errors.HTTP{Code: http.StatusUnauthorized, Message: msg} } if len(team.Users) == 1 { msg := "You can not remove this user from this team, because it is the last user within the team, and a team can not be orphaned" return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } user, err := auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } err = removeUserFromTeamInDatabase(user, team) if err != nil { return err } return removeUserFromTeamInRepository(user, team) }
// title: set node status // path: /node/status // method: POST // consume: application/x-www-form-urlencoded // produce: application/json // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: App or unit not found func setNodeStatus(w http.ResponseWriter, r *http.Request, t auth.Token) error { if t.GetAppName() != app.InternalAppName { return &errors.HTTP{Code: http.StatusForbidden, Message: "this token is not allowed to execute this action"} } err := r.ParseForm() if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } var hostInput provision.NodeStatusData dec := form.NewDecoder(nil) dec.IgnoreUnknownKeys(true) err = dec.DecodeValues(&hostInput, r.Form) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } result, err := app.UpdateNodeStatus(hostInput) if err != nil { if err == provision.ErrNodeNotFound { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } return err } w.Header().Add("Content-Type", "application/json") return json.NewEncoder(w).Encode(result) }
func unsetCName(w http.ResponseWriter, r *http.Request, t auth.Token) error { msg := "You must provide the cname." if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var v map[string][]string err := json.NewDecoder(r.Body).Decode(&v) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: "Invalid JSON in request body."} } if _, ok := v["cname"]; !ok { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") rawCName := strings.Join(v["cname"], ", ") rec.Log(u.Email, "remove-cname", "app="+appName, "cnames="+rawCName) app, err := getAppFromContext(appName, u, r) if err != nil { return err } if err = app.RemoveCName(v["cname"]...); err == nil { return nil } if err.Error() == "Invalid cname" { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } return err }
func changePassword(w http.ResponseWriter, r *http.Request, t auth.Token) error { managed, ok := app.AuthScheme.(auth.ManagedScheme) if !ok { return &errors.HTTP{Code: http.StatusBadRequest, Message: nonManagedSchemeMsg} } var body map[string]string err := json.NewDecoder(r.Body).Decode(&body) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "Invalid JSON.", } } if body["old"] == "" || body["new"] == "" { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "Both the old and the new passwords are required.", } } err = managed.ChangePassword(t, body["old"], body["new"]) if err != nil { return handleAuthError(err) } rec.Log(t.GetUserName(), "change-password") return nil }
func addUnits(w http.ResponseWriter, r *http.Request, t auth.Token) error { n, err := numberOfUnits(r) if err != nil { return err } processName := r.FormValue("process") appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "add-units", "app="+appName, fmt.Sprintf("units=%d", n)) app, err := getApp(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = app.AddUnits(n, processName, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func setUnitsStatus(w http.ResponseWriter, r *http.Request, t auth.Token) error { if t.GetAppName() != app.InternalAppName { return &errors.HTTP{Code: http.StatusForbidden, Message: "this token is not allowed to execute this action"} } defer r.Body.Close() var input []map[string]string err := json.NewDecoder(r.Body).Decode(&input) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } units := make(map[string]provision.Status, len(input)) for _, unit := range input { units[unit["ID"]] = provision.Status(unit["Status"]) } result, err := app.UpdateUnitsStatus(units) if err != nil { return err } resp := make([]updateUnitsResponse, 0, len(result)) for unit, found := range result { resp = append(resp, updateUnitsResponse{ID: unit, Found: found}) } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) return json.NewEncoder(w).Encode(resp) }
func revokeServiceAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { serviceName := r.URL.Query().Get(":service") s, err := getService(serviceName) if err != nil { return err } allowed := permission.Check(t, permission.PermServiceUpdateRevokeAccess, append(permission.Contexts(permission.CtxTeam, s.OwnerTeams), permission.Context(permission.CtxService, s.Name), )..., ) if !allowed { return permission.ErrUnauthorized } teamName := r.URL.Query().Get(":team") team, err := auth.GetTeam(teamName) if err != nil { if err == auth.ErrTeamNotFound { return &errors.HTTP{Code: http.StatusNotFound, Message: "Team not found"} } return err } if len(s.Teams) < 2 { msg := "You can not revoke the access from this team, because it is the unique team with access to this service, and a service can not be orphaned" return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } rec.Log(t.GetUserName(), "revoke-service-access", "service="+serviceName, "team="+teamName) err = s.RevokeAccess(team) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } return s.Update() }
func createServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { b, err := ioutil.ReadAll(r.Body) if err != nil { return err } var body map[string]string err = json.Unmarshal(b, &body) if err != nil { return err } serviceName := body["service_name"] user, err := t.User() if err != nil { return err } rec.Log(user.Email, "create-service-instance", string(b)) srv, err := getServiceOrError(serviceName, user) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } instance := service.ServiceInstance{ Name: body["name"], PlanName: body["plan"], TeamOwner: body["owner"], } return service.CreateServiceInstance(instance, &srv, user) }
func grantServiceAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { serviceName := r.URL.Query().Get(":service") s, err := getService(serviceName) if err != nil { return err } allowed := permission.Check(t, permission.PermServiceUpdateGrantAccess, append(permission.Contexts(permission.CtxTeam, s.OwnerTeams), permission.Context(permission.CtxService, s.Name), )..., ) if !allowed { return permission.ErrUnauthorized } teamName := r.URL.Query().Get(":team") team, err := auth.GetTeam(teamName) if err != nil { if err == auth.ErrTeamNotFound { return &errors.HTTP{Code: http.StatusNotFound, Message: "Team not found"} } return err } rec.Log(t.GetUserName(), "grant-service-access", "service="+serviceName, "team="+teamName) err = s.GrantAccess(team) if err != nil { return &errors.HTTP{Code: http.StatusConflict, Message: err.Error()} } return s.Update() }
func serviceDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { s, err := getService(r.URL.Query().Get(":name")) if err != nil { return err } allowed := permission.Check(t, permission.PermServiceDelete, append(permission.Contexts(permission.CtxTeam, s.OwnerTeams), permission.Context(permission.CtxService, s.Name), )..., ) if !allowed { return permission.ErrUnauthorized } rec.Log(t.GetUserName(), "delete-service", r.URL.Query().Get(":name")) instances, err := service.GetServiceInstancesByServices([]service.Service{s}) if err != nil { return err } if len(instances) > 0 { msg := "This service cannot be removed because it has instances.\nPlease remove these instances before removing the service." return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = s.Delete() if err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func unsetEnv(w http.ResponseWriter, r *http.Request, t *auth.Token) error { msg := "You must provide the list of environment variables, in JSON format" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables []string defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } if len(variables) == 0 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "unset-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) app, err := getApp(appName, u) if err != nil { return err } return app.UnsetEnvs(variables, true) }
func runCommand(w http.ResponseWriter, r *http.Request, t auth.Token) error { w.Header().Set("Content-Type", "text") msg := "You must provide the command to run" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } c, err := ioutil.ReadAll(r.Body) if err != nil { return err } if len(c) < 1 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") once := r.URL.Query().Get("once") rec.Log(u.Email, "run-command", "app="+appName, "command="+string(c)) app, err := getAppFromContext(appName, u, r) if err != nil { return err } keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = app.Run(string(c), writer, once == "true") if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return err } return nil }
func unsetEnv(w http.ResponseWriter, r *http.Request, t auth.Token) error { msg := "You must provide the list of environment variables, in JSON format" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables []string defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } if len(variables) == 0 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "unset-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) app, err := getApp(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = app.UnsetEnvs(variables, true, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func getEnv(w http.ResponseWriter, r *http.Request, t auth.Token) error { var variables []string if r.Body != nil { defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil && err != io.EOF { return err } } appName := r.URL.Query().Get(":app") var u *auth.User var err error if !t.IsAppToken() { u, err = t.User() if err != nil { return err } rec.Log(u.Email, "get-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) } app, err := getAppFromContext(appName, u, r) if err != nil { return err } return writeEnvVars(w, &app, variables...) }
func bindServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { instanceName, appName := r.URL.Query().Get(":instance"), r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } instance, a, err := getServiceInstance(instanceName, appName, u) if err != nil { return err } rec.Log(u.Email, "bind-app", "instance="+instanceName, "app="+appName) w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = instance.BindApp(a, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } fmt.Fprintf(writer, "\nInstance %q is now bound to the app %q.\n", instanceName, appName) envs := a.InstanceEnv(instanceName) if len(envs) > 0 { fmt.Fprintf(writer, "The following environment variables are available for use in your app:\n\n") } for k := range envs { fmt.Fprintf(writer, "- %s\n", k) } fmt.Fprintf(writer, "- %s\n", app.TsuruServicesEnvVar) return nil }
func unbindServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { instanceName, appName, serviceName := r.URL.Query().Get(":instance"), r.URL.Query().Get(":app"), r.URL.Query().Get(":service") noRestart, err := strconv.ParseBool(r.URL.Query().Get("noRestart")) if err != nil { return nil } u, err := t.User() if err != nil { return err } instance, a, err := getServiceInstance(serviceName, instanceName, appName, u) if err != nil { return err } rec.Log(u.Email, "unbind-app", "instance="+instanceName, "app="+appName) w.Header().Set("Content-Type", "application/json") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = instance.UnbindApp(a, !noRestart, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } fmt.Fprintf(writer, "\nInstance %q is not bound to the app %q anymore.\n", instanceName, appName) return nil }
func serviceInfo(w http.ResponseWriter, r *http.Request, t *auth.Token) error { u, err := t.User() if err != nil { return err } serviceName := r.URL.Query().Get(":name") rec.Log(u.Email, "service-info", serviceName) _, err = getServiceOrError(serviceName, u) if err != nil { return err } instances := []service.ServiceInstance{} teams, err := u.Teams() if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() teamsNames := auth.GetTeamsNames(teams) q := bson.M{"service_name": serviceName, "teams": bson.M{"$in": teamsNames}} err = conn.ServiceInstances().Find(q).All(&instances) if err != nil { return err } b, err := json.Marshal(instances) if err != nil { return nil } w.Write(b) return nil }
func addUserToTeam(w http.ResponseWriter, r *http.Request, t auth.Token) error { teamName := r.URL.Query().Get(":team") email := r.URL.Query().Get(":user") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "add-user-to-team", "team="+teamName, "user="******"Team not found"} } if !team.ContainsUser(u) { msg := fmt.Sprintf("You are not authorized to add new users to the team %s", team.Name) return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } user, err := auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: "User not found"} } actions := []*action.Action{ &addUserToTeamInRepositoryAction, &addUserToTeamInDatabaseAction, } pipeline := action.NewPipeline(actions...) return pipeline.Execute(user, team) }
func serviceInstances(w http.ResponseWriter, r *http.Request, t *auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "list-service-instances") services, _ := service.GetServicesByTeamKindAndNoRestriction("teams", u) sInstances, _ := service.GetServiceInstancesByServicesAndTeams(services, u) result := make([]service.ServiceModel, len(services)) for i, s := range services { result[i].Service = s.Name for _, si := range sInstances { if si.ServiceName == s.Name { result[i].Instances = append(result[i].Instances, si.Name) } } } body, err := json.Marshal(result) if err != nil { return err } n, err := w.Write(body) if n != len(body) { return &errors.HTTP{Code: http.StatusInternalServerError, Message: "Failed to write the response body."} } return err }
// title: app log // path: /apps/{app}/log // method: POST // consume: application/x-www-form-urlencoded // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: App not found func addLog(w http.ResponseWriter, r *http.Request, t auth.Token) error { a, err := app.GetByName(r.URL.Query().Get(":app")) if err != nil { return err } err = r.ParseForm() if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } if t.GetAppName() != app.InternalAppName { allowed := permission.Check(t, permission.PermAppUpdateLog, contextsForApp(a)..., ) if !allowed { return permission.ErrUnauthorized } } logs := r.Form["message"] source := r.FormValue("source") if source == "" { source = "app" } unit := r.FormValue("unit") for _, log := range logs { err := a.Log(log, source, unit) if err != nil { return err } } return nil }
func setTeamOwner(w http.ResponseWriter, r *http.Request, t auth.Token) error { if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: "You must provide a team name."} } defer r.Body.Close() b, err := ioutil.ReadAll(r.Body) if err != nil { return err } teamName := string(b) team, err := auth.GetTeam(teamName) if err != nil { return err } u, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), u, r) if err != nil { return err } err = a.SetTeamOwner(team, u) if err != nil { return err } return nil }
func canUseRole(t auth.Token, roleName, contextValue string) error { role, err := permission.FindRole(roleName) if err != nil { if err == permission.ErrRoleNotFound { return &errors.HTTP{ Code: http.StatusNotFound, Message: err.Error(), } } return err } userPerms, err := t.Permissions() if err != nil { return err } perms := role.PermissionsFor(contextValue) for _, p := range perms { if !permission.CheckFromPermList(userPerms, p.Scheme, p.Context) { return &errors.HTTP{ Code: http.StatusForbidden, Message: fmt.Sprintf("User not authorized to use permission %s", p.String()), } } } return nil }
func removeUnits(w http.ResponseWriter, r *http.Request, t auth.Token) error { n, err := numberOfUnits(r) if err != nil { return err } u, err := t.User() if err != nil { return err } processName := r.FormValue("process") appName := r.URL.Query().Get(":app") rec.Log(u.Email, "remove-units", "app="+appName, fmt.Sprintf("units=%d", n)) app, err := getAppFromContext(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = app.RemoveUnits(uint(n), processName, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func serviceDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "delete-service", r.URL.Query().Get(":name")) s, err := getServiceByOwner(r.URL.Query().Get(":name"), u) if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() n, err := conn.ServiceInstances().Find(bson.M{"service_name": s.Name}).Count() if err != nil { return err } if n > 0 { msg := "This service cannot be removed because it has instances.\nPlease remove these instances before removing the service." return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = s.Delete() if err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func grantAppAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") teamName := r.URL.Query().Get(":team") rec.Log(u.Email, "grant-app-access", "app="+appName, "team="+teamName) team := new(auth.Team) a, err := getAppFromContext(appName, u, r) if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Teams().Find(bson.M{"_id": teamName}).One(team) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: "Team not found"} } err = a.Grant(team) if err == app.ErrAlreadyHaveAccess { return &errors.HTTP{Code: http.StatusConflict, Message: err.Error()} } return err }
func deployRollback(w http.ResponseWriter, r *http.Request, t auth.Token) error { appName := r.URL.Query().Get(":appname") instance, err := app.GetByName(appName) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: fmt.Sprintf("App %s not found.", appName)} } image := r.PostFormValue("image") if image == "" { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "you cannot rollback without an image name", } } w.Header().Set("Content-Type", "application/json") keepAliveWriter := io.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &io.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} if !regexp.MustCompile(":v[0-9]+$").MatchString(image) { img, err := getImage(appName, image) //err is not handled because it is treated in funcion app.Deploy() if err == nil { image = img } } err = app.Deploy(app.DeployOptions{ App: instance, OutputStream: writer, Image: image, User: t.GetUserName(), }) if err != nil { writer.Encode(io.SimpleJsonMessage{Error: err.Error()}) } return nil }
func runCommand(w http.ResponseWriter, r *http.Request, t *auth.Token) error { w.Header().Set("Content-Type", "text") msg := "You must provide the command to run" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } c, err := ioutil.ReadAll(r.Body) if err != nil { return err } if len(c) < 1 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") once := r.URL.Query().Get("once") rec.Log(u.Email, "run-command", "app="+appName, "command="+string(c)) app, err := getApp(appName, u) if err != nil { return err } return app.Run(string(c), w, once == "true") }