// title: saml callback // path: /auth/saml // method: POST // responses: // 200: Ok // 400: Invalid data func samlCallbackLogin(w http.ResponseWriter, r *http.Request) error { if app.AuthScheme.Name() != "saml" { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "This URL is only supported with saml enabled", } } params := map[string]string{} content := r.PostFormValue("SAMLResponse") if content == "" { return &errors.HTTP{Code: http.StatusBadRequest, Message: "Empty SAML Response"} } params["callback"] = "true" params["xml"] = content //Get saml.SAMLAuthScheme, error already treated on first check scheme, _ := auth.GetScheme("saml") _, err := scheme.Login(params) if err != nil { msg := fmt.Sprintf(cmd.SamlCallbackFailureMessage(), err.Error()) fmt.Fprintf(w, msg) } else { fmt.Fprintf(w, cmd.SamlCallbackSuccessMessage()) } return nil }
func (createRootUserCmd) Run(context *cmd.Context, client *cmd.Client) error { context.RawOutput() scheme, err := config.GetString("auth:scheme") if err != nil { scheme = "native" } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { return err } email := context.Args[0] user, err := auth.GetUserByEmail(email) if err == nil { err = addSuperRole(user) if err != nil { return err } fmt.Fprintln(context.Stdout, "Root user successfully updated.") } var confirm, password string if scheme == "native" { fmt.Fprint(context.Stdout, "Password: "******"\nConfirm: ") confirm, err = cmd.PasswordFromReader(context.Stdin) if err != nil { return err } fmt.Fprintln(context.Stdout) if password != confirm { return errors.New("Passwords didn't match.") } } user, err = app.AuthScheme.Create(&auth.User{ Email: email, Password: password, }) if err != nil { return err } err = addSuperRole(user) if err != nil { return err } fmt.Fprintln(context.Stdout, "Root user successfully created.") return nil }
func (tokenCmd) Run(context *cmd.Context, client *cmd.Client) error { scheme, err := config.GetString("auth:scheme") if err != nil { scheme = "native" } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { return err } t, err := app.AuthScheme.AppLogin(app.InternalAppName) if err != nil { return err } fmt.Fprintln(context.Stdout, t.GetValue()) return nil }
// RunServer starts tsuru API server. The dry parameter indicates whether the // server should run in dry mode, not starting the HTTP listener (for testing // purposes). func RunServer(dry bool) http.Handler { log.Init() connString, err := config.GetString("database:url") if err != nil { connString = db.DefaultDatabaseURL } dbName, err := config.GetString("database:name") if err != nil { dbName = db.DefaultDatabaseName } fmt.Printf("Using mongodb database %q from the server %q.\n", dbName, connString) m := &delayedRouter{} for _, handler := range tsuruHandlerList { m.Add(handler.method, handler.path, handler.h) } if disableIndex, _ := config.GetBool("disable-index-page"); !disableIndex { m.Add("Get", "/", Handler(index)) } m.Add("Get", "/info", Handler(info)) m.Add("Get", "/services/instances", authorizationRequiredHandler(serviceInstances)) m.Add("Get", "/services/instances/{name}", authorizationRequiredHandler(serviceInstance)) m.Add("Delete", "/services/instances/{name}", authorizationRequiredHandler(removeServiceInstance)) m.Add("Post", "/services/instances", authorizationRequiredHandler(createServiceInstance)) m.Add("Put", "/services/instances/{instance}/{app}", authorizationRequiredHandler(bindServiceInstance)) m.Add("Delete", "/services/instances/{instance}/{app}", authorizationRequiredHandler(unbindServiceInstance)) m.Add("Get", "/services/instances/{instance}/status", authorizationRequiredHandler(serviceInstanceStatus)) m.Add("Put", "/services/instances/permission/{instance}/{team}", authorizationRequiredHandler(serviceInstanceGrantTeam)) m.Add("Delete", "/services/instances/permission/{instance}/{team}", authorizationRequiredHandler(serviceInstanceRevokeTeam)) m.AddAll("/services/proxy/{instance}", authorizationRequiredHandler(serviceInstanceProxy)) m.AddAll("/services/proxy/service/{service}", authorizationRequiredHandler(serviceProxy)) m.Add("Get", "/services", authorizationRequiredHandler(serviceList)) m.Add("Post", "/services", authorizationRequiredHandler(serviceCreate)) m.Add("Put", "/services", authorizationRequiredHandler(serviceUpdate)) m.Add("Delete", "/services/{name}", authorizationRequiredHandler(serviceDelete)) m.Add("Get", "/services/{name}", authorizationRequiredHandler(serviceInfo)) m.Add("Get", "/services/{name}/plans", authorizationRequiredHandler(servicePlans)) m.Add("Get", "/services/{name}/doc", authorizationRequiredHandler(serviceDoc)) m.Add("Put", "/services/{name}/doc", authorizationRequiredHandler(serviceAddDoc)) m.Add("Put", "/services/{service}/team/{team}", authorizationRequiredHandler(grantServiceAccess)) m.Add("Delete", "/services/{service}/team/{team}", authorizationRequiredHandler(revokeServiceAccess)) m.Add("Delete", "/apps/{app}", authorizationRequiredHandler(appDelete)) m.Add("Get", "/apps/{app}", authorizationRequiredHandler(appInfo)) m.Add("Post", "/apps/{app}/cname", authorizationRequiredHandler(setCName)) m.Add("Delete", "/apps/{app}/cname", authorizationRequiredHandler(unsetCName)) m.Add("Post", "/apps/{app}/plan", authorizationRequiredHandler(changePlan)) runHandler := authorizationRequiredHandler(runCommand) m.Add("Post", "/apps/{app}/run", runHandler) m.Add("Post", "/apps/{app}/restart", authorizationRequiredHandler(restart)) m.Add("Post", "/apps/{app}/start", authorizationRequiredHandler(start)) m.Add("Post", "/apps/{app}/stop", authorizationRequiredHandler(stop)) m.Add("Get", "/apps/{appname}/quota", AdminRequiredHandler(getAppQuota)) m.Add("Post", "/apps/{appname}/quota", AdminRequiredHandler(changeAppQuota)) m.Add("Get", "/apps/{app}/env", authorizationRequiredHandler(getEnv)) m.Add("Post", "/apps/{app}/env", authorizationRequiredHandler(setEnv)) m.Add("Delete", "/apps/{app}/env", authorizationRequiredHandler(unsetEnv)) m.Add("Get", "/apps", authorizationRequiredHandler(appList)) m.Add("Post", "/apps", authorizationRequiredHandler(createApp)) m.Add("Post", "/apps/{app}/team-owner", authorizationRequiredHandler(setTeamOwner)) forceDeleteLockHandler := AdminRequiredHandler(forceDeleteLock) m.Add("Delete", "/apps/{app}/lock", forceDeleteLockHandler) m.Add("Put", "/apps/{app}/units", authorizationRequiredHandler(addUnits)) m.Add("Delete", "/apps/{app}/units", authorizationRequiredHandler(removeUnits)) registerUnitHandler := authorizationRequiredHandler(registerUnit) m.Add("Post", "/apps/{app}/units/register", registerUnitHandler) setUnitStatusHandler := authorizationRequiredHandler(setUnitStatus) m.Add("Post", "/apps/{app}/units/{unit}", setUnitStatusHandler) m.Add("Put", "/apps/{app}/teams/{team}", authorizationRequiredHandler(grantAppAccess)) m.Add("Delete", "/apps/{app}/teams/{team}", authorizationRequiredHandler(revokeAppAccess)) m.Add("Get", "/apps/{app}/log", authorizationRequiredHandler(appLog)) logPostHandler := authorizationRequiredHandler(addLog) m.Add("Post", "/apps/{app}/log", logPostHandler) m.Add("Post", "/apps/{appname}/deploy/rollback", authorizationRequiredHandler(deployRollback)) m.Add("Post", "/apps/{app}/pool", authorizationRequiredHandler(appChangePool)) m.Add("Get", "/apps/{app}/metric/envs", authorizationRequiredHandler(appMetricEnvs)) m.Add("Post", "/apps/{app}/routes", AdminRequiredHandler(appRebuildRoutes)) m.Add("Post", "/units/status", authorizationRequiredHandler(setUnitsStatus)) m.Add("Get", "/deploys", authorizationRequiredHandler(deploysList)) m.Add("Get", "/deploys/{deploy}", authorizationRequiredHandler(deployInfo)) m.Add("Get", "/platforms", authorizationRequiredHandler(platformList)) m.Add("Post", "/platforms", AdminRequiredHandler(platformAdd)) m.Add("Put", "/platforms/{name}", AdminRequiredHandler(platformUpdate)) m.Add("Delete", "/platforms/{name}", AdminRequiredHandler(platformRemove)) // These handlers don't use {app} on purpose. Using :app means that only // the token generate for the given app is valid, but these handlers // use a token generated for Gandalf. m.Add("Get", "/apps/{appname}/available", authorizationRequiredHandler(appIsAvailable)) m.Add("Post", "/apps/{appname}/repository/clone", authorizationRequiredHandler(deploy)) m.Add("Post", "/apps/{appname}/deploy", authorizationRequiredHandler(deploy)) // Shell also doesn't use {app} on purpose. Middlewares don't play well // with websocket. m.Add("Get", "/apps/{appname}/shell", websocket.Handler(remoteShellHandler)) m.Add("Get", "/users", AdminRequiredHandler(listUsers)) m.Add("Post", "/users", Handler(createUser)) m.Add("Get", "/users/info", authorizationRequiredHandler(userInfo)) m.Add("Get", "/auth/scheme", Handler(authScheme)) m.Add("Post", "/auth/login", Handler(login)) m.Add("Post", "/users/{email}/password", Handler(resetPassword)) m.Add("Post", "/users/{email}/tokens", Handler(login)) m.Add("Get", "/users/{email}/quota", AdminRequiredHandler(getUserQuota)) m.Add("Post", "/users/{email}/quota", AdminRequiredHandler(changeUserQuota)) m.Add("Delete", "/users/tokens", authorizationRequiredHandler(logout)) m.Add("Put", "/users/password", authorizationRequiredHandler(changePassword)) m.Add("Delete", "/users", authorizationRequiredHandler(removeUser)) m.Add("Get", "/users/keys", authorizationRequiredHandler(listKeys)) m.Add("Post", "/users/keys", authorizationRequiredHandler(addKeyToUser)) m.Add("Delete", "/users/keys", authorizationRequiredHandler(removeKeyFromUser)) m.Add("Get", "/users/api-key", authorizationRequiredHandler(showAPIToken)) m.Add("Post", "/users/api-key", authorizationRequiredHandler(regenerateAPIToken)) m.Add("Delete", "/logs", AdminRequiredHandler(logRemove)) m.Add("Get", "/logs", websocket.Handler(addLogs)) m.Add("Get", "/teams", authorizationRequiredHandler(teamList)) m.Add("Post", "/teams", authorizationRequiredHandler(createTeam)) m.Add("Get", "/teams/{name}", authorizationRequiredHandler(getTeam)) m.Add("Delete", "/teams/{name}", authorizationRequiredHandler(removeTeam)) m.Add("Put", "/teams/{team}/{user}", authorizationRequiredHandler(addUserToTeam)) m.Add("Delete", "/teams/{team}/{user}", authorizationRequiredHandler(removeUserFromTeam)) m.Add("Put", "/swap", authorizationRequiredHandler(swap)) m.Add("Get", "/healthcheck/", http.HandlerFunc(healthcheck)) m.Add("Get", "/iaas/machines", AdminRequiredHandler(machinesList)) m.Add("Delete", "/iaas/machines/{machine_id}", AdminRequiredHandler(machineDestroy)) m.Add("Get", "/iaas/templates", AdminRequiredHandler(templatesList)) m.Add("Post", "/iaas/templates", AdminRequiredHandler(templateCreate)) m.Add("Put", "/iaas/templates/{template_name}", AdminRequiredHandler(templateUpdate)) m.Add("Delete", "/iaas/templates/{template_name}", AdminRequiredHandler(templateDestroy)) m.Add("Get", "/plans", authorizationRequiredHandler(listPlans)) m.Add("Post", "/plans", AdminRequiredHandler(addPlan)) m.Add("Delete", "/plans/{planname}", AdminRequiredHandler(removePlan)) m.Add("Get", "/plans/routers", AdminRequiredHandler(listRouters)) m.Add("Get", "/debug/goroutines", AdminRequiredHandler(dumpGoroutines)) m.Add("Get", "/pools", authorizationRequiredHandler(listPoolsToUser)) m.Add("Get", "/pool", AdminRequiredHandler(listPoolHandler)) m.Add("Post", "/pool", AdminRequiredHandler(addPoolHandler)) m.Add("Delete", "/pool", AdminRequiredHandler(removePoolHandler)) m.Add("Post", "/pool/{name}", AdminRequiredHandler(poolUpdateHandler)) m.Add("Post", "/pool/{name}/team", AdminRequiredHandler(addTeamToPoolHandler)) m.Add("Delete", "/pool/{name}/team", AdminRequiredHandler(removeTeamToPoolHandler)) m.Add("Get", "/debug/pprof/", AdminRequiredHandler(indexHandler)) m.Add("Get", "/debug/pprof/cmdline", AdminRequiredHandler(cmdlineHandler)) m.Add("Get", "/debug/pprof/profile", AdminRequiredHandler(profileHandler)) m.Add("Get", "/debug/pprof/symbol", AdminRequiredHandler(symbolHandler)) m.Add("Get", "/debug/pprof/heap", AdminRequiredHandler(indexHandler)) m.Add("Get", "/debug/pprof/goroutine", AdminRequiredHandler(indexHandler)) m.Add("Get", "/debug/pprof/threadcreate", AdminRequiredHandler(indexHandler)) m.Add("Get", "/debug/pprof/block", AdminRequiredHandler(indexHandler)) n := negroni.New() n.Use(negroni.NewRecovery()) n.Use(newLoggerMiddleware()) n.UseHandler(m) n.Use(negroni.HandlerFunc(contextClearerMiddleware)) n.Use(negroni.HandlerFunc(flushingWriterMiddleware)) n.Use(negroni.HandlerFunc(errorHandlingMiddleware)) n.Use(negroni.HandlerFunc(setVersionHeadersMiddleware)) n.Use(negroni.HandlerFunc(authTokenMiddleware)) n.Use(&appLockMiddleware{excludedHandlers: []http.Handler{ logPostHandler, runHandler, forceDeleteLockHandler, registerUnitHandler, setUnitStatusHandler, }}) n.UseHandler(http.HandlerFunc(runDelayedHandler)) if !dry { var startupMessage string routers, err := router.List() if err != nil { fatal(err) } for _, routerDesc := range routers { var r router.Router r, err = router.Get(routerDesc.Name) if err != nil { fatal(err) } fmt.Printf("Registered router %q", routerDesc.Name) if messageRouter, ok := r.(router.MessageRouter); ok { startupMessage, err = messageRouter.StartupMessage() if err == nil && startupMessage != "" { fmt.Printf(": %s", startupMessage) } } fmt.Println() } defaultRouter, _ := config.GetString("docker:router") fmt.Printf("Default router is %q.\n", defaultRouter) repoManager, err := config.GetString("repo-manager") if err != nil { repoManager = "gandalf" fmt.Println("Warning: configuration didn't declare a repository manager, using default manager.") } fmt.Printf("Using %q repository manager.\n", repoManager) provisioner, err := getProvisioner() if err != nil { fmt.Println("Warning: configuration didn't declare a provisioner, using default provisioner.") } app.Provisioner, err = provision.Get(provisioner) if err != nil { fatal(err) } fmt.Printf("Using %q provisioner.\n", provisioner) if initializableProvisioner, ok := app.Provisioner.(provision.InitializableProvisioner); ok { err = initializableProvisioner.Initialize() if err != nil { fatal(err) } } if messageProvisioner, ok := app.Provisioner.(provision.MessageProvisioner); ok { startupMessage, err = messageProvisioner.StartupMessage() if err == nil && startupMessage != "" { fmt.Print(startupMessage) } } scheme, err := getAuthScheme() if err != nil { fmt.Printf("Warning: configuration didn't declare auth:scheme, using default scheme.\n") } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { fatal(err) } fmt.Printf("Using %q auth scheme.\n", scheme) fmt.Println("Checking components status:") results := hc.Check() for _, result := range results { if result.Status != hc.HealthCheckOK { fmt.Printf(" WARNING: %q is not working: %s\n", result.Name, result.Status) } } fmt.Println(" Components checked.") listen, err := config.GetString("listen") if err != nil { fatal(err) } shutdownChan := make(chan bool) shutdownTimeout, _ := config.GetInt("shutdown-timeout") if shutdownTimeout == 0 { shutdownTimeout = 10 * 60 } idleTracker := newIdleTracker() shutdown.Register(idleTracker) shutdown.Register(&logTracker) readTimeout, _ := config.GetInt("server:read-timeout") writeTimeout, _ := config.GetInt("server:write-timeout") srv := &graceful.Server{ Timeout: time.Duration(shutdownTimeout) * time.Second, Server: &http.Server{ ReadTimeout: time.Duration(readTimeout) * time.Second, WriteTimeout: time.Duration(writeTimeout) * time.Second, Addr: listen, Handler: n, }, ConnState: func(conn net.Conn, state http.ConnState) { idleTracker.trackConn(conn, state) }, ShutdownInitiated: func() { fmt.Println("tsuru is shutting down, waiting for pending connections to finish.") handlers := shutdown.All() wg := sync.WaitGroup{} for _, h := range handlers { wg.Add(1) go func(h shutdown.Shutdownable) { defer wg.Done() fmt.Printf("running shutdown handler for %v...\n", h) h.Shutdown() fmt.Printf("running shutdown handler for %v. DONE.\n", h) }(h) } wg.Wait() close(shutdownChan) }, } tls, _ := config.GetBool("use-tls") if tls { var ( certFile string keyFile string ) certFile, err = config.GetString("tls:cert-file") if err != nil { fatal(err) } keyFile, err = config.GetString("tls:key-file") if err != nil { fatal(err) } fmt.Printf("tsuru HTTP/TLS server listening at %s...\n", listen) err = srv.ListenAndServeTLS(certFile, keyFile) } else { fmt.Printf("tsuru HTTP server listening at %s...\n", listen) err = srv.ListenAndServe() } if err != nil { fmt.Printf("Listening stopped: %s\n", err) } <-shutdownChan } return n }
func migrateBSEnvs() error { scheme, err := config.GetString("auth:scheme") if err != nil { scheme = nativeSchemeName } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { return err } _, err = nodecontainer.InitializeBS() if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() var entry map[string]interface{} err = conn.Collection("bsconfig").FindId("bs").One(&entry) if err != nil { if err == mgo.ErrNotFound { return nil } return err } image, _ := entry["image"].(string) envs, _ := entry["envs"].([]interface{}) var baseEnvs []string for _, envEntry := range envs { mapEntry, _ := envEntry.(map[string]interface{}) if mapEntry == nil { continue } name, _ := mapEntry["name"].(string) value, _ := mapEntry["value"].(string) baseEnvs = append(baseEnvs, fmt.Sprintf("%s=%s", name, value)) } bsNodeContainer, err := nodecontainer.LoadNodeContainer("", nodecontainer.BsDefaultName) if err != nil { return err } if len(baseEnvs) > 0 { bsNodeContainer.Config.Env = append(bsNodeContainer.Config.Env, baseEnvs...) } bsNodeContainer.PinnedImage = image err = nodecontainer.AddNewContainer("", bsNodeContainer) if err != nil { return err } pools, _ := entry["pools"].([]interface{}) for _, poolData := range pools { poolMap, _ := poolData.(map[string]interface{}) if poolMap == nil { continue } poolName, _ := poolMap["name"].(string) if poolName == "" { continue } envs, _ := poolMap["envs"].([]interface{}) var toAdd []string for _, envEntry := range envs { mapEntry, _ := envEntry.(map[string]interface{}) if mapEntry == nil { continue } name, _ := mapEntry["name"].(string) value, _ := mapEntry["value"].(string) toAdd = append(toAdd, fmt.Sprintf("%s=%s", name, value)) } if len(toAdd) > 0 { bsCont := nodecontainer.NodeContainerConfig{Name: nodecontainer.BsDefaultName} bsCont.Config.Env = append(bsCont.Config.Env, toAdd...) err = nodecontainer.AddNewContainer(poolName, &bsCont) if err != nil { return err } } } return nil }
// RunServer starts tsuru API server. The dry parameter indicates whether the // server should run in dry mode, not starting the HTTP listener (for testing // purposes). func RunServer(dry bool) http.Handler { log.Init() connString, err := config.GetString("database:url") if err != nil { connString = db.DefaultDatabaseURL } dbName, err := config.GetString("database:name") if err != nil { dbName = db.DefaultDatabaseName } fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString) m := &delayedRouter{} for _, handler := range tsuruHandlerList { m.Add(handler.method, handler.path, handler.h) } m.Add("Get", "/schema/app", authorizationRequiredHandler(appSchema)) m.Add("Get", "/schema/service", authorizationRequiredHandler(serviceSchema)) m.Add("Get", "/schema/services", authorizationRequiredHandler(servicesSchema)) m.Add("Get", "/services/instances", authorizationRequiredHandler(serviceInstances)) m.Add("Get", "/services/instances/{name}", authorizationRequiredHandler(serviceInstance)) m.Add("Delete", "/services/instances/{name}", authorizationRequiredHandler(removeServiceInstance)) m.Add("Post", "/services/instances", authorizationRequiredHandler(createServiceInstance)) m.Add("Put", "/services/instances/{instance}/{app}", authorizationRequiredHandler(bindServiceInstance)) m.Add("Delete", "/services/instances/{instance}/{app}", authorizationRequiredHandler(unbindServiceInstance)) m.Add("Get", "/services/instances/{instance}/status", authorizationRequiredHandler(serviceInstanceStatus)) m.AddAll("/services/proxy/{instance}", authorizationRequiredHandler(serviceProxy)) m.Add("Get", "/services", authorizationRequiredHandler(serviceList)) m.Add("Post", "/services", authorizationRequiredHandler(serviceCreate)) m.Add("Put", "/services", authorizationRequiredHandler(serviceUpdate)) m.Add("Delete", "/services/{name}", authorizationRequiredHandler(serviceDelete)) m.Add("Get", "/services/{name}", authorizationRequiredHandler(serviceInfo)) m.Add("Get", "/services/{name}/plans", authorizationRequiredHandler(servicePlans)) m.Add("Get", "/services/{name}/doc", authorizationRequiredHandler(serviceDoc)) m.Add("Put", "/services/{name}/doc", authorizationRequiredHandler(serviceAddDoc)) m.Add("Put", "/services/{service}/{team}", authorizationRequiredHandler(grantServiceAccess)) m.Add("Delete", "/services/{service}/{team}", authorizationRequiredHandler(revokeServiceAccess)) m.Add("Delete", "/apps/{app}", authorizationRequiredHandler(appDelete)) m.Add("Get", "/apps/{app}", authorizationRequiredHandler(appInfo)) m.Add("Post", "/apps/{app}/cname", authorizationRequiredHandler(setCName)) m.Add("Delete", "/apps/{app}/cname", authorizationRequiredHandler(unsetCName)) runHandler := authorizationRequiredHandler(runCommand) m.Add("Post", "/apps/{app}/run", runHandler) m.Add("Post", "/apps/{app}/restart", authorizationRequiredHandler(restart)) m.Add("Post", "/apps/{app}/start", authorizationRequiredHandler(start)) m.Add("Post", "/apps/{app}/stop", authorizationRequiredHandler(stop)) m.Add("Get", "/apps/{app}/env", authorizationRequiredHandler(getEnv)) m.Add("Post", "/apps/{app}/env", authorizationRequiredHandler(setEnv)) m.Add("Delete", "/apps/{app}/env", authorizationRequiredHandler(unsetEnv)) m.Add("Get", "/apps", authorizationRequiredHandler(appList)) m.Add("Post", "/apps", authorizationRequiredHandler(createApp)) m.Add("Put", "/apps/{app}/units", authorizationRequiredHandler(addUnits)) m.Add("Delete", "/apps/{app}/units", authorizationRequiredHandler(removeUnits)) m.Add("Post", "/apps/{app}/units/{unit}", authorizationRequiredHandler(setUnitStatus)) m.Add("Put", "/apps/{app}/{team}", authorizationRequiredHandler(grantAppAccess)) m.Add("Delete", "/apps/{app}/{team}", authorizationRequiredHandler(revokeAppAccess)) m.Add("Get", "/apps/{app}/log", authorizationRequiredHandler(appLog)) logPostHandler := authorizationRequiredHandler(addLog) m.Add("Post", "/apps/{app}/log", logPostHandler) m.Add("Get", "/deploys", AdminRequiredHandler(deploysList)) m.Add("Get", "/deploys/{deploy}", AdminRequiredHandler(deployInfo)) m.Add("Get", "/platforms", authorizationRequiredHandler(platformList)) m.Add("Post", "/platforms", AdminRequiredHandler(platformAdd)) m.Add("Put", "/platforms/{name}", AdminRequiredHandler(platformUpdate)) // These handlers don't use :app on purpose. Using :app means that only // the token generate for the given app is valid, but these handlers // use a token generated for Gandalf. m.Add("Get", "/apps/{appname}/available", authorizationRequiredHandler(appIsAvailable)) m.Add("Post", "/apps/{appname}/repository/clone", authorizationRequiredHandler(deploy)) m.Add("Post", "/apps/{appname}/deploy", authorizationRequiredHandler(deploy)) m.Add("Post", "/users", Handler(createUser)) m.Add("Get", "/auth/scheme", Handler(authScheme)) m.Add("Post", "/auth/login", Handler(login)) m.Add("Post", "/users/{email}/password", Handler(resetPassword)) m.Add("Post", "/users/{email}/tokens", Handler(login)) m.Add("Delete", "/users/tokens", authorizationRequiredHandler(logout)) m.Add("Put", "/users/password", authorizationRequiredHandler(changePassword)) m.Add("Delete", "/users", authorizationRequiredHandler(removeUser)) m.Add("Get", "/users/{email}/keys", authorizationRequiredHandler(listKeys)) m.Add("Post", "/users/keys", authorizationRequiredHandler(addKeyToUser)) m.Add("Delete", "/users/keys", authorizationRequiredHandler(removeKeyFromUser)) m.Add("Post", "/tokens", AdminRequiredHandler(generateAppToken)) m.Add("Delete", "/logs", AdminRequiredHandler(logRemove)) m.Add("Get", "/teams", authorizationRequiredHandler(teamList)) m.Add("Post", "/teams", authorizationRequiredHandler(createTeam)) m.Add("Get", "/teams/{name}", authorizationRequiredHandler(getTeam)) m.Add("Delete", "/teams/{name}", authorizationRequiredHandler(removeTeam)) m.Add("Put", "/teams/{team}/{user}", authorizationRequiredHandler(addUserToTeam)) m.Add("Delete", "/teams/{team}/{user}", authorizationRequiredHandler(removeUserFromTeam)) m.Add("Get", "/healers", authorizationRequiredHandler(healers)) m.Add("Get", "/healers/{healer}", authorizationRequiredHandler(healer)) m.Add("Put", "/swap", authorizationRequiredHandler(swap)) m.Add("Get", "/healthcheck/", http.HandlerFunc(healthcheck)) m.Add("Get", "/iaas/machines", AdminRequiredHandler(machinesList)) m.Add("Delete", "/iaas/machines/{machine_id}", AdminRequiredHandler(machineDestroy)) n := negroni.New() n.Use(negroni.NewRecovery()) n.Use(negroni.NewLogger()) n.UseHandler(m) n.Use(negroni.HandlerFunc(contextClearerMiddleware)) n.Use(negroni.HandlerFunc(flushingWriterMiddleware)) n.Use(negroni.HandlerFunc(errorHandlingMiddleware)) n.Use(negroni.HandlerFunc(setVersionHeadersMiddleware)) n.Use(negroni.HandlerFunc(authTokenMiddleware)) n.Use(&appLockMiddleware{excludedHandlers: []http.Handler{ logPostHandler, runHandler, }}) n.UseHandler(http.HandlerFunc(runDelayedHandler)) if !dry { provisioner, err := getProvisioner() if err != nil { fmt.Printf("Warning: configuration didn't declare a provisioner, using default provisioner.\n") } app.Provisioner, err = provision.Get(provisioner) if err != nil { fatal(err) } fmt.Printf("Using %q provisioner.\n\n", provisioner) scheme, err := getAuthScheme() if err != nil { fmt.Printf("Warning: configuration didn't declare a auth:scheme, using default scheme.\n") } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { fatal(err) } fmt.Printf("Using %q auth scheme.\n\n", scheme) listen, err := config.GetString("listen") if err != nil { fatal(err) } tls, _ := config.GetBool("use-tls") if tls { certFile, err := config.GetString("tls:cert-file") if err != nil { fatal(err) } keyFile, err := config.GetString("tls:key-file") if err != nil { fatal(err) } fmt.Printf("tsuru HTTP/TLS server listening at %s...\n", listen) fatal(http.ListenAndServeTLS(listen, certFile, keyFile, n)) } else { listener, err := net.Listen("tcp", listen) if err != nil { fatal(err) } fmt.Printf("tsuru HTTP server listening at %s...\n", listen) http.Handle("/", n) fatal(http.Serve(listener, nil)) } } return n }
// RunServer starts tsuru API server. The dry parameter indicates whether the // server should run in dry mode, not starting the HTTP listener (for testing // purposes). func RunServer(dry bool) { log.Init() connString, err := config.GetString("database:url") if err != nil { connString = db.DefaultDatabaseURL } dbName, err := config.GetString("database:name") if err != nil { dbName = db.DefaultDatabaseName } fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString) m := pat.New() for _, handler := range tsuruHandlerList { m.Add(handler.method, handler.path, handler.h) } m.Get("/schema/app", authorizationRequiredHandler(appSchema)) m.Get("/schema/service", authorizationRequiredHandler(serviceSchema)) m.Get("/schema/services", authorizationRequiredHandler(servicesSchema)) m.Get("/services/instances", authorizationRequiredHandler(serviceInstances)) m.Get("/services/instances/:name", authorizationRequiredHandler(serviceInstance)) m.Del("/services/instances/:name", authorizationRequiredHandler(removeServiceInstance)) m.Post("/services/instances", authorizationRequiredHandler(createServiceInstance)) m.Put("/services/instances/:instance/:app", authorizationRequiredHandler(bindServiceInstance)) m.Del("/services/instances/:instance/:app", authorizationRequiredHandler(unbindServiceInstance)) m.Get("/services/instances/:instance/status", authorizationRequiredHandler(serviceInstanceStatus)) m.Get("/services", authorizationRequiredHandler(serviceList)) m.Post("/services", authorizationRequiredHandler(serviceCreate)) m.Put("/services", authorizationRequiredHandler(serviceUpdate)) m.Del("/services/:name", authorizationRequiredHandler(serviceDelete)) m.Get("/services/:name", authorizationRequiredHandler(serviceInfo)) m.Get("/services/:name/plans", authorizationRequiredHandler(servicePlans)) m.Get("/services/:name/doc", authorizationRequiredHandler(serviceDoc)) m.Put("/services/:name/doc", authorizationRequiredHandler(serviceAddDoc)) m.Put("/services/:service/:team", authorizationRequiredHandler(grantServiceAccess)) m.Del("/services/:service/:team", authorizationRequiredHandler(revokeServiceAccess)) m.Del("/apps/:app", authorizationRequiredHandler(appDelete)) m.Get("/apps/:app", authorizationRequiredHandler(appInfo)) m.Post("/apps/:app/cname", authorizationRequiredHandler(setCName)) m.Del("/apps/:app/cname", authorizationRequiredHandler(unsetCName)) m.Post("/apps/:app/run", authorizationRequiredHandler(runCommand)) m.Get("/apps/:app/restart", authorizationRequiredHandler(restart)) m.Get("/apps/:app/start", authorizationRequiredHandler(start)) m.Get("/apps/:app/env", authorizationRequiredHandler(getEnv)) m.Post("/apps/:app/env", authorizationRequiredHandler(setEnv)) m.Del("/apps/:app/env", authorizationRequiredHandler(unsetEnv)) m.Get("/apps", authorizationRequiredHandler(appList)) m.Post("/apps", authorizationRequiredHandler(createApp)) m.Put("/apps/:app/units", authorizationRequiredHandler(addUnits)) m.Del("/apps/:app/units", authorizationRequiredHandler(removeUnits)) m.Put("/apps/:app/:team", authorizationRequiredHandler(grantAppAccess)) m.Del("/apps/:app/:team", authorizationRequiredHandler(revokeAppAccess)) m.Get("/apps/:app/log", authorizationRequiredHandler(appLog)) m.Post("/apps/:app/log", authorizationRequiredHandler(addLog)) m.Get("/deploys", AdminRequiredHandler(deploysList)) m.Get("/platforms", authorizationRequiredHandler(platformList)) m.Post("/platforms", AdminRequiredHandler(platformAdd)) m.Put("/platforms/:name", AdminRequiredHandler(platformUpdate)) // These handlers don't use :app on purpose. Using :app means that only // the token generate for the given app is valid, but these handlers // use a token generated for Gandalf. m.Get("/apps/:appname/available", authorizationRequiredHandler(appIsAvailable)) m.Post("/apps/:appname/repository/clone", authorizationRequiredHandler(deploy)) m.Post("/apps/:appname/deploy", authorizationRequiredHandler(deploy)) if registrationEnabled, _ := config.GetBool("auth:user-registration"); registrationEnabled { m.Post("/users", Handler(createUser)) } m.Get("/auth/scheme", Handler(authScheme)) m.Post("/auth/login", Handler(login)) m.Post("/users/:email/password", Handler(resetPassword)) m.Post("/users/:email/tokens", Handler(login)) m.Del("/users/tokens", authorizationRequiredHandler(logout)) m.Put("/users/password", authorizationRequiredHandler(changePassword)) m.Del("/users", authorizationRequiredHandler(removeUser)) m.Get("/users/:email/keys", authorizationRequiredHandler(listKeys)) m.Post("/users/keys", authorizationRequiredHandler(addKeyToUser)) m.Del("/users/keys", authorizationRequiredHandler(removeKeyFromUser)) m.Post("/tokens", AdminRequiredHandler(generateAppToken)) m.Del("/logs", AdminRequiredHandler(logRemove)) m.Get("/teams", authorizationRequiredHandler(teamList)) m.Post("/teams", authorizationRequiredHandler(createTeam)) m.Get("/teams/:name", authorizationRequiredHandler(getTeam)) m.Del("/teams/:name", authorizationRequiredHandler(removeTeam)) m.Put("/teams/:team/:user", authorizationRequiredHandler(addUserToTeam)) m.Del("/teams/:team/:user", authorizationRequiredHandler(removeUserFromTeam)) m.Get("/healers", authorizationRequiredHandler(healers)) m.Get("/healers/:healer", authorizationRequiredHandler(healer)) m.Put("/swap", authorizationRequiredHandler(swap)) m.Get("/healthcheck/", http.HandlerFunc(healthcheck)) if !dry { provisioner, err := getProvisioner() if err != nil { fmt.Printf("Warning: configuration didn't declare a provisioner, using default provisioner.\n") } app.Provisioner, err = provision.Get(provisioner) if err != nil { fatal(err) } fmt.Printf("Using %q provisioner.\n\n", provisioner) scheme, err := getAuthScheme() if err != nil { fmt.Printf("Warning: configuration didn't declare a auth:scheme, using default scheme.\n") } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { fatal(err) } fmt.Printf("Using %q auth scheme.\n\n", scheme) listen, err := config.GetString("listen") if err != nil { fatal(err) } tls, _ := config.GetBool("use-tls") if tls { certFile, err := config.GetString("tls:cert-file") if err != nil { fatal(err) } keyFile, err := config.GetString("tls:key-file") if err != nil { fatal(err) } fmt.Printf("tsuru HTTP/TLS server listening at %s...\n", listen) fatal(http.ListenAndServeTLS(listen, certFile, keyFile, m)) } else { listener, err := net.Listen("tcp", listen) if err != nil { fatal(err) } fmt.Printf("tsuru HTTP server listening at %s...\n", listen) http.Handle("/", m) fatal(http.Serve(listener, nil)) } } }
func startServer(handler http.Handler) { shutdownChan := make(chan bool) shutdownTimeout, _ := config.GetInt("shutdown-timeout") if shutdownTimeout == 0 { shutdownTimeout = 10 * 60 } idleTracker := newIdleTracker() shutdown.Register(idleTracker) shutdown.Register(&logTracker) readTimeout, _ := config.GetInt("server:read-timeout") writeTimeout, _ := config.GetInt("server:write-timeout") listen, err := config.GetString("listen") if err != nil { fatal(err) } srv := &graceful.Server{ Timeout: time.Duration(shutdownTimeout) * time.Second, Server: &http.Server{ ReadTimeout: time.Duration(readTimeout) * time.Second, WriteTimeout: time.Duration(writeTimeout) * time.Second, Addr: listen, Handler: handler, }, ConnState: func(conn net.Conn, state http.ConnState) { idleTracker.trackConn(conn, state) }, NoSignalHandling: true, ShutdownInitiated: func() { fmt.Println("tsuru is shutting down, waiting for pending connections to finish.") handlers := shutdown.All() wg := sync.WaitGroup{} for _, h := range handlers { wg.Add(1) go func(h shutdown.Shutdownable) { defer wg.Done() fmt.Printf("running shutdown handler for %v...\n", h) h.Shutdown() fmt.Printf("running shutdown handler for %v. DONE.\n", h) }(h) } wg.Wait() close(shutdownChan) }, } sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigChan srv.Stop(srv.Timeout) }() var startupMessage string routers, err := router.List() if err != nil { fatal(err) } for _, routerDesc := range routers { var r router.Router r, err = router.Get(routerDesc.Name) if err != nil { fatal(err) } fmt.Printf("Registered router %q", routerDesc.Name) if messageRouter, ok := r.(router.MessageRouter); ok { startupMessage, err = messageRouter.StartupMessage() if err == nil && startupMessage != "" { fmt.Printf(": %s", startupMessage) } } fmt.Println() } defaultRouter, _ := config.GetString("docker:router") fmt.Printf("Default router is %q.\n", defaultRouter) repoManager, err := config.GetString("repo-manager") if err != nil { repoManager = "gandalf" fmt.Println("Warning: configuration didn't declare a repository manager, using default manager.") } fmt.Printf("Using %q repository manager.\n", repoManager) err = rebuild.RegisterTask(appFinder) if err != nil { fatal(err) } scheme, err := getAuthScheme() if err != nil { fmt.Printf("Warning: configuration didn't declare auth:scheme, using default scheme.\n") } app.AuthScheme, err = auth.GetScheme(scheme) if err != nil { fatal(err) } fmt.Printf("Using %q auth scheme.\n", scheme) err = provision.InitializeAll() if err != nil { fatal(err) } _, err = healer.Initialize() if err != nil { fatal(err) } fmt.Println("Checking components status:") results := hc.Check() for _, result := range results { if result.Status != hc.HealthCheckOK { fmt.Printf(" WARNING: %q is not working: %s\n", result.Name, result.Status) } } fmt.Println(" Components checked.") tls, _ := config.GetBool("use-tls") if tls { var ( certFile string keyFile string ) certFile, err = config.GetString("tls:cert-file") if err != nil { fatal(err) } keyFile, err = config.GetString("tls:key-file") if err != nil { fatal(err) } fmt.Printf("tsuru HTTP/TLS server listening at %s...\n", listen) err = srv.ListenAndServeTLS(certFile, keyFile) } else { fmt.Printf("tsuru HTTP server listening at %s...\n", listen) err = srv.ListenAndServe() } if err != nil { fmt.Printf("Listening stopped: %s\n", err) if errOp, ok := err.(*net.OpError); ok { if errOp.Op == "listen" { os.Exit(1) } } } <-shutdownChan }