github.com/kvattikuti/drone@v0.2.1-0.20140603034306-d400229a327a/cmd/droned/drone.go (about) 1 package main 2 3 import ( 4 "flag" 5 "log" 6 "net/http" 7 "runtime" 8 "strings" 9 "time" 10 11 "code.google.com/p/go.net/websocket" 12 "github.com/GeertJohan/go.rice" 13 "github.com/bmizerany/pat" 14 15 "github.com/drone/drone/pkg/build/docker" 16 "github.com/drone/drone/pkg/channel" 17 "github.com/drone/drone/pkg/database" 18 "github.com/drone/drone/pkg/handler" 19 "github.com/drone/drone/pkg/queue" 20 ) 21 22 var ( 23 // port the server will run on 24 port string 25 26 // database driver used to connect to the database 27 driver string 28 29 // driver specific connection information. In this 30 // case, it should be the location of the SQLite file 31 datasource string 32 33 // optional flags for tls listener 34 sslcert string 35 sslkey string 36 37 // build will timeout after N milliseconds. 38 // this will default to 500 minutes (6 hours) 39 timeout time.Duration 40 41 // commit sha for the current build. 42 version string 43 44 // Number of concurrent build workers to run 45 // default to number of CPUs on machine 46 workers int 47 ) 48 49 func main() { 50 // parse command line flags 51 flag.StringVar(&port, "port", ":8080", "") 52 flag.StringVar(&driver, "driver", "sqlite3", "") 53 flag.StringVar(&datasource, "datasource", "drone.sqlite", "") 54 flag.StringVar(&sslcert, "sslcert", "", "") 55 flag.StringVar(&sslkey, "sslkey", "", "") 56 flag.DurationVar(&timeout, "timeout", 300*time.Minute, "") 57 flag.IntVar(&workers, "workers", runtime.NumCPU(), "") 58 flag.Parse() 59 60 // validate the TLS arguments 61 checkTLSFlags() 62 63 // setup database and handlers 64 if err := database.Init(driver, datasource); err != nil { 65 log.Fatal("Can't initialize database: ", err) 66 } 67 discardOldBuilds() 68 setupStatic() 69 setupHandlers() 70 71 // debug 72 log.Printf("starting drone version %s on port %s\n", version, port) 73 74 // start webserver using HTTPS or HTTP 75 if sslcert != "" && sslkey != "" { 76 panic(http.ListenAndServeTLS(port, sslcert, sslkey, nil)) 77 } else { 78 panic(http.ListenAndServe(port, nil)) 79 } 80 } 81 82 // checking if the TLS flags where supplied correctly. 83 func checkTLSFlags() { 84 85 if sslcert != "" && sslkey == "" { 86 log.Fatal("invalid configuration: -sslkey unspecified, but -sslcert was specified.") 87 } else if sslcert == "" && sslkey != "" { 88 log.Fatal("invalid configuration: -sslcert unspecified, but -sslkey was specified.") 89 } 90 91 } 92 93 // discardOldBuilds sets builds that are in the 'Started' 94 // state to 'Failure' on startup. The assumption is that 95 // the drone process was shut down mid-build and thus the 96 // builds will never complete. 97 func discardOldBuilds() { 98 err := database.FailUnfinishedBuilds() 99 if err != nil { 100 log.Fatal(err) 101 } 102 103 err = database.FailUnfinishedCommits() 104 if err != nil { 105 log.Fatal(err) 106 } 107 } 108 109 // setup routes for static assets. These assets may 110 // be directly embedded inside the application using 111 // the `rice embed` command, else they are served from disk. 112 func setupStatic() { 113 box := rice.MustFindBox("assets") 114 http.Handle("/css/", http.FileServer(box.HTTPBox())) 115 http.Handle("/js/", http.FileServer(box.HTTPBox())) 116 117 // we need to intercept all attempts to serve images 118 // so that we can add a cache-control settings 119 var images = http.FileServer(box.HTTPBox()) 120 http.HandleFunc("/img/", func(w http.ResponseWriter, r *http.Request) { 121 if strings.HasPrefix(r.URL.Path, "/img/build_") { 122 w.Header().Add("Cache-Control", "no-cache") 123 } 124 125 // serce images 126 images.ServeHTTP(w, r) 127 }) 128 } 129 130 // setup routes for serving dynamic content. 131 func setupHandlers() { 132 println("setting up handlers") 133 var dckr = docker.New() 134 queueRunner := queue.NewBuildRunner(dckr, timeout) 135 println("queueRunner.dockerClient", dckr); 136 queue := queue.Start(workers, queueRunner) 137 138 var ( 139 github = handler.NewGithubHandler(queue) 140 gitlab = handler.NewGitlabHandler(queue) 141 bitbucket = handler.NewBitbucketHandler(queue) 142 gogs = handler.NewGogsHandler(queue) 143 ) 144 145 m := pat.New() 146 m.Get("/login", handler.ErrorHandler(handler.Login)) 147 m.Post("/login", handler.ErrorHandler(handler.Authorize)) 148 m.Get("/logout", handler.ErrorHandler(handler.Logout)) 149 m.Get("/forgot", handler.ErrorHandler(handler.Forgot)) 150 m.Post("/forgot", handler.ErrorHandler(handler.ForgotPost)) 151 m.Get("/reset", handler.ErrorHandler(handler.Reset)) 152 m.Post("/reset", handler.ErrorHandler(handler.ResetPost)) 153 m.Get("/signup", handler.ErrorHandler(handler.SignUp)) 154 m.Post("/signup", handler.ErrorHandler(handler.SignUpPost)) 155 m.Get("/register", handler.ErrorHandler(handler.Register)) 156 m.Post("/register", handler.ErrorHandler(handler.RegisterPost)) 157 m.Get("/accept", handler.UserHandler(handler.TeamMemberAccept)) 158 159 // handlers for setting up your GitHub repository 160 m.Post("/new/github.com", handler.UserHandler(handler.RepoCreateGithub)) 161 m.Get("/new/github.com", handler.UserHandler(handler.RepoAddGithub)) 162 163 // handlers for linking your GitHub account 164 m.Get("/auth/login/github", handler.UserHandler(handler.LinkGithub)) 165 166 // handlers for setting up your Bitbucket repository 167 m.Post("/new/bitbucket.org", handler.UserHandler(handler.RepoCreateBitbucket)) 168 m.Get("/new/bitbucket.org", handler.UserHandler(handler.RepoAddBitbucket)) 169 170 // handlers for linking your Bitbucket account 171 m.Get("/auth/login/bitbucket", handler.UserHandler(handler.LinkBitbucket)) 172 173 // handlers for setting up your GitLab repository 174 m.Post("/new/gitlab", handler.UserHandler(gitlab.Create)) 175 m.Get("/new/gitlab", handler.UserHandler(gitlab.Add)) 176 177 // handler for linking GitLab account 178 m.Post("/link/gitlab", handler.UserHandler(gitlab.Link)) 179 m.Get("/link/gitlab", handler.UserHandler(gitlab.ReLink)) 180 181 // handlers for dashboard pages 182 m.Get("/dashboard/team/:team", handler.UserHandler(handler.TeamShow)) 183 m.Get("/dashboard", handler.UserHandler(handler.UserShow)) 184 185 // handlers for user account management 186 m.Get("/account/user/profile", handler.UserHandler(handler.UserEdit)) 187 m.Post("/account/user/profile", handler.UserHandler(handler.UserUpdate)) 188 m.Get("/account/user/delete", handler.UserHandler(handler.UserDeleteConfirm)) 189 m.Post("/account/user/delete", handler.UserHandler(handler.UserDelete)) 190 m.Get("/account/user/password", handler.UserHandler(handler.UserPass)) 191 m.Post("/account/user/password", handler.UserHandler(handler.UserPassUpdate)) 192 m.Get("/account/user/teams/add", handler.UserHandler(handler.TeamAdd)) 193 m.Post("/account/user/teams/add", handler.UserHandler(handler.TeamCreate)) 194 m.Get("/account/user/teams", handler.UserHandler(handler.UserTeams)) 195 196 // handlers for team managements 197 m.Get("/account/team/:team/profile", handler.UserHandler(handler.TeamEdit)) 198 m.Post("/account/team/:team/profile", handler.UserHandler(handler.TeamUpdate)) 199 m.Get("/account/team/:team/delete", handler.UserHandler(handler.TeamDeleteConfirm)) 200 m.Post("/account/team/:team/delete", handler.UserHandler(handler.TeamDelete)) 201 m.Get("/account/team/:team/members/add", handler.UserHandler(handler.TeamMemberAdd)) 202 m.Post("/account/team/:team/members/add", handler.UserHandler(handler.TeamMemberInvite)) 203 m.Get("/account/team/:team/members/edit", handler.UserHandler(handler.TeamMemberEdit)) 204 m.Post("/account/team/:team/members/edit", handler.UserHandler(handler.TeamMemberUpdate)) 205 m.Post("/account/team/:team/members/delete", handler.UserHandler(handler.TeamMemberDelete)) 206 m.Get("/account/team/:team/members", handler.UserHandler(handler.TeamMembers)) 207 208 // handlers for system administration 209 m.Get("/account/admin/settings", handler.AdminHandler(handler.AdminSettings)) 210 m.Post("/account/admin/settings", handler.AdminHandler(handler.AdminSettingsUpdate)) 211 m.Get("/account/admin/users/edit", handler.AdminHandler(handler.AdminUserEdit)) 212 m.Post("/account/admin/users/edit", handler.AdminHandler(handler.AdminUserUpdate)) 213 m.Post("/account/admin/users/delete", handler.AdminHandler(handler.AdminUserDelete)) 214 m.Get("/account/admin/users/add", handler.AdminHandler(handler.AdminUserAdd)) 215 m.Post("/account/admin/users", handler.AdminHandler(handler.AdminUserInvite)) 216 m.Get("/account/admin/users", handler.AdminHandler(handler.AdminUserList)) 217 218 // handlers for GitHub post-commit hooks 219 m.Post("/hook/github.com", handler.ErrorHandler(github.Hook)) 220 221 // handlers for Bitbucket post-commit hooks 222 m.Post("/hook/bitbucket.org", handler.ErrorHandler(bitbucket.Hook)) 223 224 // handlers for GitLab post-commit hooks 225 m.Post("/hook/gitlab", handler.ErrorHandler(gitlab.Hook)) 226 227 // handlers for gogs post-commit hooks 228 m.Post("/hook/gogs", handler.ErrorHandler(gogs.Hook)) 229 230 // handlers for first-time installation 231 m.Get("/install", handler.ErrorHandler(handler.Install)) 232 m.Post("/install", handler.ErrorHandler(handler.InstallPost)) 233 234 // handlers for repository, commits and build details 235 m.Get("/:host/:owner/:name/commit/:commit/build/:label/out.txt", handler.RepoHandler(handler.BuildOut)) 236 m.Get("/:host/:owner/:name/commit/:commit/build/:label", handler.RepoHandler(handler.CommitShow)) 237 m.Get("/:host/:owner/:name/commit/:commit", handler.RepoHandler(handler.CommitShow)) 238 m.Get("/:host/:owner/:name/tree", handler.RepoHandler(handler.RepoDashboard)) 239 m.Get("/:host/:owner/:name/status.svg", handler.ErrorHandler(handler.Badge)) 240 m.Get("/:host/:owner/:name/settings", handler.RepoAdminHandler(handler.RepoSettingsForm)) 241 m.Get("/:host/:owner/:name/params", handler.RepoAdminHandler(handler.RepoParamsForm)) 242 m.Get("/:host/:owner/:name/badges", handler.RepoAdminHandler(handler.RepoBadges)) 243 m.Get("/:host/:owner/:name/keys", handler.RepoAdminHandler(handler.RepoKeys)) 244 m.Get("/:host/:owner/:name/delete", handler.RepoAdminHandler(handler.RepoDeleteForm)) 245 m.Post("/:host/:owner/:name/delete", handler.RepoAdminHandler(handler.RepoDelete)) 246 m.Get("/:host/:owner/:name", handler.RepoHandler(handler.RepoDashboard)) 247 m.Post("/:host/:owner/:name", handler.RepoHandler(handler.RepoUpdate)) 248 http.Handle("/feed", websocket.Handler(channel.Read)) 249 250 // no routes are served at the root URL. Instead we will 251 // redirect the user to his/her dashboard page. 252 m.Get("/", http.RedirectHandler("/dashboard", http.StatusSeeOther)) 253 254 // the first time a page is requested we should record 255 // the scheme and hostname. 256 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 257 // our multiplexer is a bit finnicky and therefore requires 258 // us to strip any trailing slashes in order to correctly 259 // find and match a route. 260 if r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/") { 261 http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusSeeOther) 262 return 263 } 264 265 // standard header variables that should be set, for good measure. 266 w.Header().Add("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate") 267 w.Header().Add("X-Frame-Options", "DENY") 268 w.Header().Add("X-Content-Type-Options", "nosniff") 269 w.Header().Add("X-XSS-Protection", "1; mode=block") 270 271 // ok, now we're ready to serve the request. 272 m.ServeHTTP(w, r) 273 }) 274 }