func appList(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } extra := make([]interface{}, 0, 1) filter := &app.Filter{} if name := r.URL.Query().Get("name"); name != "" { extra = append(extra, fmt.Sprintf("name=%s", name)) filter.NameMatches = name } if platform := r.URL.Query().Get("platform"); platform != "" { extra = append(extra, fmt.Sprintf("platform=%s", platform)) filter.Platform = platform } if teamOwner := r.URL.Query().Get("teamOwner"); teamOwner != "" { extra = append(extra, fmt.Sprintf("teamowner=%s", teamOwner)) filter.TeamOwner = teamOwner } if owner := r.URL.Query().Get("owner"); owner != "" { extra = append(extra, fmt.Sprintf("owner=%s", owner)) filter.UserOwner = owner } if pool := r.URL.Query().Get("pool"); pool != "" { extra = append(extra, fmt.Sprintf("pool=%s", pool)) filter.Pool = pool } locked, _ := strconv.ParseBool(r.URL.Query().Get("locked")) if locked { extra = append(extra, fmt.Sprintf("locked=%v", locked)) filter.Locked = true } if status, ok := r.URL.Query()["status"]; ok { extra = append(extra, fmt.Sprintf("status=%s", strings.Join(status, ","))) filter.Statuses = status } rec.Log(u.Email, "app-list", extra...) contexts := permission.ContextsForPermission(t, permission.PermAppRead) if len(contexts) == 0 { w.WriteHeader(http.StatusNoContent) return nil } apps, err := app.List(appFilterByContext(contexts, filter)) if err != nil { return err } if len(apps) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") miniApps := make([]miniApp, len(apps)) for i, app := range apps { miniApps[i], err = minifyApp(app) if err != nil { return err } } return json.NewEncoder(w).Encode(miniApps) }
// title: machine template list // path: /iaas/templates // method: GET // produce: application/json // responses: // 200: OK // 401: Unauthorized func templatesList(w http.ResponseWriter, r *http.Request, token auth.Token) error { templates, err := iaas.ListTemplates() if err != nil { return err } contexts := permission.ContextsForPermission(token, permission.PermMachineTemplateRead) allowedIaaS := map[string]struct{}{} for _, c := range contexts { if c.CtxType == permission.CtxGlobal { allowedIaaS = nil break } if c.CtxType == permission.CtxIaaS { allowedIaaS[c.Value] = struct{}{} } } for i := 0; allowedIaaS != nil && i < len(templates); i++ { if _, ok := allowedIaaS[templates[i].IaaSName]; !ok { templates = append(templates[:i], templates[i+1:]...) i-- } } w.Header().Add("Content-Type", "application/json") return json.NewEncoder(w).Encode(templates) }
// title: service list // path: /services // method: GET // produce: application/json // responses: // 200: List services // 204: No content // 401: Unauthorized func serviceList(w http.ResponseWriter, r *http.Request, t auth.Token) error { contexts := permission.ContextsForPermission(t, permission.PermServiceRead) services, err := provisionReadableServices(t, contexts) if err != nil { return err } sInstances, err := service.GetServiceInstancesByServices(services) if err != nil { return err } results := make([]service.ServiceModel, len(services)) for i, s := range services { results[i].Service = s.Name for _, si := range sInstances { if si.ServiceName == s.Name { results[i].Instances = append(results[i].Instances, si.Name) } } } if len(results) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(results) }
func machinesList(w http.ResponseWriter, r *http.Request, token auth.Token) error { machines, err := iaas.ListMachines() if err != nil { return err } contexts := permission.ContextsForPermission(token, permission.PermMachineRead) allowedIaaS := map[string]struct{}{} for _, c := range contexts { if c.CtxType == permission.CtxGlobal { allowedIaaS = nil break } if c.CtxType == permission.CtxIaaS { allowedIaaS[c.Value] = struct{}{} } } for i := 0; allowedIaaS != nil && i < len(machines); i++ { if _, ok := allowedIaaS[machines[i].Iaas]; !ok { machines = append(machines[:i], machines[i+1:]...) i-- } } err = json.NewEncoder(w).Encode(machines) if err != nil { return err } return nil }
func listPoolsToUser(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "pool-list") teams := []string{} contexts := permission.ContextsForPermission(t, permission.PermAppCreate) for _, c := range contexts { if c.CtxType == permission.CtxGlobal { teams = nil break } if c.CtxType != permission.CtxTeam { continue } teams = append(teams, c.Value) } var filter bson.M if teams != nil { filter = bson.M{"teams": bson.M{"$in": teams}} } pools, err := provision.ListPools(filter) if err != nil { return err } poolsByTeam := []PoolsByTeam{} poolsByTeamMap := map[string]*PoolsByTeam{} for _, p := range pools { for _, t := range p.Teams { if poolsByTeamMap[t] == nil { poolsByTeam = append(poolsByTeam, PoolsByTeam{Team: t}) poolsByTeamMap[t] = &poolsByTeam[len(poolsByTeam)-1] } poolsByTeamMap[t].Pools = append(poolsByTeamMap[t].Pools, p.Name) } } publicPools, err := provision.ListPools(bson.M{"public": true}) if err != nil { return err } allowedDefault := permission.Check(t, permission.PermPoolUpdate) defaultPool := []provision.Pool{} if allowedDefault { defaultPool, err = provision.ListPools(bson.M{"default": true}) if err != nil { return err } } p := map[string]interface{}{ "pools_by_team": poolsByTeam, "public_pools": publicPools, "default_pool": defaultPool, } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(p) }
// title: service instance list // path: /services/instances // method: GET // produce: application/json // responses: // 200: List services instances // 204: No content // 401: Unauthorized func serviceInstances(w http.ResponseWriter, r *http.Request, t auth.Token) error { appName := r.URL.Query().Get("app") contexts := permission.ContextsForPermission(t, permission.PermServiceInstanceRead) instances, err := readableInstances(t, contexts, appName, "") if err != nil { return err } contexts = permission.ContextsForPermission(t, permission.PermServiceRead) services, err := readableServices(t, contexts) if err != nil { return err } servicesMap := map[string]*service.ServiceModel{} for _, s := range services { if _, in := servicesMap[s.Name]; !in { servicesMap[s.Name] = &service.ServiceModel{ Service: s.Name, Instances: []string{}, } } } for _, instance := range instances { entry := servicesMap[instance.ServiceName] if entry == nil { continue } entry.Instances = append(entry.Instances, instance.Name) entry.Plans = append(entry.Plans, instance.PlanName) } result := []service.ServiceModel{} for _, entry := range servicesMap { result = append(result, *entry) } if len(result) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(result) }
// title: service info // path: /services/{name} // method: GET // produce: application/json // responses: // 200: OK func serviceInfo(w http.ResponseWriter, r *http.Request, t auth.Token) error { serviceName := r.URL.Query().Get(":name") _, err := getService(serviceName) if err != nil { return err } contexts := permission.ContextsForPermission(t, permission.PermServiceInstanceRead) instances, err := readableInstances(t, contexts, "", serviceName) if err != nil { return err } return json.NewEncoder(w).Encode(instances) }
// title: service list // path: /services // method: GET // produce: application/json // responses: // 200: List services // 204: No content // 401: Unauthorized func serviceList(w http.ResponseWriter, r *http.Request, t auth.Token) error { rec.Log(t.GetUserName(), "list-services") teams := []string{} serviceNames := []string{} contexts := permission.ContextsForPermission(t, permission.PermServiceRead) for _, c := range contexts { if c.CtxType == permission.CtxGlobal { teams = nil serviceNames = nil break } switch c.CtxType { case permission.CtxService: serviceNames = append(serviceNames, c.Value) case permission.CtxTeam: teams = append(teams, c.Value) } } services, err := service.GetServicesByOwnerTeamsAndServices(teams, serviceNames) if err != nil { return err } sInstances, err := service.GetServiceInstancesByServices(services) if err != nil { return err } results := make([]service.ServiceModel, len(services)) for i, s := range services { results[i].Service = s.Name for _, si := range sInstances { if si.ServiceName == s.Name { results[i].Instances = append(results[i].Instances, si.Name) } } } if len(results) == 0 { w.WriteHeader(http.StatusNoContent) return nil } b, err := json.Marshal(results) if err != nil { return &errors.HTTP{Code: http.StatusInternalServerError, Message: err.Error()} } n, err := w.Write(b) if n != len(b) { return &errors.HTTP{Code: http.StatusInternalServerError, Message: "Failed to write response body"} } w.Header().Set("Content-Type", "application/json") return err }
func listContextValues(t permission.Token, scheme *permission.PermissionScheme, failIfEmpty bool) ([]string, error) { contexts := permission.ContextsForPermission(t, scheme) if len(contexts) == 0 && failIfEmpty { return nil, permission.ErrUnauthorized } values := make([]string, 0, len(contexts)) for _, ctx := range contexts { if ctx.CtxType == permission.CtxGlobal { return nil, nil } values = append(values, ctx.Value) } return values, nil }
func serviceCreate(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 sy serviceYaml err = yaml.Unmarshal(body, &sy) if err != nil { return err } teamContexts := permission.ContextsForPermission(t, permission.PermServiceCreate, permission.CtxTeam) if sy.Team == "" && len(teamContexts) == 1 { sy.Team = teamContexts[0].Value } err = sy.validate() if err != nil { return err } if sy.Team == "" { return &errors.HTTP{Code: http.StatusBadRequest, Message: "You must provide a team responsible for this service in the manifest file."} } allowed := permission.Check(t, permission.PermServiceCreate, permission.Context(permission.CtxTeam, sy.Team), ) if !allowed { return permission.ErrUnauthorized } rec.Log(t.GetUserName(), "create-service", sy.Id, sy.Endpoint) s := service.Service{ Name: sy.Id, Username: sy.Username, Endpoint: sy.Endpoint, Password: sy.Password, OwnerTeams: []string{sy.Team}, } err = s.Create() if err != nil { httpError := http.StatusInternalServerError if err == service.ErrServiceAlreadyExists { httpError = http.StatusConflict } return &errors.HTTP{Code: httpError, Message: err.Error()} } fmt.Fprint(w, "success") return nil }
// title: app list // path: /apps // method: GET // produce: application/json // responses: // 200: List apps // 204: No content // 401: Unauthorized func appList(w http.ResponseWriter, r *http.Request, t auth.Token) error { filter := &app.Filter{} if name := r.URL.Query().Get("name"); name != "" { filter.NameMatches = name } if platform := r.URL.Query().Get("platform"); platform != "" { filter.Platform = platform } if teamOwner := r.URL.Query().Get("teamOwner"); teamOwner != "" { filter.TeamOwner = teamOwner } if owner := r.URL.Query().Get("owner"); owner != "" { filter.UserOwner = owner } if pool := r.URL.Query().Get("pool"); pool != "" { filter.Pool = pool } locked, _ := strconv.ParseBool(r.URL.Query().Get("locked")) if locked { filter.Locked = true } if status, ok := r.URL.Query()["status"]; ok { filter.Statuses = status } contexts := permission.ContextsForPermission(t, permission.PermAppRead) if len(contexts) == 0 { w.WriteHeader(http.StatusNoContent) return nil } apps, err := app.List(appFilterByContext(contexts, filter)) if err != nil { return err } if len(apps) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") miniApps := make([]miniApp, len(apps)) for i, app := range apps { miniApps[i], err = minifyApp(app) if err != nil { return err } } return json.NewEncoder(w).Encode(miniApps) }
func readableServices(t auth.Token) ([]service.Service, error) { teams := []string{} serviceNames := []string{} contexts := permission.ContextsForPermission(t, permission.PermServiceRead) for _, c := range contexts { if c.CtxType == permission.CtxGlobal { teams = nil serviceNames = nil break } switch c.CtxType { case permission.CtxService: serviceNames = append(serviceNames, c.Value) case permission.CtxTeam: teams = append(teams, c.Value) } } return service.GetServicesByTeamsAndServices(teams, serviceNames) }
func deploysList(w http.ResponseWriter, r *http.Request, t auth.Token) error { contexts := permission.ContextsForPermission(t, permission.PermAppReadDeploy) if len(contexts) == 0 { w.WriteHeader(http.StatusNoContent) return nil } filter := appFilterByContext(contexts, nil) filter.Name = r.URL.Query().Get("app") skip := r.URL.Query().Get("skip") limit := r.URL.Query().Get("limit") skipInt, _ := strconv.Atoi(skip) limitInt, _ := strconv.Atoi(limit) deploys, err := app.ListDeploys(filter, skipInt, limitInt) if err != nil { return err } if len(deploys) == 0 { w.WriteHeader(http.StatusNoContent) return nil } return json.NewEncoder(w).Encode(deploys) }
func readableInstances(t auth.Token, appName, serviceName string) ([]service.ServiceInstance, error) { teams := []string{} instanceNames := []string{} contexts := permission.ContextsForPermission(t, permission.PermServiceInstanceRead) for _, c := range contexts { if c.CtxType == permission.CtxGlobal { teams = nil instanceNames = nil break } switch c.CtxType { case permission.CtxServiceInstance: parts := strings.SplitAfterN(c.Value, "/", 2) if len(parts) == 2 && parts[0] == serviceName { instanceNames = append(instanceNames, parts[1]) } case permission.CtxTeam: teams = append(teams, c.Value) } } return service.GetServicesInstancesByTeamsAndNames(teams, instanceNames, appName, serviceName) }
// title: pool list // path: /pools // method: GET // produce: application/json // responses: // 200: OK // 204: No content // 401: Unauthorized // 404: User not found func poolList(w http.ResponseWriter, r *http.Request, t auth.Token) error { teams := []string{} contexts := permission.ContextsForPermission(t, permission.PermAppCreate) for _, c := range contexts { if c.CtxType == permission.CtxGlobal { teams = nil break } if c.CtxType != permission.CtxTeam { continue } teams = append(teams, c.Value) } pools, err := provision.ListPossiblePools(teams) if err != nil { return err } if len(pools) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(pools) }
func createApp(w http.ResponseWriter, r *http.Request, t auth.Token) error { var a app.App defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if err = json.Unmarshal(body, &a); err != nil { return err } teamContexts := permission.ContextsForPermission(t, permission.PermAppCreate, permission.CtxTeam) if a.TeamOwner == "" && len(teamContexts) == 1 { a.TeamOwner = teamContexts[0].Value } canCreate := permission.Check(t, permission.PermAppCreate, permission.Context(permission.CtxTeam, a.TeamOwner), ) if !canCreate { return permission.ErrUnauthorized } u, err := t.User() if err != nil { return err } platform, err := app.GetPlatform(a.Platform) if err != nil { return err } if platform.Disabled { canUsePlat := permission.Check(t, permission.PermPlatformUpdate) || permission.Check(t, permission.PermPlatformCreate) if !canUsePlat { return app.InvalidPlatformError{} } } rec.Log(u.Email, "create-app", "app="+a.Name, "platform="+a.Platform, "plan="+a.Plan.Name) err = app.CreateApp(&a, u) if err != nil { log.Errorf("Got error while creating app: %s", err) if e, ok := err.(*errors.ValidationError); ok { return &errors.HTTP{Code: http.StatusBadRequest, Message: e.Message} } if _, ok := err.(app.NoTeamsError); ok { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "In order to create an app, you should be member of at least one team", } } if e, ok := err.(*app.AppCreationError); ok { if e.Err == app.ErrAppAlreadyExists { return &errors.HTTP{Code: http.StatusConflict, Message: e.Error()} } if _, ok := e.Err.(*quota.QuotaExceededError); ok { return &errors.HTTP{ Code: http.StatusForbidden, Message: "Quota exceeded", } } } if e, ok := err.(app.InvalidPlatformError); ok { return &errors.HTTP{Code: http.StatusNotFound, Message: e.Error()} } return err } repo, _ := repository.Manager().GetRepository(a.Name) msg := map[string]string{ "status": "success", "repository_url": repo.ReadWriteURL, "ip": a.Ip, } jsonMsg, err := json.Marshal(msg) if err != nil { return err } fmt.Fprintf(w, "%s", jsonMsg) return nil }
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"], } if instance.TeamOwner == "" { allContexts := permission.ContextsForPermission(t, permission.PermServiceInstanceCreate) teams := make([]string, 0, len(allContexts)) for _, ctx := range allContexts { if ctx.CtxType == permission.CtxGlobal { teams = nil break } if ctx.CtxType == permission.CtxTeam { teams = append(teams, ctx.Value) } } if teams != nil && len(teams) == 0 { return permission.ErrUnauthorized } if len(teams) == 1 { instance.TeamOwner = teams[0] } } if instance.TeamOwner == "" { return &errors.HTTP{Code: http.StatusBadRequest, Message: "You must provide a team to create this service instance."} } 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) }