github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/builder/routes.go (about) 1 package builder 2 3 import ( 4 "time" 5 6 "github.com/Masterminds/cookoo" 7 "github.com/Masterminds/cookoo/fmt" 8 "github.com/deis/deis/builder/confd" 9 "github.com/deis/deis/builder/docker" 10 "github.com/deis/deis/builder/env" 11 "github.com/deis/deis/builder/etcd" 12 "github.com/deis/deis/builder/git" 13 "github.com/deis/deis/builder/sshd" 14 ) 15 16 // routes builds the Cookoo registry. 17 // 18 // Esssentially this is a list of all of the things that Builder can do, broken 19 // down into a step-by-step list. 20 func routes(reg *cookoo.Registry) { 21 22 // The "boot" route starts up the builder as a daemon process. Along the 23 // way, it starts and configures multiple services, including etcd, confd, 24 // and sshd. 25 reg.AddRoute(cookoo.Route{ 26 Name: "boot", 27 Help: "Boot the builder", 28 Does: []cookoo.Task{ 29 30 // ENV: Make sure the environment is correct. 31 cookoo.Cmd{ 32 Name: "vars", 33 Fn: env.Get, 34 Using: []cookoo.Param{ 35 {Name: "HOST", DefaultValue: "127.0.0.1"}, 36 {Name: "ETCD_PORT", DefaultValue: "4001"}, 37 {Name: "ETCD_PATH", DefaultValue: "/deis/builder"}, 38 {Name: "ETCD_TTL", DefaultValue: "20"}, 39 }, 40 }, 41 cookoo.Cmd{ // This depends on others being processed first. 42 Name: "vars2", 43 Fn: env.Get, 44 Using: []cookoo.Param{ 45 {Name: "ETCD", DefaultValue: "$HOST:$ETCD_PORT"}, 46 }, 47 }, 48 49 // DOCKER: start up Docker and make sure it's running. 50 // Then let it download the images while we keep going. 51 cookoo.Cmd{ 52 Name: "docker", 53 Fn: docker.CreateClient, 54 Using: []cookoo.Param{ 55 {Name: "url", DefaultValue: "unix:///var/run/docker.sock"}, 56 }, 57 }, 58 cookoo.Cmd{ 59 Name: "dockerclean", 60 Fn: docker.Cleanup, 61 }, 62 cookoo.Cmd{ 63 Name: "dockerstart", 64 Fn: docker.Start, 65 }, 66 cookoo.Cmd{ 67 Name: "waitfordocker", 68 Fn: docker.WaitForStart, 69 Using: []cookoo.Param{ 70 {Name: "client", From: "cxt:docker"}, 71 }, 72 }, 73 74 cookoo.Cmd{ 75 Name: "buildImages", 76 Fn: docker.ParallelBuild, 77 Using: []cookoo.Param{ 78 {Name: "client", From: "cxt:docker"}, 79 { 80 Name: "images", 81 DefaultValue: []docker.BuildImg{ 82 {Path: "/usr/local/src/slugbuilder/", Tag: "deis/slugbuilder"}, 83 {Path: "/usr/local/src/slugrunner/", Tag: "deis/slugrunner"}, 84 }, 85 }, 86 }, 87 }, 88 89 // ETCD: Make sure Etcd is running, and do the initial population. 90 cookoo.Cmd{ 91 Name: "client", 92 Fn: etcd.CreateClient, 93 Using: []cookoo.Param{{Name: "url", DefaultValue: "http://127.0.0.1:4001", From: "cxt:ETCD"}}, 94 }, 95 cookoo.Cmd{ 96 Name: "etcdup", 97 Fn: etcd.IsRunning, 98 Using: []cookoo.Param{ 99 {Name: "client", From: "cxt:client"}, 100 {Name: "count", DefaultValue: 20}, 101 }, 102 }, 103 cookoo.Cmd{ 104 Name: "-", 105 Fn: Sleep, 106 Using: []cookoo.Param{ 107 {Name: "duration", DefaultValue: 21 * time.Second}, 108 {Name: "message", DefaultValue: "Sleeping while etcd expires keys."}, 109 }, 110 }, 111 cookoo.Cmd{ 112 Name: "newdir", 113 Fn: fmt.Sprintf, 114 Using: []cookoo.Param{ 115 {Name: "format", DefaultValue: "%s/users"}, 116 {Name: "0", From: "cxt:ETCD_PATH"}, 117 }, 118 }, 119 cookoo.Cmd{ 120 Name: "mkdir", 121 Fn: etcd.MakeDir, 122 Using: []cookoo.Param{ 123 {Name: "path", From: "cxt:newdir"}, 124 {Name: "client", From: "cxt:client"}, 125 }, 126 }, 127 128 // SSHD: Create and configure host keys. 129 cookoo.Cmd{ 130 Name: "installSshHostKeys", 131 Fn: etcd.StoreHostKeys, 132 Using: []cookoo.Param{ 133 {Name: "client", From: "cxt:client"}, 134 {Name: "basepath", From: "cxt:ETCD_PATH"}, 135 }, 136 }, 137 cookoo.Cmd{ 138 Name: sshd.HostKeys, 139 Fn: sshd.ParseHostKeys, 140 }, 141 cookoo.Cmd{ 142 Name: sshd.ServerConfig, 143 Fn: sshd.Configure, 144 }, 145 146 // CONFD: Build out the templates, then start the Confd server. 147 cookoo.Cmd{ 148 Name: "once", 149 Fn: confd.RunOnce, 150 Using: []cookoo.Param{{Name: "node", From: "cxt:ETCD"}}, 151 }, 152 cookoo.Cmd{ 153 Name: "confd", 154 Fn: confd.Run, 155 Using: []cookoo.Param{{Name: "node", From: "cxt:ETCD"}}, 156 }, 157 158 // Now we wait for Docker to finish downloading. 159 cookoo.Cmd{ 160 Name: "dowloadImages", 161 Fn: docker.Wait, 162 Using: []cookoo.Param{ 163 {Name: "wg", From: "cxt:buildImages"}, 164 {Name: "msg", DefaultValue: "Images downloaded"}, 165 {Name: "waiting", DefaultValue: "Downloading Docker images. This may take a long time. https://xkcd.com/303/"}, 166 {Name: "failures", From: "cxt:ParallelBuild.failN"}, 167 }, 168 }, 169 cookoo.Cmd{ 170 Name: "pushImages", 171 Fn: docker.Push, 172 Using: []cookoo.Param{ 173 {Name: "tag", DefaultValue: "deis/slugrunner:latest"}, 174 {Name: "client", From: "cxt:client"}, 175 }, 176 }, 177 178 // ETDCD: Now watch for events on etcd, and trigger a git check-repos for 179 // each. For the most part, this runs in the background. 180 cookoo.Cmd{ 181 Name: "Cleanup", 182 Fn: etcd.Watch, 183 Using: []cookoo.Param{ 184 {Name: "client", From: "cxt:client"}, 185 }, 186 }, 187 // If there's an EXTERNAL_PORT, we publish info to etcd. 188 cookoo.Cmd{ 189 Name: "externalport", 190 Fn: env.Get, 191 Using: []cookoo.Param{ 192 {Name: "EXTERNAL_PORT", DefaultValue: ""}, 193 }, 194 }, 195 cookoo.Cmd{ 196 Name: "etcdupdate", 197 Fn: etcd.UpdateHostPort, 198 Using: []cookoo.Param{ 199 {Name: "base", From: "cxt:ETCD_PATH"}, 200 {Name: "host", From: "cxt:HOST"}, 201 {Name: "port", From: "cxt:EXTERNAL_PORT"}, 202 {Name: "client", From: "cxt:client"}, 203 {Name: "sshdPid", From: "cxt:sshd"}, 204 }, 205 }, 206 207 // DAEMON: Finally, we wait around for a signal, and then cleanup. 208 cookoo.Cmd{ 209 Name: "listen", 210 Fn: KillOnExit, 211 Using: []cookoo.Param{ 212 {Name: "docker", From: "cxt:dockerstart"}, 213 {Name: "sshd", From: "cxt:sshdstart"}, 214 }, 215 }, 216 }, 217 }) 218 219 // This route is called during a user authentication for SSH. 220 // The rough pattern is that we parse the local authorized keys file, and 221 // then validate that the supplied user key matches an authorized key. 222 // 223 // This grants access to running git-receive, but does not grant access 224 // to writing to the repo. That's handled by the sshReceive. 225 reg.AddRoute(cookoo.Route{ 226 Name: "pubkeyAuth", 227 Does: []cookoo.Task{ 228 // Parse the authorized keys file. 229 // We do this every time because confd is constantly regenerating 230 // the auth keys file. 231 cookoo.Cmd{ 232 Name: "authorizedKeys", 233 Fn: sshd.ParseAuthorizedKeys, 234 Using: []cookoo.Param{ 235 {Name: "path", DefaultValue: "/home/git/.ssh/authorized_keys"}, 236 }, 237 }, 238 239 // Auth against the keys 240 cookoo.Cmd{ 241 Name: "authN", 242 Fn: sshd.AuthKey, 243 Using: []cookoo.Param{ 244 {Name: "metadata", From: "cxt:metadata"}, 245 {Name: "key", From: "cxt:key"}, 246 {Name: "authorizedKeys", From: "cxt:authorizedKeys"}, 247 }, 248 }, 249 }, 250 }) 251 252 // This provides a very basic SSH ping. 253 // Called by the sshd.Server 254 reg.AddRoute(cookoo.Route{ 255 Name: "sshPing", 256 Help: "Handles an ssh exec ping.", 257 Does: []cookoo.Task{ 258 cookoo.Cmd{ 259 Name: "ping", 260 Fn: sshd.Ping, 261 Using: []cookoo.Param{ 262 {Name: "request", From: "cxt:request"}, 263 {Name: "channel", From: "cxt:channel"}, 264 }, 265 }, 266 }, 267 }) 268 269 // This proxies a client session into a git receive. 270 // 271 // Called by the sshd.Server 272 reg.AddRoute(cookoo.Route{ 273 Name: "sshGitReceive", 274 Help: "Handle a git receive over an SSH connection.", 275 Does: []cookoo.Task{ 276 // The Git receive handler needs the username. So we provide 277 // it by looking up the name based on the key. When the 278 // controller no longer requires username for SSH auth, we can 279 // ditch this. 280 cookoo.Cmd{ 281 Name: "fingerprint", 282 Fn: sshd.FingerprintKey, 283 Using: []cookoo.Param{ 284 {Name: "key", From: "cxt:key"}, 285 }, 286 }, 287 cookoo.Cmd{ 288 Name: "username", 289 Fn: etcd.FindSSHUser, 290 Using: []cookoo.Param{ 291 {Name: "client", From: "cxt:client"}, 292 {Name: "fingerprint", From: "cxt:fingerprint"}, 293 }, 294 }, 295 cookoo.Cmd{ 296 Name: "receive", 297 Fn: git.Receive, 298 Using: []cookoo.Param{ 299 {Name: "request", From: "cxt:request"}, 300 {Name: "channel", From: "cxt:channel"}, 301 {Name: "operation", From: "cxt:operation"}, 302 {Name: "repoName", From: "cxt:repository"}, 303 {Name: "fingerprint", From: "cxt:fingerprint"}, 304 {Name: "permissions", From: "cxt:authN"}, 305 {Name: "user", From: "cxt:username"}, 306 }, 307 }, 308 }, 309 }) 310 }