// title: app swap // path: /swap // method: POST // consume: application/x-www-form-urlencoded // responses: // 200: Ok // 400: Invalid data // 401: Unauthorized // 404: App not found // 409: App locked // 412: Number of units or platform don't match func swap(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { app1Name := r.FormValue("app1") app2Name := r.FormValue("app2") forceSwap := r.FormValue("force") cnameOnly, _ := strconv.ParseBool(r.FormValue("cnameOnly")) if forceSwap == "" { forceSwap = "false" } locked1, err := app.AcquireApplicationLockWait(app1Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app1Name) locked2, err := app.AcquireApplicationLockWait(app2Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app2Name) app1, err := getApp(app1Name) if err != nil { return err } if !locked1 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app1.Name, &app1.Lock)} } app2, err := getApp(app2Name) if err != nil { return err } if !locked2 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app2.Name, &app2.Lock)} } allowed1 := permission.Check(t, permission.PermAppUpdateSwap, contextsForApp(app1)..., ) allowed2 := permission.Check(t, permission.PermAppUpdateSwap, contextsForApp(app2)..., ) if !allowed1 || !allowed2 { return permission.ErrUnauthorized } evt1, err := event.New(&event.Opts{ Target: appTarget(app1Name), Kind: permission.PermAppUpdateSwap, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(app1)...), }) if err != nil { return err } evt2, err := event.New(&event.Opts{ Target: appTarget(app2Name), Kind: permission.PermAppUpdateSwap, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermAppReadEvents, contextsForApp(app2)...), }) if err != nil { return err } defer func() { evt1.Done(err); evt2.Done(err) }() // compare apps by platform type and number of units if forceSwap == "false" { if app1.Platform != app2.Platform { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "platforms don't match", } } app1Units, err := app1.Units() if err != nil { return err } app2Units, err := app2.Units() if err != nil { return err } if len(app1Units) != len(app2Units) { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "number of units doesn't match", } } } return app.Swap(app1, app2, cnameOnly) }
func swap(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } app1Name := r.URL.Query().Get("app1") app2Name := r.URL.Query().Get("app2") forceSwap := r.URL.Query().Get("force") if forceSwap == "" { forceSwap = "false" } locked1, err := app.AcquireApplicationLockWait(app1Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app1Name) locked2, err := app.AcquireApplicationLockWait(app2Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app2Name) app1, err := getApp(app1Name, u) if err != nil { return err } if !locked1 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app1.Name, &app1.Lock)} } app2, err := getApp(app2Name, u) if err != nil { return err } if !locked2 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app2.Name, &app2.Lock)} } // compare apps by platform type and number of units if forceSwap == "false" { if app1.Platform != app2.Platform { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "platforms don't match", } } app1Units, err := app1.Units() if err != nil { return err } app2Units, err := app2.Units() if err != nil { return err } if len(app1Units) != len(app2Units) { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "number of units doesn't match", } } } rec.Log(u.Email, "swap", "app1="+app1Name, "app2="+app2Name) return app.Swap(app1, app2) }
func swap(w http.ResponseWriter, r *http.Request, t auth.Token) error { getApp := func(name string, u *auth.User, r *http.Request) (app.App, error) { a, err := app.GetByName(name) if err != nil { return app.App{}, &errors.HTTP{Code: http.StatusNotFound, Message: fmt.Sprintf("App %s not found.", name)} } if u == nil || u.IsAdmin() { return *a, nil } if !auth.CheckUserAccess(a.Teams, u) { return *a, &errors.HTTP{Code: http.StatusForbidden, Message: "user does not have access to this app"} } return *a, nil } u, err := t.User() if err != nil { return err } app1Name := r.URL.Query().Get("app1") app2Name := r.URL.Query().Get("app2") forceSwap := r.URL.Query().Get("force") if forceSwap == "" { forceSwap = "false" } locked1, err := app.AcquireApplicationLockWait(app1Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app1Name) locked2, err := app.AcquireApplicationLockWait(app2Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app2Name) app1, err := getApp(app1Name, u, r) if err != nil { return err } if !locked1 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app1.Name, &app1.Lock)} } app2, err := getApp(app2Name, u, r) if err != nil { return err } if !locked2 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app2.Name, &app2.Lock)} } // compare apps by platform type and number of units if forceSwap == "false" { if app1.Platform != app2.Platform { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "platforms don't match", } } if len(app1.Units()) != len(app2.Units()) { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "number of units doesn't match", } } } rec.Log(u.Email, "swap", "app1="+app1Name, "app2="+app2Name) return app.Swap(&app1, &app2) }
func (m *appLockMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { if r.Method == "GET" { next(w, r) return } currentHandler := context.GetDelayedHandler(r) if currentHandler != nil { currentHandlerPtr := reflect.ValueOf(currentHandler).Pointer() for _, h := range m.excludedHandlers { if reflect.ValueOf(h).Pointer() == currentHandlerPtr { next(w, r) return } } } appName := r.URL.Query().Get(":app") if appName == "" { appName = r.URL.Query().Get(":appname") } if appName == "" { next(w, r) return } t := context.GetAuthToken(r) var owner string if t != nil { if t.IsAppToken() { owner = t.GetAppName() } else { owner = t.GetUserName() } } _, err := app.GetByName(appName) if err == app.ErrAppNotFound { context.AddRequestError(r, &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}) return } ok, err := app.AcquireApplicationLockWait(appName, owner, fmt.Sprintf("%s %s", r.Method, r.URL.Path), lockWaitDuration) if err != nil { context.AddRequestError(r, fmt.Errorf("Error trying to acquire application lock: %s", err)) return } if ok { defer func() { if !context.IsPreventUnlock(r) { app.ReleaseApplicationLock(appName) } }() next(w, r) return } a, err := app.GetByName(appName) httpErr := &errors.HTTP{Code: http.StatusInternalServerError} if err != nil { if err == app.ErrAppNotFound { httpErr.Code = http.StatusNotFound httpErr.Message = err.Error() } else { httpErr.Message = fmt.Sprintf("Error to get application: %s", err) } } else { httpErr.Code = http.StatusConflict if a.Lock.Locked { httpErr.Message = fmt.Sprintf("%s", &a.Lock) } else { httpErr.Message = "Not locked anymore, please try again." } } context.AddRequestError(r, httpErr) }
func swap(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } app1Name := r.URL.Query().Get("app1") app2Name := r.URL.Query().Get("app2") forceSwap := r.URL.Query().Get("force") cnameOnly, _ := strconv.ParseBool(r.URL.Query().Get("cnameOnly")) if forceSwap == "" { forceSwap = "false" } locked1, err := app.AcquireApplicationLockWait(app1Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app1Name) locked2, err := app.AcquireApplicationLockWait(app2Name, t.GetUserName(), "/swap", lockWaitDuration) if err != nil { return err } defer app.ReleaseApplicationLock(app2Name) app1, err := getApp(app1Name) if err != nil { return err } if !locked1 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app1.Name, &app1.Lock)} } app2, err := getApp(app2Name) if err != nil { return err } if !locked2 { return &errors.HTTP{Code: http.StatusConflict, Message: fmt.Sprintf("%s: %s", app2.Name, &app2.Lock)} } allowed1 := permission.Check(t, permission.PermAppUpdateSwap, append(permission.Contexts(permission.CtxTeam, app1.Teams), permission.Context(permission.CtxApp, app1.Name), permission.Context(permission.CtxPool, app1.Pool), )..., ) allowed2 := permission.Check(t, permission.PermAppUpdateSwap, append(permission.Contexts(permission.CtxTeam, app2.Teams), permission.Context(permission.CtxApp, app2.Name), permission.Context(permission.CtxPool, app2.Pool), )..., ) if !allowed1 || !allowed2 { return permission.ErrUnauthorized } // compare apps by platform type and number of units if forceSwap == "false" { if app1.Platform != app2.Platform { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "platforms don't match", } } app1Units, err := app1.Units() if err != nil { return err } app2Units, err := app2.Units() if err != nil { return err } if len(app1Units) != len(app2Units) { return &errors.HTTP{ Code: http.StatusPreconditionFailed, Message: "number of units doesn't match", } } } rec.Log(u.Email, "swap", "app1="+app1Name, "app2="+app2Name) return app.Swap(app1, app2, cnameOnly) }