// Broker is a middleware function that initializes the broker // and adds the broker client to the request context. func Broker(cli *cli.Context) gin.HandlerFunc { secret := cli.String("agent-secret") if secret == "" { logrus.Fatalf("fatal error. please provide the DRONE_SECRET") } // setup broker logging. log := redlog.New(os.Stderr) log.SetLevel(0) logger.SetLogger(log) if cli.Bool("broker-debug") { log.SetLevel(1) } broker := server.NewServer( server.WithCredentials("x-token", secret), ) client := broker.Client() var once sync.Once return func(c *gin.Context) { c.Set(serverKey, broker) c.Set(clientKey, client) once.Do(func() { // this is some really hacky stuff // turns out I need to do some refactoring // don't judge! // will fix in 0.6 release ctx := c.Copy() client.Connect( stomp.WithCredentials("x-token", secret), ) client.Subscribe("/queue/updates", stomp.HandlerFunc(func(m *stomp.Message) { go handlers.HandleUpdate(ctx, m.Copy()) })) }) } }
func start(c *cli.Context) { log := redlog.New(os.Stderr) log.SetLevel(0) logger.SetLogger(log) // debug level if requested by user if c.Bool("debug") { logrus.SetLevel(logrus.DebugLevel) log.SetLevel(1) } else { logrus.SetLevel(logrus.WarnLevel) } var accessToken string if c.String("drone-secret") != "" { // secretToken := c.String("drone-secret") accessToken = c.String("drone-secret") // accessToken, _ = token.New(token.AgentToken, "").Sign(secretToken) } else { accessToken = c.String("drone-token") } logger.Noticef("connecting to server %s", c.String("drone-server")) server := strings.TrimRight(c.String("drone-server"), "/") tls, err := dockerclient.TLSConfigFromCertPath(c.String("docker-cert-path")) if err == nil { tls.InsecureSkipVerify = c.Bool("docker-tls-verify") } docker, err := dockerclient.NewDockerClient(c.String("docker-host"), tls) if err != nil { logrus.Fatal(err) } var client *stomp.Client handler := func(m *stomp.Message) { running.Add(1) defer func() { running.Done() client.Ack(m.Ack) }() r := pipeline{ drone: client, docker: docker, config: config{ platform: c.String("docker-os") + "/" + c.String("docker-arch"), timeout: c.Duration("timeout"), namespace: c.String("namespace"), privileged: c.StringSlice("privileged"), pull: c.BoolT("pull"), logs: int64(c.Int("max-log-size")) * 1000000, }, } work := new(model.Work) m.Unmarshal(work) r.run(work) } handleSignals() backoff := c.Duration("backoff") for { // dial the drone server to establish a TCP connection. client, err = stomp.Dial(server) if err != nil { logger.Warningf("connection failed, retry in %v. %s", backoff, err) <-time.After(backoff) continue } opts := []stomp.MessageOption{ stomp.WithCredentials("x-token", accessToken), } // initialize the stomp session and authenticate. if err = client.Connect(opts...); err != nil { logger.Warningf("session failed, retry in %v. %s", backoff, err) <-time.After(backoff) continue } opts = []stomp.MessageOption{ stomp.WithAck("client"), stomp.WithPrefetch( c.Int("docker-max-procs"), ), } if filter := c.String("filter"); filter != "" { opts = append(opts, stomp.WithSelector(filter)) } // subscribe to the pending build queue. client.Subscribe("/queue/pending", stomp.HandlerFunc(func(m *stomp.Message) { go handler(m) // HACK until we a channel based Subscribe implementation }), opts...) logger.Noticef("connection established, ready to process builds.") <-client.Done() logger.Warningf("connection interrupted, attempting to reconnect.") } }