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")
	locked1, err := app.AcquireApplicationLock(app1Name, t.GetUserName(), "/swap")
	if err != nil {
		return err
	}
	defer app.ReleaseApplicationLock(app1Name)
	locked2, err := app.AcquireApplicationLock(app2Name, t.GetUserName(), "/swap")
	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)}
	}
	rec.Log(u.Email, "swap", app1Name, app2Name)
	return app.Swap(&app1, &app2)
}
Exemple #2
0
func (p *dockerProvisioner) runningContainersByNode(nodes []*cluster.Node) (map[string][]container.Container, error) {
	appNames, err := p.listAppsForNodes(nodes)
	if err != nil {
		return nil, err
	}
	for _, appName := range appNames {
		locked, err := app.AcquireApplicationLock(appName, app.InternalAppName, "node auto scale")
		if err != nil {
			return nil, err
		}
		if !locked {
			return nil, fmt.Errorf("unable to lock app %s, aborting", appName)
		}
		defer app.ReleaseApplicationLock(appName)
	}
	result := map[string][]container.Container{}
	for _, n := range nodes {
		nodeConts, err := p.listRunningContainersByHost(urlToHost(n.Address))
		if err != nil {
			return nil, err
		}
		result[n.Address] = nodeConts
	}
	return result, nil
}
Exemple #3
0
// 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
}
Exemple #4
0
func (s *S) TestRoutesRebuildOrEnqueueLocked(c *check.C) {
	err := s.p.Initialize()
	c.Assert(err, check.IsNil)
	coll := s.storage.Apps()
	a := &app.App{
		Name:     "almah",
		Platform: "static",
	}
	err = coll.Insert(a)
	c.Assert(err, check.IsNil)
	locked, err := app.AcquireApplicationLock(a.Name, "me", "mine")
	c.Assert(err, check.IsNil)
	c.Assert(locked, check.Equals, true)
	err = s.p.Provision(a)
	c.Assert(err, check.IsNil)
	invalidAddr, err := url.Parse("http://invalid.addr")
	c.Assert(err, check.IsNil)
	err = routertest.FakeRouter.AddRoute(a.GetName(), invalidAddr)
	c.Assert(err, check.IsNil)
	lockedRoutesRebuildOrEnqueue(a.GetName())
	c.Assert(routertest.FakeRouter.HasRoute(a.GetName(), invalidAddr.String()), check.Equals, true)
	app.ReleaseApplicationLock(a.Name)
	err = queue.TestingWaitQueueTasks(1, 10*time.Second)
	c.Assert(err, check.IsNil)
	c.Assert(routertest.FakeRouter.HasRoute(a.GetName(), invalidAddr.String()), check.Equals, false)
}
Exemple #5
0
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.AcquireApplicationLock(app1Name, t.GetUserName(), "/swap")
	if err != nil {
		return err
	}
	defer app.ReleaseApplicationLock(app1Name)
	locked2, err := app.AcquireApplicationLock(app2Name, t.GetUserName(), "/swap")
	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" && ((len(app1.Units()) != len(app2.Units())) || (app1.Platform != app2.Platform)) {
		return app.ErrAppNotEqual
	}
	rec.Log(u.Email, "swap", app1Name, app2Name)
	return app.Swap(&app1, &app2)
}
Exemple #6
0
func (l *appLocker) Unlock(appName string) {
	l.mut.Lock()
	defer l.mut.Unlock()
	if l.refCount == nil {
		return
	}
	l.refCount[appName]--
	if l.refCount[appName] <= 0 {
		l.refCount[appName] = 0
		app.ReleaseApplicationLock(appName)
	}
}
Exemple #7
0
func (l *appLocker) unlock(appName string) {
	appDBMutex.Lock()
	defer appDBMutex.Unlock()
	if l.refCount == nil {
		return
	}
	l.refCount[appName]--
	if l.refCount[appName] <= 0 {
		l.refCount[appName] = 0
		app.ReleaseApplicationLock(appName)
	}
}
Exemple #8
0
func forceDeleteLock(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	appName := r.URL.Query().Get(":app")
	a, err := getAppFromContext(appName, r)
	if err != nil {
		return err
	}
	allowed := permission.Check(t, permission.PermAppAdminUnlock,
		append(permission.Contexts(permission.CtxTeam, a.Teams),
			permission.Context(permission.CtxApp, a.Name),
			permission.Context(permission.CtxPool, a.Pool),
		)...,
	)
	if !allowed {
		return permission.ErrUnauthorized
	}
	app.ReleaseApplicationLock(a.Name)
	w.WriteHeader(http.StatusNoContent)
	return nil
}
Exemple #9
0
func (s *S) TestRoutesRebuildOrEnqueueLocked(c *check.C) {
	a := &app.App{
		Name:      "almah",
		Platform:  "static",
		TeamOwner: s.team.Name,
	}
	err := app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	locked, err := app.AcquireApplicationLock(a.Name, "me", "mine")
	c.Assert(err, check.IsNil)
	c.Assert(locked, check.Equals, true)
	invalidAddr, err := url.Parse("http://invalid.addr")
	c.Assert(err, check.IsNil)
	err = routertest.FakeRouter.AddRoute(a.GetName(), invalidAddr)
	c.Assert(err, check.IsNil)
	rebuild.LockedRoutesRebuildOrEnqueue(a.GetName())
	c.Assert(routertest.FakeRouter.HasRoute(a.GetName(), invalidAddr.String()), check.Equals, true)
	app.ReleaseApplicationLock(a.Name)
	err = queue.TestingWaitQueueTasks(1, 10*time.Second)
	c.Assert(err, check.IsNil)
	c.Assert(routertest.FakeRouter.HasRoute(a.GetName(), invalidAddr.String()), check.Equals, false)
}
Exemple #10
0
func runRoutesRebuildOnce(appName string, lock bool) bool {
	if lock {
		locked, err := app.AcquireApplicationLock(appName, app.InternalAppName, "rebuild-routes-task")
		if err != nil || !locked {
			return false
		}
		defer app.ReleaseApplicationLock(appName)
	}
	a, err := app.GetByName(appName)
	if err == app.ErrAppNotFound {
		return true
	}
	if err != nil {
		log.Errorf("[routes-rebuild-task] error getting app: %s", err)
		return false
	}
	_, err = a.RebuildRoutes()
	if err != nil {
		log.Errorf("[routes-rebuild-task] error rebuilding: %s", err)
		return false
	}
	return true
}
Exemple #11
0
func (s *S) TestAppLockMiddlewareWaitForLock(c *check.C) {
	myApp := app.App{
		Name: "my-app",
		Lock: app.AppLock{
			Locked:      true,
			Reason:      "/app/my-app/deploy",
			Owner:       "someone",
			AcquireDate: time.Date(2048, time.November, 10, 10, 0, 0, 0, time.UTC),
		},
	}
	err := s.conn.Apps().Insert(myApp)
	c.Assert(err, check.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": myApp.Name})
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("POST", "/?:app=my-app", nil)
	c.Assert(err, check.IsNil)
	called := false
	wg := sync.WaitGroup{}
	wg.Add(1)
	defer wg.Wait()
	go func() {
		defer wg.Done()
		time.Sleep(1 * time.Second)
		app.ReleaseApplicationLock(myApp.Name)
	}()
	m := &appLockMiddleware{}
	m.ServeHTTP(recorder, request, func(w http.ResponseWriter, r *http.Request) {
		a, err := app.GetByName(request.URL.Query().Get(":app"))
		c.Assert(err, check.IsNil)
		c.Assert(a.Lock.Locked, check.Equals, true)
		called = true
	})
	c.Assert(called, check.Equals, true)
	a, err := app.GetByName(request.URL.Query().Get(":app"))
	c.Assert(err, check.IsNil)
	c.Assert(a.Lock.Locked, check.Equals, false)
}
Exemple #12
0
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)
}
Exemple #13
0
// 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)
}
Exemple #14
0
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)
}
Exemple #15
0
func forceDeleteLock(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	appName := r.URL.Query().Get(":app")
	app.ReleaseApplicationLock(appName)
	w.WriteHeader(http.StatusNoContent)
	return nil
}
Exemple #16
0
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)
}
Exemple #17
0
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)
}