func (a *Api) Run() error { globalMux := http.NewServeMux() controllerManager := a.manager client := a.manager.DockerClient() // forwarder for swarm var err error a.fwd, err = forward.New() if err != nil { return err } u := client.URL // setup redirect target to swarm scheme := "http://" // check if TLS is enabled and configure if so if client.TLSConfig != nil { log.Debug("configuring ssl for swarm redirect") scheme = "https://" // setup custom roundtripper with TLS transport r := forward.RoundTripper( &http.Transport{ TLSClientConfig: client.TLSConfig, }) f, err := forward.New(r) if err != nil { return err } a.fwd = f } a.dUrl = fmt.Sprintf("%s%s", scheme, u.Host) log.Debugf("configured docker proxy target: %s", a.dUrl) swarmRedirect := http.HandlerFunc(a.swarmRedirect) swarmHijack := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { a.swarmHijack(client.TLSConfig, a.dUrl, w, req) }) apiRouter := mux.NewRouter() apiRouter.HandleFunc("/api/accounts", a.accounts).Methods("GET") apiRouter.HandleFunc("/api/accounts", a.saveAccount).Methods("POST") apiRouter.HandleFunc("/api/accounts/{username}", a.account).Methods("GET") apiRouter.HandleFunc("/api/accounts/{username}", a.deleteAccount).Methods("DELETE") apiRouter.HandleFunc("/api/svcregs", a.serviceRegs).Methods("GET") apiRouter.HandleFunc("/api/svcregs", a.saveServiceReg).Methods("POST") apiRouter.HandleFunc("/api/svcregs/{service_name}", a.serviceReg).Methods("GET") apiRouter.HandleFunc("/api/svcregs/{service_name}", a.deleteServiceReg).Methods("DELETE") apiRouter.HandleFunc("/api/roles", a.roles).Methods("GET") apiRouter.HandleFunc("/api/roles/{name}", a.role).Methods("GET") apiRouter.HandleFunc("/api/nodes", a.nodes).Methods("GET") apiRouter.HandleFunc("/api/nodes/{name}", a.node).Methods("GET") apiRouter.HandleFunc("/api/containers/{id}/scale", a.scaleContainer).Methods("POST") apiRouter.HandleFunc("/api/events", a.events).Methods("GET") apiRouter.HandleFunc("/api/events", a.purgeEvents).Methods("DELETE") apiRouter.HandleFunc("/api/registries", a.registries).Methods("GET") apiRouter.HandleFunc("/api/registries", a.addRegistry).Methods("POST") apiRouter.HandleFunc("/api/registries/{name}", a.registry).Methods("GET") apiRouter.HandleFunc("/api/registries/{name}", a.removeRegistry).Methods("DELETE") apiRouter.HandleFunc("/api/registries/{name}/repositories", a.repositories).Methods("GET") apiRouter.HandleFunc("/api/registries/{name}/repositories/{repo:.*}", a.repository).Methods("GET") apiRouter.HandleFunc("/api/registries/{name}/repositories/{repo:.*}", a.deleteRepository).Methods("DELETE") apiRouter.HandleFunc("/api/servicekeys", a.serviceKeys).Methods("GET") apiRouter.HandleFunc("/api/servicekeys", a.addServiceKey).Methods("POST") apiRouter.HandleFunc("/api/servicekeys", a.removeServiceKey).Methods("DELETE") apiRouter.HandleFunc("/api/webhookkeys", a.webhookKeys).Methods("GET") apiRouter.HandleFunc("/api/webhookkeys/{id}", a.webhookKey).Methods("GET") apiRouter.HandleFunc("/api/webhookkeys", a.addWebhookKey).Methods("POST") apiRouter.HandleFunc("/api/webhookkeys/{id}", a.deleteWebhookKey).Methods("DELETE") apiRouter.HandleFunc("/api/consolesession/{container}", a.createConsoleSession).Methods("GET") apiRouter.HandleFunc("/api/consolesession/{token}", a.consoleSession).Methods("GET") apiRouter.HandleFunc("/api/consolesession/{token}", a.removeConsoleSession).Methods("DELETE") apiRouter.HandleFunc("/api/getcloudaddr", a.getCloudAddr).Methods("GET") // global handler globalMux.Handle("/", http.FileServer(http.Dir("static"))) auditExcludes := []string{ "^/containers/json", "^/images/json", "^/api/events", } apiAuditor := audit.NewAuditor(controllerManager, auditExcludes) // api router; protected by auth apiAuthRouter := negroni.New() // apiAuthRequired := mAuth.NewAuthRequired(controllerManager, a.authWhitelistCIDRs) // apiAccessRequired := access.NewAccessRequired(controllerManager) // apiAuthRouter.Use(negroni.HandlerFunc(apiAuthRequired.HandlerFuncWithNext)) // apiAuthRouter.Use(negroni.HandlerFunc(apiAccessRequired.HandlerFuncWithNext)) apiAuthRouter.Use(negroni.HandlerFunc(apiAuditor.HandlerFuncWithNext)) apiAuthRouter.UseHandler(apiRouter) globalMux.Handle("/api/", apiAuthRouter) // account router ; protected by auth accountRouter := mux.NewRouter() accountRouter.HandleFunc("/account/changepassword", a.changePassword).Methods("POST") accountAuthRouter := negroni.New() accountAuthRequired := mAuth.NewAuthRequired(controllerManager, a.authWhitelistCIDRs) accountAuthRouter.Use(negroni.HandlerFunc(accountAuthRequired.HandlerFuncWithNext)) accountAuthRouter.Use(negroni.HandlerFunc(apiAuditor.HandlerFuncWithNext)) accountAuthRouter.UseHandler(accountRouter) globalMux.Handle("/account/", accountAuthRouter) // login handler; public loginRouter := mux.NewRouter() loginRouter.HandleFunc("/auth/login", a.login).Methods("POST") globalMux.Handle("/auth/", loginRouter) globalMux.Handle("/exec", websocket.Handler(a.execContainer)) // hub handler; public hubRouter := mux.NewRouter() hubRouter.HandleFunc("/hub/webhook/{id}", a.hubWebhook).Methods("POST") globalMux.Handle("/hub/", hubRouter) // swarm swarmRouter := mux.NewRouter() // these are pulled from the swarm api code to proxy and allow // usage with the standard Docker cli m := map[string]map[string]http.HandlerFunc{ "GET": { "/_ping": swarmRedirect, "/events": swarmRedirect, "/info": swarmRedirect, "/version": swarmRedirect, "/images/json": swarmRedirect, "/images/viz": swarmRedirect, "/images/search": swarmRedirect, "/images/get": swarmRedirect, "/images/{name:.*}/get": swarmRedirect, "/images/{name:.*}/history": swarmRedirect, "/images/{name:.*}/json": swarmRedirect, "/containers/ps": swarmRedirect, "/containers/json": swarmRedirect, "/containers/{name:.*}/export": swarmRedirect, "/containers/{name:.*}/changes": swarmRedirect, "/containers/{name:.*}/json": swarmRedirect, "/containers/{name:.*}/top": swarmRedirect, "/containers/{name:.*}/logs": swarmRedirect, "/containers/{name:.*}/stats": swarmRedirect, "/containers/{name:.*}/attach/ws": swarmHijack, "/exec/{execid:.*}/json": swarmRedirect, }, "POST": { "/auth": swarmRedirect, "/commit": swarmRedirect, "/build": swarmRedirect, "/images/create": swarmRedirect, "/images/load": swarmRedirect, "/images/{name:.*}/push": swarmRedirect, "/images/{name:.*}/tag": swarmRedirect, "/containers/create": swarmRedirect, "/containers/{name:.*}/kill": swarmRedirect, "/containers/{name:.*}/pause": swarmRedirect, "/containers/{name:.*}/unpause": swarmRedirect, "/containers/{name:.*}/rename": swarmRedirect, "/containers/{name:.*}/restart": swarmRedirect, "/containers/{name:.*}/start": swarmRedirect, "/containers/{name:.*}/stop": swarmRedirect, "/containers/{name:.*}/wait": swarmRedirect, "/containers/{name:.*}/resize": swarmRedirect, "/containers/{name:.*}/attach": swarmHijack, "/containers/{name:.*}/copy": swarmRedirect, "/containers/{name:.*}/exec": swarmRedirect, "/exec/{execid:.*}/start": swarmHijack, "/exec/{execid:.*}/resize": swarmRedirect, }, "DELETE": { "/containers/{name:.*}": swarmRedirect, "/images/{name:.*}": swarmRedirect, }, "OPTIONS": { "": swarmRedirect, }, } for method, routes := range m { for route, fct := range routes { localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { if a.enableCors { writeCorsHeaders(w, r) } localFct(w, r) } localMethod := method // add the new route swarmRouter.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap) swarmRouter.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) } } swarmAuthRouter := negroni.New() // swarmAuthRequired := mAuth.NewAuthRequired(controllerManager, a.authWhitelistCIDRs) // swarmAccessRequired := access.NewAccessRequired(controllerManager) // swarmAuthRouter.Use(negroni.HandlerFunc(swarmAuthRequired.HandlerFuncWithNext)) // swarmAuthRouter.Use(negroni.HandlerFunc(swarmAccessRequired.HandlerFuncWithNext)) // swarmAuthRouter.Use(negroni.HandlerFunc(apiAuditor.HandlerFuncWithNext)) swarmAuthRouter.UseHandler(swarmRouter) globalMux.Handle("/containers/", swarmAuthRouter) globalMux.Handle("/_ping", swarmAuthRouter) globalMux.Handle("/commit", swarmAuthRouter) globalMux.Handle("/build", swarmAuthRouter) globalMux.Handle("/events", swarmAuthRouter) globalMux.Handle("/version", swarmAuthRouter) globalMux.Handle("/images/", swarmAuthRouter) globalMux.Handle("/exec/", swarmAuthRouter) globalMux.Handle("/v1.14/", swarmAuthRouter) globalMux.Handle("/v1.15/", swarmAuthRouter) globalMux.Handle("/v1.16/", swarmAuthRouter) globalMux.Handle("/v1.17/", swarmAuthRouter) globalMux.Handle("/v1.18/", swarmAuthRouter) globalMux.Handle("/v1.19/", swarmAuthRouter) globalMux.Handle("/v1.20/", swarmAuthRouter) //eureka eurekaRouter := mux.NewRouter() a.eUrl = fmt.Sprintf("%s%s", scheme, a.eurekaAddr) log.Debugf("configured eureka proxy target: %s", a.eUrl) eurekaRedirect := http.HandlerFunc(a.eurekaRedirect) n := map[string]map[string]http.HandlerFunc{ "GET": { "/eureka/apps": eurekaRedirect, }, } for method, routes := range n { for route, fct := range routes { localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { if a.enableCors { writeCorsHeaders(w, r) } localFct(w, r) } localMethod := method // add the new route eurekaRouter.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) } } eurekaAuthRouter := negroni.New() // eurekaAuthRequired := mAuth.NewAuthRequired(controllerManager, a.authWhitelistCIDRs) // eurekaAccessRequired := access.NewAccessRequired(controllerManager) // eurekaAuthRouter.Use(negroni.HandlerFunc(eurekaAuthRequired.HandlerFuncWithNext)) // eurekaAuthRouter.Use(negroni.HandlerFunc(eurekaAccessRequired.HandlerFuncWithNext)) eurekaAuthRouter.Use(negroni.HandlerFunc(apiAuditor.HandlerFuncWithNext)) eurekaAuthRouter.UseHandler(eurekaRouter) globalMux.Handle("/eureka/", eurekaAuthRouter) //hystrix hystrixRouter := mux.NewRouter() a.hUrl = fmt.Sprintf("%s%s", scheme, a.hystrixAddr) log.Debugf("configured hystrix proxy target: %s", a.hUrl) hystrixRedirect := http.HandlerFunc(a.hystrixRedirect) o := map[string]map[string]http.HandlerFunc{ "GET": { "/proxy.stream": hystrixRedirect, }, } for method, routes := range o { for route, fct := range routes { localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { if a.enableCors { writeCorsHeaders(w, r) } localFct(w, r) } localMethod := method // add the new route hystrixRouter.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) } } hystrixAuthRouter := negroni.New() // hystrixAuthRequired := mAuth.NewAuthRequired(controllerManager, a.authWhitelistCIDRs) // hystrixAccessRequired := access.NewAccessRequired(controllerManager) // hystrixAuthRouter.Use(negroni.HandlerFunc(hystrixAuthRequired.HandlerFuncWithNext)) // hystrixAuthRouter.Use(negroni.HandlerFunc(hystrixAccessRequired.HandlerFuncWithNext)) // hystrixAuthRouter.Use(negroni.HandlerFunc(apiAuditor.HandlerFuncWithNext)) hystrixAuthRouter.UseHandler(hystrixRouter) globalMux.Handle("/proxy.stream", hystrixAuthRouter) // check for admin user if _, err := controllerManager.Account("admin"); err == manager.ErrAccountDoesNotExist { // create roles acct := &auth.Account{ Username: "******", Password: "******", FirstName: "Shipyard", LastName: "Admin", Roles: []string{"admin"}, } if err := controllerManager.SaveAccount(acct); err != nil { log.Fatal(err) } log.Infof("created admin user: username: admin password: shipyard") } log.Infof("controller listening on %s", a.listenAddr) s := &http.Server{ Addr: a.listenAddr, Handler: context.ClearHandler(globalMux), } var runErr error if a.tlsCertPath != "" && a.tlsKeyPath != "" { log.Infof("using TLS for communication: cert=%s key=%s", a.tlsCertPath, a.tlsKeyPath, ) // setup TLS config var caCert []byte if a.tlsCACertPath != "" { ca, err := ioutil.ReadFile(a.tlsCACertPath) if err != nil { return err } caCert = ca } serverCert, err := ioutil.ReadFile(a.tlsCertPath) if err != nil { return err } serverKey, err := ioutil.ReadFile(a.tlsKeyPath) if err != nil { return err } tlsConfig, err := tlsutils.GetServerTLSConfig(caCert, serverCert, serverKey, a.allowInsecure) if err != nil { return err } s.TLSConfig = tlsConfig runErr = s.ListenAndServeTLS(a.tlsCertPath, a.tlsKeyPath) } else { runErr = s.ListenAndServe() } return runErr }
func (a *Api) Run() error { globalMux := http.NewServeMux() // forwarder for swarm var err error a.fwd, err = forward.New() if err != nil { return err } u := a.client.URL // setup redirect target to swarm scheme := "http://" // check if TLS is enabled and configure if so if a.client.TLSConfig != nil { log.Debug("configuring ssl for swarm redirect") scheme = "https://" // setup custom roundtripper with TLS transport r := forward.RoundTripper( &http.Transport{ TLSClientConfig: a.client.TLSConfig, }) f, err := forward.New(r) if err != nil { return err } a.fwd = f } // init key-value path if err := a.initPath(); err != nil { return err } a.dUrl = fmt.Sprintf("%s%s", scheme, u.Host) log.Debugf("configured docker proxy target: %s", a.dUrl) swarmRedirect := http.HandlerFunc(a.swarmRedirect) swarmHijack := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { a.swarmHijack(a.client.TLSConfig, a.dUrl, w, req) }) mh := map[string]map[string]http.HandlerFunc{ "GET": { "/api/gateways": a.gateways, "/api/gateways/{id}": a.gateway, "/api/groups": a.groups, "/api/groups/{name}": a.group, "/api/policy": a.policys, "/api/policy/{peer}": a.policy, "/api/firewalls": a.firewalls, "/api/firewalls/{name}": a.firewallByContainer, "/api/firewalls/{node}/{port}": a.firewall, "/api/containers/{id}": a.showContainer, }, "POST": { "/api/groups": a.saveGroup, "/api/groups/{name}": a.saveMember, "/api/policy/{peer}": a.savePolicy, "/api/firewalls": a.saveFirewall, }, "DELETE": { "/api/groups/{name}": a.deleteGroup, "/api/groups/{name}/{member}": a.deleteMember, "/api/policy/{peer}": a.deletePolicy, "/api/firewalls/{name}": a.deleteFirewall, }, "PUT": { "/api/containers/{id}/reset": a.resetContainer, }, } apiRouter := mux.NewRouter() for method, routes := range mh { for route, fct := range routes { localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { localFct(w, r) } localMethod := method // add the new route apiRouter.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap) apiRouter.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) } } // global handler globalMux.Handle("/", http.FileServer(http.Dir("static"))) globalMux.Handle("/api/", apiRouter) //globalMux.Handle("/v{version:[0-9.]+}/api/", apiRouter) globalMux.Handle("/v1.14/api/", apiRouter) globalMux.Handle("/v1.15/api/", apiRouter) globalMux.Handle("/v1.16/api/", apiRouter) globalMux.Handle("/v1.17/api/", apiRouter) globalMux.Handle("/v1.18/api/", apiRouter) globalMux.Handle("/v1.19/api/", apiRouter) globalMux.Handle("/v1.20/api/", apiRouter) globalMux.Handle("/v1.21/api/", apiRouter) globalMux.Handle("/v1.22/api/", apiRouter) globalMux.Handle("/v1.23/api/", apiRouter) globalMux.Handle("/v1.24/api/", apiRouter) globalMux.Handle("/v1.25/api/", apiRouter) globalMux.Handle("/v1.26/api/", apiRouter) // swarm swarmRouter := mux.NewRouter() // these are pulled from the swarm api code to proxy and allow // usage with the standard Docker cli m := map[string]map[string]http.HandlerFunc{ "GET": { "/_ping": swarmRedirect, "/events": swarmRedirect, "/info": swarmRedirect, "/version": swarmRedirect, "/images/json": swarmRedirect, "/images/viz": swarmRedirect, "/images/search": swarmRedirect, "/images/get": swarmRedirect, "/images/{name:.*}/get": swarmRedirect, "/images/{name:.*}/history": swarmRedirect, "/images/{name:.*}/json": swarmRedirect, "/containers/ps": swarmRedirect, "/containers/json": swarmRedirect, "/containers/{name:.*}/export": swarmRedirect, "/containers/{name:.*}/changes": swarmRedirect, "/containers/{name:.*}/json": swarmRedirect, "/containers/{name:.*}/top": swarmRedirect, "/containers/{name:.*}/logs": swarmRedirect, "/containers/{name:.*}/stats": swarmRedirect, "/containers/{name:.*}/attach/ws": swarmHijack, "/exec/{execid:.*}/json": swarmRedirect, "/networks": swarmRedirect, "/networks/{networkid:.*}": swarmRedirect, "/volumes": swarmRedirect, "/volumes/{volumename:.*}": swarmRedirect, }, "POST": { "/auth": swarmRedirect, "/commit": swarmRedirect, "/build": swarmRedirect, "/images/create": swarmRedirect, "/images/load": swarmRedirect, "/images/{name:.*}/push": swarmRedirect, "/images/{name:.*}/tag": swarmRedirect, "/containers/create": swarmRedirect, "/containers/{name:.*}/kill": swarmRedirect, "/containers/{name:.*}/pause": swarmRedirect, "/containers/{name:.*}/unpause": swarmRedirect, "/containers/{name:.*}/rename": swarmRedirect, "/containers/{name:.*}/restart": swarmRedirect, "/containers/{name:.*}/start": swarmRedirect, "/containers/{name:.*}/stop": swarmRedirect, "/containers/{name:.*}/wait": swarmRedirect, "/containers/{name:.*}/resize": swarmRedirect, "/containers/{name:.*}/attach": swarmHijack, "/containers/{name:.*}/copy": swarmRedirect, "/containers/{name:.*}/exec": swarmRedirect, "/exec/{execid:.*}/start": swarmHijack, "/exec/{execid:.*}/resize": swarmRedirect, "/networks/create": swarmRedirect, "/networks/{networkid:.*}/connect": swarmRedirect, "/networks/{networkid:.*}/disconnect": swarmRedirect, "/volumes/create": swarmRedirect, }, "PUT": { "/containers/{name:.*}/archive": swarmRedirect, }, "DELETE": { "/containers/{name:.*}": swarmRedirect, "/images/{name:.*}": swarmRedirect, "/networks/{networkid:.*}": swarmRedirect, "/volumes/{name:.*}": swarmRedirect, }, "OPTIONS": { "": swarmRedirect, }, } for method, routes := range m { for route, fct := range routes { localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { localFct(w, r) } localMethod := method // add the new route swarmRouter.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap) swarmRouter.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) } } globalMux.Handle("/containers/", swarmRouter) globalMux.Handle("/_ping", swarmRouter) globalMux.Handle("/commit", swarmRouter) globalMux.Handle("/build", swarmRouter) globalMux.Handle("/events", swarmRouter) globalMux.Handle("/version", swarmRouter) globalMux.Handle("/images/", swarmRouter) globalMux.Handle("/exec/", swarmRouter) globalMux.Handle("/v1.14/", swarmRouter) globalMux.Handle("/v1.15/", swarmRouter) globalMux.Handle("/v1.16/", swarmRouter) globalMux.Handle("/v1.17/", swarmRouter) globalMux.Handle("/v1.18/", swarmRouter) globalMux.Handle("/v1.19/", swarmRouter) globalMux.Handle("/v1.20/", swarmRouter) globalMux.Handle("/v1.21/", swarmRouter) globalMux.Handle("/v1.22/", swarmRouter) globalMux.Handle("/v1.23/", swarmRouter) globalMux.Handle("/v1.24/", swarmRouter) globalMux.Handle("/v1.25/", swarmRouter) globalMux.Handle("/v1.26/", swarmRouter) log.Infof("controller listening on %s", a.listenAddr) s := &http.Server{ Addr: a.listenAddr, Handler: context.ClearHandler(globalMux), } var runErr error runErr = s.ListenAndServe() return runErr }