func (s *S) TestGetS3Endpoint(c *gocheck.C) { oldRegion, _ := config.Get("aws:s3:region-name") defer config.Set("aws:s3:region-name", oldRegion) config.Set("aws:s3:region-name", "myregion") edp, err := config.GetString("aws:s3:endpoint") c.Assert(err, gocheck.IsNil) locConst, err := config.GetBool("aws:s3:location-constraint") c.Assert(err, gocheck.IsNil) lwrCaseBucket, err := config.GetBool("aws:s3:lowercase-bucket") c.Assert(err, gocheck.IsNil) s3 := getS3Endpoint() c.Assert(s3.S3Endpoint, gocheck.Equals, edp) c.Assert(s3.S3LocationConstraint, gocheck.Equals, locConst) c.Assert(s3.S3LowercaseBucket, gocheck.Equals, lwrCaseBucket) c.Assert(s3.Region.Name, gocheck.Equals, "myregion") }
func (p *JujuProvisioner) elbSupport() bool { if p.elb == nil { elb, _ := config.GetBool("juju:use-elb") p.elb = &elb } return *p.elb }
// CreateApp creates a new app. // // Creating a new app is a process composed of four steps: // // 1. Save the app in the database // 2. Create IAM credentials for the app // 3. Create S3 bucket for the app (if the bucket support is enabled) // 4. Create the git repository using gandalf // 5. Provision units within the provisioner func CreateApp(app *App, units uint, teams []auth.Team) error { if units == 0 { return &errors.ValidationError{Message: "Cannot create app with 0 units."} } if len(teams) == 0 { return NoTeamsError{} } app.SetTeams(teams) if !app.isValid() { msg := "Invalid app name, your app should have at most 63 " + "characters, containing only lower case letters or numbers, " + "starting with a letter." return &errors.ValidationError{Message: msg} } actions := []*action.Action{&insertApp} useS3, _ := config.GetBool("bucket-support") if useS3 { actions = append(actions, &createIAMUserAction, &createIAMAccessKeyAction, &createBucketAction, &createUserPolicyAction) } actions = append(actions, &exportEnvironmentsAction, &createRepository, &provisionApp, &provisionAddUnits) pipeline := action.NewPipeline(actions...) err := pipeline.Execute(app, units) if err != nil { return &appCreationError{app: app.Name, err: err} } return nil }
func dockerCluster() *cluster.Cluster { cmutex.Lock() defer cmutex.Unlock() if dCluster == nil { if segregate, _ := config.GetBool("docker:segregate"); segregate { dCluster, _ = cluster.New(segScheduler) } else { clusterNodes = make(map[string]string) servers, _ := config.GetList("docker:servers") if len(servers) < 1 { log.Fatal(`Tsuru is misconfigured. Setting "docker:servers" is mandatory`) } nodes := make([]cluster.Node, len(servers)) for index, server := range servers { id := fmt.Sprintf("server%d", index) node := cluster.Node{ ID: id, Address: server, } nodes[index] = node clusterNodes[id] = server } dCluster, _ = cluster.New(nil, nodes...) } if redisServer, err := config.GetString("docker:scheduler:redis-server"); err == nil { prefix, _ := config.GetString("docker:scheduler:redis-prefix") if password, err := config.GetString("docker:scheduler:redis-password"); err == nil { dCluster.SetStorage(storage.AuthenticatedRedis(redisServer, password, prefix)) } else { dCluster.SetStorage(storage.Redis(redisServer, prefix)) } } } return dCluster }
// CreateApp creates a new app. // // Creating a new app is a process composed of four steps: // // 1. Save the app in the database // 2. Create IAM credentials for the app // 3. Create S3 bucket for the app (if the bucket support is enabled) // 4. Create the git repository using gandalf // 5. Provision units within the provisioner func CreateApp(app *App, user *auth.User) error { teams, err := user.Teams() if err != nil { return err } if len(teams) == 0 { return NoTeamsError{} } if _, err := getPlatform(app.Platform); err != nil { return err } app.SetTeams(teams) app.Owner = user.Email if !app.isValid() { msg := "Invalid app name, your app should have at most 63 " + "characters, containing only lower case letters, numbers or dashes, " + "starting with a letter." return &errors.ValidationError{Message: msg} } actions := []*action.Action{&reserveUserApp, &createAppQuota, &insertApp} useS3, _ := config.GetBool("bucket-support") if useS3 { actions = append(actions, &createIAMUserAction, &createIAMAccessKeyAction, &createBucketAction, &createUserPolicyAction) } actions = append(actions, &exportEnvironmentsAction, &createRepository, &provisionApp) pipeline := action.NewPipeline(actions...) err = pipeline.Execute(app, user) if err != nil { return &AppCreationError{app: app.Name, Err: err} } return nil }
func (r elbRouter) AddBackend(name string) error { var err error options := elb.CreateLoadBalancer{ Name: name, Listeners: []elb.Listener{ { InstancePort: 80, InstanceProtocol: "HTTP", LoadBalancerPort: 80, Protocol: "HTTP", }, }, } vpc, _ := config.GetBool("juju:elb-use-vpc") if vpc { options.Subnets, err = config.GetList("juju:elb-vpc-subnets") if err != nil { return err } options.SecurityGroups, err = config.GetList("juju:elb-vpc-secgroups") if err != nil { return err } options.Scheme = "internal" } else { options.AvailZones, err = config.GetList("juju:elb-avail-zones") if err != nil { return err } } _, err = r.elb().CreateLoadBalancer(&options) return router.Store(name, name) }
func (h elbInstanceHealer) checkInstances(names []string) ([]elbInstance, error) { if elbSupport, _ := config.GetBool("juju:use-elb"); !elbSupport { return nil, nil } lbs, err := h.describeLoadBalancers(names) if err != nil { return nil, err } var unhealthy []elbInstance description := "Instance has failed at least the UnhealthyThreshold number of health checks consecutively." state := "OutOfService" reasonCode := "Instance" for _, lb := range lbs { instances, err := h.describeInstancesHealth(lb) if err != nil { return nil, err } for _, instance := range instances { if instance.description == description && instance.state == state && instance.reasonCode == reasonCode { unhealthy = append(unhealthy, instance) } } } log.Printf("Found %d unhealthy instances.", len(unhealthy)) return unhealthy, nil }
func (p *JujuProvisioner) elbSupport() bool { if p.elb == nil { p.elb = new(bool) if elb, err := config.GetBool("juju:use-elb"); err == nil { *p.elb = elb } } return *p.elb }
func getHostAddr(hostID string) string { var fullAddress string if seg, _ := config.GetBool("docker:segregate"); seg { node, _ := segScheduler.GetNode(hostID) fullAddress = node.Address } else { fullAddress = clusterNodes[hostID] } url, _ := url.Parse(fullAddress) host, _, _ := net.SplitHostPort(url.Host) return host }
func Init() { debug, err := config.GetBool("debug") if err != nil { debug = false } logFileName, err := config.GetString("log:file") var logger Logger if err != nil { logger = NewSyslogLogger("tsr", debug) } else { logger = NewFileLogger(logFileName, debug) } SetLogger(logger) }
func getS3Endpoint() *s3.S3 { regionName, _ := config.GetString("aws:s3:region-name") endpoint, err := config.GetString("aws:s3:endpoint") if err != nil { panic("FATAL: aws:s3:endpoint must be defined in configuration file.") } bucketEndpoint, _ := config.GetString("aws:s3:bucketEndpoint") locationConstraint, err := config.GetBool("aws:s3:location-constraint") if err != nil { panic("FATAL: aws:s3:location-constraint must be defined in configuration file.") } lowercaseBucket, err := config.GetBool("aws:s3:lowercase-bucket") if err != nil { panic("FATAL: aws:s3:lowercase-bucket must be defined in configuration file.") } region := aws.Region{ Name: regionName, S3Endpoint: endpoint, S3BucketEndpoint: bucketEndpoint, S3LocationConstraint: locationConstraint, S3LowercaseBucket: lowercaseBucket, } return s3.New(getAWSAuth(), region) }
// ForceDestroy destroys an app with force. // // Destroying an app is a process composed of four steps: // // 1. Destroy the bucket and S3 credentials (if bucket-support is // enabled). // 2. Destroy the app unit using juju // 3. Unbind all service instances from the app // 4. Remove the app from the database func ForceDestroy(app *App) error { gUrl := repository.GitServerUri() (&gandalf.Client{Endpoint: gUrl}).RemoveRepository(app.Name) useS3, _ := config.GetBool("bucket-support") if useS3 { destroyBucket(app) } if len(app.Units) > 0 { Provisioner.Destroy(app) app.unbind() } conn, err := db.Conn() if err != nil { return err } defer conn.Close() return conn.Apps().Remove(bson.M{"name": app.Name}) }
// ReadWriteURL formats the git ssh url and return it. If no remote is configured in // gandalf.conf, this method panics. func (r *Repository) ReadWriteURL() string { uid, err := config.GetString("uid") if err != nil { panic(err.Error()) } remote := uid + "@%s:%s.git" if useSSH, _ := config.GetBool("git:ssh:use"); useSSH { port, err := config.GetString("git:ssh:port") if err == nil { remote = "ssh://" + uid + "@%s:" + port + "/%s.git" } else { remote = "ssh://" + uid + "@%s/%s.git" } } host, err := config.GetString("host") if err != nil { panic(err.Error()) } return fmt.Sprintf(remote, host, r.Name) }
// Delete deletes an app. // // Delete an app is a process composed of four steps: // // 1. Destroy the bucket and S3 credentials (if bucket-support is // enabled). // 2. Destroy the app unit using juju // 3. Unbind all service instances from the app // 4. Remove the app from the database func Delete(app *App) error { gURL := repository.ServerURL() (&gandalf.Client{Endpoint: gURL}).RemoveRepository(app.Name) useS3, _ := config.GetBool("bucket-support") if useS3 { destroyBucket(app) } if len(app.Units) > 0 { Provisioner.Destroy(app) app.unbind() } token := app.Env["TSURU_APP_TOKEN"].Value auth.DeleteToken(token) quota.Release(app.Owner, app.Name) conn, err := db.Conn() if err != nil { return err } defer conn.Close() quota.Delete(app.Name) return conn.Apps().Remove(bson.M{"name": app.Name}) }
func dockerCluster() *cluster.Cluster { cmutex.Lock() defer cmutex.Unlock() var clusterStorage cluster.Storage if dCluster == nil { if redisServer, err := config.GetString("docker:scheduler:redis-server"); err == nil { prefix, _ := config.GetString("docker:scheduler:redis-prefix") if password, err := config.GetString("docker:scheduler:redis-password"); err == nil { clusterStorage = storage.AuthenticatedRedis(redisServer, password, prefix) } else { clusterStorage = storage.Redis(redisServer, prefix) } } var nodes []cluster.Node if segregate, _ := config.GetBool("docker:segregate"); segregate { dCluster, _ = cluster.New(segScheduler, clusterStorage) } else { nodes = getDockerServers() dCluster, _ = cluster.New(nil, clusterStorage, nodes...) } } return dCluster }
// 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 { fatal(err) } dbName, err := config.GetString("database:name") if err != nil { fatal(err) } fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString) m := pat.New() m.Get("/schema/app", authorizationRequiredHandler(appSchema)) m.Get("/schema/service", authorizationRequiredHandler(serviceSchema)) m.Get("/schema/services", authorizationRequiredHandler(servicesSchema)) m.Get("/quota/:owner", authorizationRequiredHandler(quotaByOwner)) 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/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/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("/platforms", authorizationRequiredHandler(platformList)) // 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(cloneRepository)) if registrationEnabled, _ := config.GetBool("auth:user-registration"); registrationEnabled { m.Post("/users", handler(createUser)) } 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)) 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) 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 main() { logger, err := syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags) if err != nil { stdlog.Fatal(err) } log.SetLogger(logger) configFile := flag.String("config", "/etc/tsuru/tsuru.conf", "tsuru config file") dry := flag.Bool("dry", false, "dry-run: does not start the server (for testing purpose)") flag.Parse() err = config.ReadAndWatchConfigFile(*configFile) if err != nil { fatal(err) } connString, err := config.GetString("database:url") if err != nil { fatal(err) } dbName, err := config.GetString("database:name") if err != nil { fatal(err) } fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString) m := pat.New() m.Get("/services/instances", AuthorizationRequiredHandler(ServicesInstancesHandler)) m.Post("/services/instances", AuthorizationRequiredHandler(CreateInstanceHandler)) m.Put("/services/instances/:instance/:app", AuthorizationRequiredHandler(BindHandler)) m.Del("/services/instances/:instance/:app", AuthorizationRequiredHandler(UnbindHandler)) m.Del("/services/c/instances/:name", AuthorizationRequiredHandler(RemoveServiceInstanceHandler)) m.Get("/services/instances/:instance/status", AuthorizationRequiredHandler(ServiceInstanceStatusHandler)) m.Get("/services", AuthorizationRequiredHandler(ServicesHandler)) m.Post("/services", AuthorizationRequiredHandler(CreateHandler)) m.Put("/services", AuthorizationRequiredHandler(UpdateHandler)) m.Del("/services/:name", AuthorizationRequiredHandler(DeleteHandler)) m.Get("/services/:name", AuthorizationRequiredHandler(ServiceInfoHandler)) m.Get("/services/c/:name/doc", AuthorizationRequiredHandler(Doc)) m.Get("/services/:name/doc", AuthorizationRequiredHandler(GetDocHandler)) m.Put("/services/:name/doc", AuthorizationRequiredHandler(AddDocHandler)) m.Put("/services/:service/:team", AuthorizationRequiredHandler(GrantServiceAccessToTeamHandler)) m.Del("/services/:service/:team", AuthorizationRequiredHandler(RevokeServiceAccessFromTeamHandler)) m.Del("/apps/:name", AuthorizationRequiredHandler(appDelete)) m.Get("/apps/:name/repository/clone", Handler(CloneRepositoryHandler)) m.Get("/apps/:name/avaliable", Handler(AppIsAvailableHandler)) m.Get("/apps/:name", AuthorizationRequiredHandler(AppInfo)) m.Post("/apps/:name", AuthorizationRequiredHandler(setCName)) m.Post("/apps/:name/run", AuthorizationRequiredHandler(RunCommand)) m.Get("/apps/:name/restart", AuthorizationRequiredHandler(RestartHandler)) m.Get("/apps/:name/env", AuthorizationRequiredHandler(GetEnv)) m.Post("/apps/:name/env", AuthorizationRequiredHandler(SetEnv)) m.Del("/apps/:name/env", AuthorizationRequiredHandler(UnsetEnv)) m.Get("/apps", AuthorizationRequiredHandler(AppList)) m.Post("/apps", AuthorizationRequiredHandler(CreateAppHandler)) m.Put("/apps/:name/units", AuthorizationRequiredHandler(AddUnitsHandler)) m.Del("/apps/:name/units", AuthorizationRequiredHandler(RemoveUnitsHandler)) m.Put("/apps/:app/:team", AuthorizationRequiredHandler(GrantAccessToTeamHandler)) m.Del("/apps/:app/:team", AuthorizationRequiredHandler(RevokeAccessFromTeamHandler)) m.Get("/apps/:name/log", AuthorizationRequiredHandler(appLog)) m.Post("/apps/:name/log", Handler(AddLogHandler)) m.Post("/users", Handler(CreateUser)) m.Post("/users/:email/tokens", Handler(Login)) m.Put("/users/password", AuthorizationRequiredHandler(ChangePassword)) m.Del("/users", AuthorizationRequiredHandler(RemoveUser)) m.Post("/users/keys", AuthorizationRequiredHandler(AddKeyToUser)) m.Del("/users/keys", AuthorizationRequiredHandler(RemoveKeyFromUser)) m.Get("/teams", AuthorizationRequiredHandler(ListTeams)) m.Post("/teams", AuthorizationRequiredHandler(CreateTeam)) m.Del("/teams/:name", AuthorizationRequiredHandler(RemoveTeam)) m.Put("/teams/:team/:user", AuthorizationRequiredHandler(AddUserToTeam)) m.Del("/teams/:team/:user", AuthorizationRequiredHandler(RemoveUserFromTeam)) m.Get("/healers", Handler(healers)) m.Get("/healers/:healer", Handler(healer)) if !*dry { provisioner, err := config.GetString("provisioner") if err != nil { fmt.Printf("Warning: %q didn't declare a provisioner, using default provisioner.\n", configFile) provisioner = "juju" } app.Provisioner, err = provision.Get(provisioner) if err != nil { fatal(err) } fmt.Printf("Using %q provisioner.\n\n", provisioner) 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 { fmt.Printf("tsuru HTTP server listening at %s...\n", listen) fatal(http.ListenAndServe(listen, m)) } } }
func (m *ELBManager) vpc() bool { vpc, _ := config.GetBool("juju:elb-use-vpc") return vpc }
func RunServer(flags map[string]interface{}) { logger, err := syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags) if err != nil { stdlog.Fatal(err) } log.SetLogger(logger) configFile, ok := flags["config"].(string) if !ok { configFile = "/etc/tsuru/tsuru.conf" } dry, ok := flags["dry"].(bool) if !ok { dry = false } err = config.ReadAndWatchConfigFile(configFile) if err != nil { fatal(err) } connString, err := config.GetString("database:url") if err != nil { fatal(err) } dbName, err := config.GetString("database:name") if err != nil { fatal(err) } fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString) m := pat.New() m.Get("/schema/app", authorizationRequiredHandler(appSchema)) m.Get("/services/instances", authorizationRequiredHandler(serviceInstances)) m.Post("/services/instances", authorizationRequiredHandler(createServiceInstance)) m.Put("/services/instances/:instance/:app", authorizationRequiredHandler(bindServiceInstance)) m.Del("/services/instances/:instance/:app", authorizationRequiredHandler(unbindServiceInstance)) m.Del("/services/c/instances/:name", authorizationRequiredHandler(removeServiceInstance)) 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/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", authorizationRequiredHandler(setCName)) m.Post("/apps/:app/run", authorizationRequiredHandler(runCommand)) m.Get("/apps/:app/restart", authorizationRequiredHandler(restart)) 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("/platforms", authorizationRequiredHandler(platformList)) // 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.Get("/apps/:appname/repository/clone", authorizationRequiredHandler(cloneRepository)) if registrationEnabled, _ := config.GetBool("auth:user-registration"); registrationEnabled { m.Post("/users", handler(createUser)) } 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.Post("/users/keys", authorizationRequiredHandler(addKeyToUser)) m.Del("/users/keys", authorizationRequiredHandler(removeKeyFromUser)) m.Post("/tokens", adminRequiredHandler(generateAppToken)) m.Get("/teams", authorizationRequiredHandler(teamList)) m.Post("/teams", authorizationRequiredHandler(createTeam)) 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)) if !dry { provisioner, err := config.GetString("provisioner") if err != nil { fmt.Printf("Warning: %q didn't declare a provisioner, using default provisioner.\n", configFile) provisioner = "juju" } app.Provisioner, err = provision.Get(provisioner) if err != nil { fatal(err) } fmt.Printf("Using %q provisioner.\n\n", provisioner) 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)) } } }