func listContainersHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { address := r.URL.Query().Get(":address") if address != "" { node, err := mainDockerProvisioner.Cluster().GetNode(address) if err != nil { return err } hasAccess := permission.Check(t, permission.PermNodeRead, permission.Context(permission.CtxPool, node.Metadata["pool"])) if !hasAccess { return permission.ErrUnauthorized } containerList, err := mainDockerProvisioner.listContainersByHost(address) if err != nil { return err } return json.NewEncoder(w).Encode(containerList) } appName := r.URL.Query().Get(":appname") a, err := app.GetByName(appName) if err != nil { return err } hasAccess := permission.Check(t, permission.PermNodeRead, permission.Context(permission.CtxPool, a.Pool)) if !hasAccess { return permission.ErrUnauthorized } containerList, err := mainDockerProvisioner.listContainersByApp(appName) if err != nil { return err } return json.NewEncoder(w).Encode(containerList) }
func nodeHealingUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) error { err := r.ParseForm() if err != nil { return err } poolName := r.FormValue("pool") if poolName == "" { if !permission.Check(t, permission.PermHealingUpdate) { return permission.ErrUnauthorized } } else { if !permission.Check(t, permission.PermHealingUpdate, permission.Context(permission.CtxPool, poolName)) { return permission.ErrUnauthorized } } var config healer.NodeHealerConfig delete(r.Form, "pool") dec := form.NewDecoder(nil) dec.IgnoreUnknownKeys(true) err = dec.DecodeValues(&config, r.Form) if err != nil { return err } return healer.UpdateConfig(poolName, config) }
func nodeContainerUpgrade(w http.ResponseWriter, r *http.Request, t auth.Token) error { name := r.URL.Query().Get(":name") poolName := r.FormValue("pool") if poolName == "" { if !permission.Check(t, permission.PermNodecontainerUpdateUpgrade) { return permission.ErrUnauthorized } } else { if !permission.Check(t, permission.PermNodecontainerUpdateUpgrade, permission.Context(permission.CtxPool, poolName)) { return permission.ErrUnauthorized } } config, err := nodecontainer.LoadNodeContainer("", name) if err != nil { return err } err = config.ResetImage() if err != nil { return err } keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = nodecontainer.RecreateContainers(mainDockerProvisioner, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) } return nil }
func logsConfigSetHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { var requestData logsSetData err := json.NewDecoder(r.Body).Decode(&requestData) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: fmt.Sprintf("unable to parse body as json: %s", err), } } requestConfig := requestData.Config if len(requestConfig.Envs) > 0 && !permission.Check(t, permission.PermPoolUpdateLogs) { return permission.ErrUnauthorized } for _, poolEnv := range requestConfig.Pools { hasPermission := permission.Check(t, permission.PermPoolUpdateLogs, permission.Context(permission.CtxPool, poolEnv.Name)) if !hasPermission { return permission.ErrUnauthorized } } dockerLog := container.DockerLog{} err = dockerLog.Update(&requestConfig) if err != nil { return err } if requestData.Restart { //TODO(cezarsa): restart containers } w.WriteHeader(http.StatusOK) return nil }
// addNodeHandler can provide an machine and/or register a node address. // If register flag is true, it will just register a node. // It checks if node address is valid and accessible. func addNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { params, err := unmarshal(r.Body) if err != nil { return err } if templateName, ok := params["template"]; ok { params, err = iaas.ExpandTemplate(templateName) if err != nil { w.WriteHeader(http.StatusBadRequest) return json.NewEncoder(w).Encode(map[string]string{"error": err.Error()}) } } pool := params["pool"] if pool == "" { w.WriteHeader(http.StatusBadRequest) return json.NewEncoder(w).Encode(map[string]string{"error": "pool is required"}) } if !permission.Check(t, permission.PermNodeCreate, permission.Context(permission.CtxPool, pool)) { return permission.ErrUnauthorized } isRegister, _ := strconv.ParseBool(r.URL.Query().Get("register")) if !isRegister { canCreateMachine := permission.Check(t, permission.PermMachineCreate, permission.Context(permission.CtxIaaS, params["iaas"])) if !canCreateMachine { return permission.ErrUnauthorized } } response, err := mainDockerProvisioner.addNodeForParams(params, isRegister) if err != nil { w.WriteHeader(http.StatusBadRequest) response["error"] = err.Error() } return json.NewEncoder(w).Encode(response) }
// title: role info // path: /roles/{name} // method: GET // produce: application/json // responses: // 200: OK // 401: Unauthorized // 404: Role not found func roleInfo(w http.ResponseWriter, r *http.Request, t auth.Token) error { if !(permission.Check(t, permission.PermRoleUpdate) || permission.Check(t, permission.PermRoleUpdateAssign) || permission.Check(t, permission.PermRoleUpdateDissociate) || permission.Check(t, permission.PermRoleCreate) || permission.Check(t, permission.PermRoleDelete)) { return permission.ErrUnauthorized } roleName := r.URL.Query().Get(":name") role, err := permission.FindRole(roleName) if err == permission.ErrRoleNotFound { return &errors.HTTP{ Code: http.StatusNotFound, Message: err.Error(), } } if err != nil { return err } b, err := json.Marshal(role) if err != nil { return err } w.Header().Set("Content-Type", "application/json") _, err = w.Write(b) return err }
func nodeHealingDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { err := r.ParseForm() if err != nil { return err } poolName := r.FormValue("pool") if poolName == "" { if !permission.Check(t, permission.PermHealingUpdate) { return permission.ErrUnauthorized } } else { if !permission.Check(t, permission.PermHealingUpdate, permission.Context(permission.CtxPool, poolName)) { return permission.ErrUnauthorized } } if len(r.Form["name"]) == 0 { return healer.RemoveConfig(poolName, "") } for _, v := range r.Form["name"] { err = healer.RemoveConfig(poolName, v) if err != nil { return err } } return nil }
// title: service instance create // path: /services/{service}/instances // method: POST // consume: application/x-www-form-urlencoded // responses: // 201: Service created // 400: Invalid data // 401: Unauthorized // 409: Service already exists func createServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { serviceName := r.URL.Query().Get(":service") user, err := t.User() if err != nil { return err } srv, err := getService(serviceName) if err != nil { return err } instance := service.ServiceInstance{ Name: r.FormValue("name"), PlanName: r.FormValue("plan"), TeamOwner: r.FormValue("owner"), Description: r.FormValue("description"), } var teamOwner string if instance.TeamOwner == "" { teamOwner, err = permission.TeamForPermission(t, permission.PermServiceInstanceCreate) if err != nil { return err } instance.TeamOwner = teamOwner } allowed := permission.Check(t, permission.PermServiceInstanceCreate, permission.Context(permission.CtxTeam, instance.TeamOwner), ) if !allowed { return permission.ErrUnauthorized } if srv.IsRestricted { allowed := permission.Check(t, permission.PermServiceRead, append(permission.Contexts(permission.CtxTeam, srv.Teams), permission.Context(permission.CtxService, srv.Name))..., ) if !allowed { return permission.ErrUnauthorized } } rec.Log(user.Email, "create-service-instance", fmt.Sprintf("%#v", instance)) err = service.CreateServiceInstance(instance, &srv, user) if err == service.ErrInstanceNameAlreadyExists { return &errors.HTTP{ Code: http.StatusConflict, Message: err.Error(), } } if err == service.ErrInvalidInstanceName { return &errors.HTTP{ Code: http.StatusBadRequest, Message: err.Error(), } } if err == nil { w.WriteHeader(http.StatusCreated) } return err }
func bsEnvSetHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { var requestConfig bs.Config err := json.NewDecoder(r.Body).Decode(&requestConfig) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: fmt.Sprintf("unable to parse body as json: %s", err), } } if len(requestConfig.Envs) > 0 && !permission.Check(t, permission.PermNodeBs) { return permission.ErrUnauthorized } for _, poolEnv := range requestConfig.Pools { hasPermission := permission.Check(t, permission.PermNodeBs, permission.Context(permission.CtxPool, poolEnv.Name)) if !hasPermission { return permission.ErrUnauthorized } } currentConfig, err := bs.LoadConfig(nil) if err != nil { if err != mgo.ErrNotFound { return err } currentConfig = &bs.Config{} } envMap := bs.EnvMap{} poolEnvMap := bs.PoolEnvMap{} err = currentConfig.UpdateEnvMaps(envMap, poolEnvMap) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: err.Error(), } } err = requestConfig.UpdateEnvMaps(envMap, poolEnvMap) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: err.Error(), } } err = bs.SaveEnvs(envMap, poolEnvMap) if err != nil { return err } keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = bs.RecreateContainers(mainDockerProvisioner, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) } return nil }
func updateNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { params, err := unmarshal(r.Body) if err != nil { return err } address, _ := params["address"] if address == "" { return &errors.HTTP{Code: http.StatusBadRequest, Message: "address is required"} } nodes, err := mainDockerProvisioner.Cluster().UnfilteredNodes() if err != nil { return err } var oldNode *cluster.Node for i := range nodes { if nodes[i].Address == address { oldNode = &nodes[i] break } } oldPool, _ := oldNode.Metadata["pool"] allowedOldPool := permission.Check(t, permission.PermNodeUpdate, permission.Context(permission.CtxPool, oldPool), ) if !allowedOldPool { return permission.ErrUnauthorized } newPool, ok := params["pool"] if ok { allowedNewPool := permission.Check(t, permission.PermNodeUpdate, permission.Context(permission.CtxPool, newPool), ) if !allowedNewPool { return permission.ErrUnauthorized } } delete(params, "address") node := cluster.Node{Address: address, Metadata: params} disabled, _ := strconv.ParseBool(r.URL.Query().Get("disabled")) enabled, _ := strconv.ParseBool(r.URL.Query().Get("enabled")) if disabled && enabled { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "You can't make a node enable and disable at the same time.", } } if disabled { node.CreationStatus = cluster.NodeCreationStatusDisabled } if enabled { node.CreationStatus = cluster.NodeStatusReady } _, err = mainDockerProvisioner.Cluster().UpdateNode(node) return err }
// removeNodeHandler calls scheduler.Unregister to unregistering a node into it. func removeNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { params, err := unmarshal(r.Body) if err != nil { return err } address, _ := params["address"] if address == "" { return fmt.Errorf("Node address is required.") } node, err := mainDockerProvisioner.Cluster().GetNode(address) if err != nil { return err } allowedNodeRemove := permission.Check(t, permission.PermNodeDelete, permission.Context(permission.CtxPool, node.Metadata["pool"]), ) if !allowedNodeRemove { return permission.ErrUnauthorized } removeIaaS, _ := strconv.ParseBool(params["remove_iaas"]) if removeIaaS { allowedIaasRemove := permission.Check(t, permission.PermMachineDelete, permission.Context(permission.CtxIaaS, node.Metadata["iaas"]), ) if !allowedIaasRemove { return permission.ErrUnauthorized } } node.CreationStatus = cluster.NodeCreationStatusDisabled _, err = mainDockerProvisioner.Cluster().UpdateNode(node) if err != nil { return err } noRebalance, err := strconv.ParseBool(r.URL.Query().Get("no-rebalance")) if !noRebalance { err = mainDockerProvisioner.rebalanceContainersByHost(urlToHost(address), w) if err != nil { return err } } err = mainDockerProvisioner.Cluster().Unregister(address) if err != nil { return err } if removeIaaS { var m iaas.Machine m, err = iaas.FindMachineByIdOrAddress(node.Metadata["iaas-id"], urlToHost(address)) if err != nil && err != mgo.ErrNotFound { return err } return m.Destroy() } return nil }
// title: list default roles // path: /role/default // method: GET // produce: application/json // responses: // 200: Ok // 401: Unauthorized func listDefaultRoles(w http.ResponseWriter, r *http.Request, t auth.Token) error { if !permission.Check(t, permission.PermRoleDefaultCreate) && !permission.Check(t, permission.PermRoleDefaultDelete) { return permission.ErrUnauthorized } roles, err := permission.ListRolesWithEvents() if err != nil { return err } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(roles) }
// title: bind service instance // path: /services/{service}/instances/{instance}/{app} // method: PUT // consume: application/x-www-form-urlencoded // produce: application/x-json-stream // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: App not found func bindServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { instanceName := r.URL.Query().Get(":instance") appName := r.URL.Query().Get(":app") serviceName := r.URL.Query().Get(":service") noRestart, _ := strconv.ParseBool(r.FormValue("noRestart")) instance, a, err := getServiceInstance(serviceName, instanceName, appName) if err != nil { return err } allowed := permission.Check(t, permission.PermServiceInstanceUpdateBind, append(permission.Contexts(permission.CtxTeam, instance.Teams), permission.Context(permission.CtxServiceInstance, instance.Name), )..., ) if !allowed { return permission.ErrUnauthorized } allowed = permission.Check(t, permission.PermAppUpdateBind, contextsForApp(a)..., ) if !allowed { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: appTarget(appName), Kind: permission.PermAppUpdateBind, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() w.Header().Set("Content-Type", "application/x-json-stream") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = instance.BindApp(a, !noRestart, writer) if err != nil { return err } 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 }
// title: platform list // path: /platforms // method: GET // produce: application/json // responses: // 200: List platforms // 204: No content // 401: Unauthorized func platformList(w http.ResponseWriter, r *http.Request, t auth.Token) error { canUsePlat := permission.Check(t, permission.PermPlatformUpdate) || permission.Check(t, permission.PermPlatformCreate) platforms, err := app.Platforms(!canUsePlat) if err != nil { return err } if len(platforms) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(platforms) }
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 } srv, err := getService(serviceName) if err != nil { return err } instance := service.ServiceInstance{ Name: body["name"], PlanName: body["plan"], TeamOwner: body["owner"], Description: body["description"], } if instance.TeamOwner == "" { teamOwner, err := permission.TeamForPermission(t, permission.PermServiceInstanceCreate) if err != nil { return err } instance.TeamOwner = teamOwner } allowed := permission.Check(t, permission.PermServiceInstanceCreate, permission.Context(permission.CtxTeam, instance.TeamOwner), ) if !allowed { return permission.ErrUnauthorized } if srv.IsRestricted { allowed := permission.Check(t, permission.PermServiceRead, append(permission.Contexts(permission.CtxTeam, srv.Teams), permission.Context(permission.CtxService, srv.Name))..., ) if !allowed { return permission.ErrUnauthorized } } rec.Log(user.Email, "create-service-instance", string(b)) return service.CreateServiceInstance(instance, &srv, user) }
func platformList(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "platform-list") canUsePlat := permission.Check(t, permission.PermPlatformUpdate) || permission.Check(t, permission.PermPlatformCreate) platforms, err := app.Platforms(!canUsePlat) if err != nil { return err } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(platforms) }
func nodeContainerDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { name := r.URL.Query().Get(":name") poolName := r.FormValue("pool") if poolName == "" { if !permission.Check(t, permission.PermNodecontainerDelete) { return permission.ErrUnauthorized } } else { if !permission.Check(t, permission.PermNodecontainerDelete, permission.Context(permission.CtxPool, poolName)) { return permission.ErrUnauthorized } } return nodecontainer.RemoveContainer(poolName, name) }
func rebalanceContainersHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { var dry bool var params struct { Dry string MetadataFilter map[string]string AppFilter []string } err := json.NewDecoder(r.Body).Decode(¶ms) if err == nil { dry, _ = strconv.ParseBool(params.Dry) } var permContexts []permission.PermissionContext if pool, ok := params.MetadataFilter["pool"]; ok { permContexts = append(permContexts, permission.Context(permission.CtxPool, pool)) } if !permission.Check(t, permission.PermNode, permContexts...) { return permission.ErrUnauthorized } writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} _, err = mainDockerProvisioner.rebalanceContainersByFilter(writer, params.AppFilter, params.MetadataFilter, dry) if err != nil { fmt.Fprintf(writer, "Error trying to rebalance containers: %s\n", err) } else { fmt.Fprintf(writer, "Containers successfully rebalanced!\n") } return nil }
// title: set unit status // path: /apps/{app}/units/{unit} // method: POST // consume: application/x-www-form-urlencoded // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: App or unit not found func setUnitStatus(w http.ResponseWriter, r *http.Request, t auth.Token) error { unitName := r.URL.Query().Get(":unit") if unitName == "" { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "missing unit", } } postStatus := r.FormValue("status") status, err := provision.ParseStatus(postStatus) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: err.Error(), } } appName := r.URL.Query().Get(":app") a, err := app.GetByName(appName) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } allowed := permission.Check(t, permission.PermAppUpdateUnitStatus, contextsForApp(a)..., ) if !allowed { return permission.ErrUnauthorized } err = a.SetUnitStatus(unitName, status) if _, ok := err.(*provision.UnitNotFoundError); ok { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } return err }
func moveContainerHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { params, err := unmarshal(r.Body) if err != nil { return err } contId := r.URL.Query().Get(":id") to := params["to"] if to == "" { return fmt.Errorf("Invalid params: id: %s - to: %s", contId, to) } cont, err := mainDockerProvisioner.GetContainer(contId) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } permContexts, err := moveContainersPermissionContexts(cont.HostAddr, to) if err != nil { return err } if !permission.Check(t, permission.PermNode, permContexts...) { return permission.ErrUnauthorized } writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} _, err = mainDockerProvisioner.moveContainer(contId, to, writer) if err != nil { fmt.Fprintf(writer, "Error trying to move container: %s\n", err.Error()) } else { fmt.Fprintf(writer, "Containers moved successfully!\n") } return nil }
func moveContainersHandler(w http.ResponseWriter, r *http.Request, t auth.Token) error { params, err := unmarshal(r.Body) if err != nil { return err } from := params["from"] to := params["to"] if from == "" || to == "" { return fmt.Errorf("Invalid params: from: %s - to: %s", from, to) } permContexts, err := moveContainersPermissionContexts(from, to) if err != nil { return err } if !permission.Check(t, permission.PermNode, permContexts...) { return permission.ErrUnauthorized } writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = mainDockerProvisioner.MoveContainers(from, to, writer) if err != nil { fmt.Fprintf(writer, "Error trying to move containers: %s\n", err.Error()) } else { fmt.Fprintf(writer, "Containers moved successfully!\n") } return nil }
// title: rebuild routes // path: /apps/{app}/routes // method: POST // produce: application/json // responses: // 200: Ok // 401: Unauthorized // 404: App not found func appRebuildRoutes(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { a, err := getAppFromContext(r.URL.Query().Get(":app"), r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppAdminRoutes, contextsForApp(&a)..., ) if !allowed { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: appTarget(a.Name), Kind: permission.PermAppAdminRoutes, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() w.Header().Set("Content-Type", "application/json") result, err := rebuild.RebuildRoutes(&a) if err != nil { return err } return json.NewEncoder(w).Encode(&result) }
// title: app unlock // path: /apps/{app}/lock // method: DELETE // produce: application/json // responses: // 200: Ok // 401: Unauthorized // 404: App not found func forceDeleteLock(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() appName := r.URL.Query().Get(":app") a, err := getAppFromContext(appName, r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppAdminUnlock, contextsForApp(&a)..., ) if !allowed { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: appTarget(appName), Kind: permission.PermAppAdminUnlock, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() app.ReleaseApplicationLock(a.Name) return nil }
// title: update application quota // path: /apps/{appname}/quota // method: PUT // consume: application/x-www-form-urlencoded // responses: // 200: Quota updated // 400: Invalid data // 401: Unauthorized // 404: Application not found func changeAppQuota(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() appName := r.URL.Query().Get(":appname") a, err := getAppFromContext(appName, r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppAdminQuota, contextsForApp(&a)...) if !allowed { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: event.Target{Type: event.TargetTypeApp, Value: appName}, Kind: permission.PermAppAdminQuota, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() limit, err := strconv.Atoi(r.FormValue("limit")) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "Invalid limit", } } return app.ChangeQuota(&a, limit) }
// title: remove role // path: /roles/{name} // method: DELETE // responses: // 200: Role removed // 401: Unauthorized // 404: Role not found func removeRole(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() if !permission.Check(t, permission.PermRoleDelete) { return permission.ErrUnauthorized } roleName := r.URL.Query().Get(":name") evt, err := event.New(&event.Opts{ Target: event.Target{Type: event.TargetTypeRole, Value: roleName}, Kind: permission.PermRoleDelete, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermRoleReadEvents), }) if err != nil { return err } defer func() { evt.Done(err) }() err = auth.RemoveRoleFromAllUsers(roleName) if err != nil { return err } err = permission.DestroyRole(roleName) if err == permission.ErrRoleNotFound { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } return err }
// title: remove units // path: /apps/{name}/units // method: DELETE // produce: application/x-json-stream // responses: // 200: Units removed // 400: Invalid data // 401: Unauthorized // 404: App not found func removeUnits(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { n, err := numberOfUnits(r) if err != nil { return err } processName := r.FormValue("process") appName := r.URL.Query().Get(":app") a, err := getAppFromContext(appName, r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppUpdateUnitRemove, contextsForApp(&a)..., ) if !allowed { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: appTarget(appName), Kind: permission.PermAppUpdateUnitRemove, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() w.Header().Set("Content-Type", "application/x-json-stream") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} return a.RemoveUnits(n, processName, writer) }
// title: dissociate role from user // path: /roles/{name}/user/{email} // method: DELETE // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: Role not found func dissociateRole(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() if !permission.Check(t, permission.PermRoleUpdateDissociate) { return permission.ErrUnauthorized } roleName := r.URL.Query().Get(":name") evt, err := event.New(&event.Opts{ Target: event.Target{Type: event.TargetTypeRole, Value: roleName}, Kind: permission.PermRoleUpdateDissociate, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermRoleReadEvents), }) if err != nil { return err } defer func() { evt.Done(err) }() email := r.URL.Query().Get(":email") contextValue := r.URL.Query().Get("context") user, err := auth.GetUserByEmail(email) if err != nil { return err } err = canUseRole(t, roleName, contextValue) if err != nil { return err } err = runWithPermSync([]auth.User{*user}, func() error { return user.RemoveRole(roleName, contextValue) }) return err }
func platformUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) error { defer r.Body.Close() name := r.URL.Query().Get(":name") file, _, _ := r.FormFile("dockerfile_content") if file != nil { defer file.Close() } args := make(map[string]string) for key, values := range r.Form { args[key] = values[0] } canUpdatePlatform := permission.Check(t, permission.PermPlatformUpdate) if !canUpdatePlatform { return permission.ErrUnauthorized } w.Header().Set("Content-Type", "text") keepAliveWriter := io.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &io.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err := app.PlatformUpdate(provision.PlatformOptions{ Name: name, Args: args, Input: file, Output: writer, }) if err != nil { writer.Encode(io.SimpleJsonMessage{Error: err.Error()}) writer.Write([]byte("Failed to update platform!\n")) return nil } writer.Write([]byte("Platform successfully updated!\n")) return nil }
func templateUpdate(w http.ResponseWriter, r *http.Request, token auth.Token) error { var paramTemplate iaas.Template err := json.NewDecoder(r.Body).Decode(¶mTemplate) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } templateName := r.URL.Query().Get(":template_name") dbTpl, err := iaas.FindTemplate(templateName) if err != nil { if err == mgo.ErrNotFound { return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"} } return err } allowed := permission.Check(token, permission.PermMachineTemplateUpdate, permission.Context(permission.CtxIaaS, dbTpl.IaaSName), ) if !allowed { return permission.ErrUnauthorized } err = dbTpl.Update(¶mTemplate) if err != nil { return err } w.WriteHeader(http.StatusOK) return nil }
// title: remove app // path: /apps/{name} // method: DELETE // produce: application/x-json-stream // responses: // 200: App removed // 401: Unauthorized // 404: Not found func appDelete(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() a, err := getAppFromContext(r.URL.Query().Get(":app"), r) if err != nil { return err } canDelete := permission.Check(t, permission.PermAppDelete, contextsForApp(&a)..., ) if !canDelete { return permission.ErrUnauthorized } evt, err := event.New(&event.Opts{ Target: appTarget(a.Name), Kind: permission.PermAppDelete, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...), }) if err != nil { return err } defer func() { evt.Done(err) }() keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} w.Header().Set("Content-Type", "application/x-json-stream") return app.Delete(&a, writer) }