Exemple #1
0
// RunHealth launches the Health API, which only exposes a method to fetch
// quay-sec's health without any security or authentification mechanism.
func RunHealth(port int, st *utils.Stopper) {
	log.Infof("starting Health API on port %d.", port)
	defer func() {
		log.Info("Health API stopped")
		st.End()
	}()

	srv := &graceful.Server{
		Timeout:          10 * time.Second, // Interrupt health checks when stopping
		NoSignalHandling: true,             // We want to use our own Stopper
		Server: &http.Server{
			Addr:    ":" + strconv.Itoa(port),
			Handler: NewHealthRouter(),
		},
	}
	listenAndServeWithStopper(srv, st, "", "")
}
Exemple #2
0
// listenAndServeWithStopper wraps graceful.Server's
// ListenAndServe/ListenAndServeTLS and adds the ability to interrupt them with
// the provided utils.Stopper
func listenAndServeWithStopper(srv *graceful.Server, st *utils.Stopper, certFile, keyFile string) {
	go func() {
		<-st.Chan()
		srv.Stop(0)
	}()

	var err error
	if certFile != "" && keyFile != "" {
		log.Info("API: TLS Enabled")
		err = srv.ListenAndServeTLS(certFile, keyFile)
	} else {
		err = srv.ListenAndServe()
	}

	if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
		log.Fatal(err)
	}
}
Exemple #3
0
// RunMain launches the main API, which exposes every possible interactions
// with quay-sec.
func RunMain(conf *Config, st *utils.Stopper) {
	log.Infof("starting API on port %d.", conf.Port)
	defer func() {
		log.Info("API stopped")
		st.End()
	}()

	srv := &graceful.Server{
		Timeout:          0,    // Already handled by our TimeOut middleware
		NoSignalHandling: true, // We want to use our own Stopper
		Server: &http.Server{
			Addr:      ":" + strconv.Itoa(conf.Port),
			TLSConfig: setupClientCert(conf.CAFile),
			Handler:   NewVersionRouter(conf.TimeOut),
		},
	}
	listenAndServeWithStopper(srv, st, conf.CertFile, conf.KeyFile)
}
Exemple #4
0
// Run pops notifications from the database, lock them, send them, mark them as
// send and unlock them
//
// It uses an exponential backoff when POST requests fail
func (notifier *HTTPNotifier) Run(st *utils.Stopper) {
	defer st.End()

	whoAmI := uuid.New()
	log.Infof("HTTP notifier started. URL: %s. Lock Identifier: %s", notifier.url, whoAmI)

	for {
		node, notification, err := database.FindOneNotificationToSend(database.GetDefaultNotificationWrapper())
		if notification == nil || err != nil {
			if err != nil {
				log.Warningf("could not get notification to send: %s.", err)
			}

			if !st.Sleep(checkInterval) {
				break
			}

			continue
		}

		// Try to lock the notification
		hasLock, hasLockUntil := database.Lock(node, lockDuration, whoAmI)
		if !hasLock {
			continue
		}

		for backOff := time.Duration(0); ; backOff = timeutil.ExpBackoff(backOff, maxBackOff) {
			// Backoff, it happens when an error occurs during the communication
			// with the notification endpoint
			if backOff > 0 {
				// Renew lock before going to sleep if necessary
				if time.Now().Add(backOff).After(hasLockUntil.Add(-refreshLockAnticipation)) {
					hasLock, hasLockUntil = database.Lock(node, lockDuration, whoAmI)
					if !hasLock {
						log.Warning("lost lock ownership, aborting")
						break
					}
				}

				// Sleep
				if !st.Sleep(backOff) {
					return
				}
			}

			// Get notification content
			content, err := notification.GetContent()
			if err != nil {
				log.Warningf("could not get content of notification '%s': %s", notification.GetName(), err.Error())
				break
			}

			// Marshal the notification content
			jsonContent, err := json.Marshal(struct {
				Name, Type string
				Content    interface{}
			}{
				Name:    notification.GetName(),
				Type:    notification.GetType(),
				Content: content,
			})
			if err != nil {
				log.Errorf("could not marshal content of notification '%s': %s", notification.GetName(), err.Error())
				break
			}

			// Post notification
			req, _ := http.NewRequest("POST", notifier.url, bytes.NewBuffer(jsonContent))
			req.Header.Set("Content-Type", "application/json")

			client := &http.Client{}
			res, err := client.Do(req)
			if err != nil {
				log.Warningf("could not post notification '%s': %s", notification.GetName(), err.Error())
				continue
			}
			res.Body.Close()

			if res.StatusCode != 200 && res.StatusCode != 201 {
				log.Warningf("could not post notification '%s': got status code %d", notification.GetName(), res.StatusCode)
				continue
			}

			// Mark the notification as sent
			database.MarkNotificationAsSent(node)

			log.Infof("sent notification '%s' successfully", notification.GetName())
			break
		}

		if hasLock {
			database.Unlock(node, whoAmI)
		}
	}

	log.Info("HTTP notifier stopped")
}