Пример #1
0
// removeOldKeys removes keys older than specified age
func removeOldKeys() error {
	datas, err := backends.List()
	if err != nil {
		return err
	}

	now := time.Now()

	lumber.Debug("Garbage Collector - Finding files...")
	for _, data := range datas {

		// clean-after defaults to Now() to ensure no files are deleted in case
		// cobra decides to change how 'Command.Flag().Changed' works. It does this
		// because no files, written by hoarder, will have a modified time before the
		// Unix epoch began
		if data.ModTime.Unix() < (now.Unix() - int64(viper.GetInt("clean-after"))) {
			lumber.Debug("Cleaning key: ", data.Name)
			if err := backends.Remove(data.Name); err != nil {
				return fmt.Errorf("Cleaning of '%s' failed - %v", data.Name, err.Error())
			}
		}
	}

	return nil
}
Пример #2
0
// writeBody
func writeBody(v interface{}, rw http.ResponseWriter, status int, req *http.Request) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// print the error only if there is one
	var msg map[string]string
	json.Unmarshal(b, &msg)

	var errMsg string
	if msg["error"] != "" {
		errMsg = msg["error"]
	}

	lumber.Debug(`[PULSE :: ACCESS] %v - [%v] %v %v %v - "User-Agent: %s" %s`,
		req.RemoteAddr, req.Proto, req.Method, req.RequestURI,
		status, req.Header.Get("User-Agent"), errMsg)

	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(status)
	rw.Write(append(b, byte('\n')))

	return nil
}
Пример #3
0
// registerRoutes
func registerRoutes() (*pat.Router, error) {
	lumber.Debug("[PULSE :: API] Registering routes...")

	//
	router := pat.New()

	//
	router.Get("/ping", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte("pong"))
	})

	router.Options("/", cors)

	router.Get("/keys", keysRequest)
	router.Get("/tags", tagsRequest)

	router.Get("/latest/{stat}", doCors(latestStat))
	router.Get("/hourly/{stat}", doCors(hourlyStat))
	router.Get("/daily/{stat}", doCors(dailyStat))
	router.Get("/daily_peaks/{stat}", doCors(dailyStat))

	// only expose alert routes if alerting configured
	if viper.GetString("kapacitor-address") != "" {
		// todo: maybe get and list tasks from kapacitor
		router.Post("/alerts", doCors(setAlert))
		router.Put("/alerts", doCors(setAlert))
		router.Delete("/alerts/{id}", doCors(deleteAlert))
	}

	return router, nil
}
Пример #4
0
// connect
func (p *Proxy) connect() {

	lumber.Debug("Client connecting...")

	// this gofunc handles matching messages to subscriptions for the proxy
	go p.handleMessages()
}
Пример #5
0
func startHoarder(ccmd *cobra.Command, args []string) error {
	// convert the log level
	logLvl := lumber.LvlInt(viper.GetString("log-level"))

	// configure the logger
	lumber.Prefix("[hoader]")
	lumber.Level(logLvl)

	// enable/start garbage collection if age config was changed
	if ccmd.Flag("clean-after").Changed {
		lumber.Debug("Starting garbage collector (data older than %vs)...\n", ccmd.Flag("clean-after").Value)

		// start garbage collector
		go collector.Start()
	}

	// set, and initialize, the backend driver
	if err := backends.Initialize(); err != nil {
		lumber.Error("Failed to initialize backend - %v", err)
		return err
	}

	// start the API
	if err := api.Start(); err != nil {
		lumber.Fatal("Failed to start API: ", err.Error())
		return err
	}

	return nil
}
Пример #6
0
func (t *Server) handlePrefix(id string, msg PrefixMsg) {
	log.Trace("Handling prefix message")
	if _, ok := t.prefixes[id]; !ok {
		t.prefixes[id] = make(PrefixMap)
	}
	if err := t.prefixes[id].RegisterPrefix(msg.Prefix, msg.URI); err != nil {
		log.Error("Error registering prefix: %s", err)
	}
	log.Debug("Client %s registered prefix '%s' for URI: %s", id, msg.Prefix, msg.URI)
}
Пример #7
0
func (t *Server) handleUnsubscribe(id string, msg UnsubscribeMsg) {
	log.Trace("Handling unsubscribe message")
	t.subLock.Lock()
	topic := CheckCurie(t.prefixes[id], msg.TopicURI)
	if lm, ok := t.subscriptions[topic]; ok {
		lm.Remove(id)
	}
	t.subLock.Unlock()
	log.Debug("Client %s unsubscribed from topic: %s", id, topic)
}
Пример #8
0
// runLoop handles communication from the server
func (relay *Relay) runLoop(reader *bufio.Reader) {
	for {
		// when implementing relay, set `lumber.Level(lumber.LvlInt("TRACE"))` in client to view logs
		line, err := reader.ReadString('\n')
		if err != nil {
			lumber.Error("[PULSE :: RELAY] Disconnected from host %v!", relay.hostAddr)
			// retry indefinitely
			for {
				if reader, err = relay.establishConnection(); err == nil {
					lumber.Info("[PULSE :: RELAY] Reconnected to host %v!", relay.hostAddr)
					break
				}
				lumber.Debug("[PULSE :: RELAY] Reconnecting to host %v...  Fail!", relay.hostAddr)
				<-time.After(5 * time.Second)
			}
			// we won't have anything in 'line' so continue
			continue
		}

		line = strings.TrimSuffix(line, "\n")
		split := strings.SplitN(line, " ", 2)

		cmd := split[0]
		switch cmd {
		case "ok":
			lumber.Trace("[PULSE :: RELAY] OK: %v", split)
			// just an ack
		case "get":
			lumber.Trace("[PULSE :: RELAY] GET: %v", split)
			if len(split) != 2 {
				continue
			}
			stats := strings.Split(split[1], ",")
			results := make([]string, 0)
			for _, stat := range stats {
				tagCollector, ok := relay.collectors[stat]
				if !ok {
					continue
				}
				for name, value := range tagCollector.collector.Collect() {
					formatted := strconv.FormatFloat(value, 'f', 4, 64)
					if name == "" {
						name = stat
					}
					results = append(results, fmt.Sprintf("%s-%s:%s", stat, name, formatted))
				}
			}
			response := fmt.Sprintf("got %s\n", strings.Join(results, ","))
			relay.conn.Write([]byte(response))
		default:
			lumber.Trace("[PULSE :: RELAY] BAD: %v", split)
			relay.conn.Write([]byte("unknown command\n"))
		}
	}
}
Пример #9
0
func (t *Server) handleSubscribe(id string, msg SubscribeMsg) {
	log.Trace("Handling subscribe message")
	t.subLock.Lock()
	topic := CheckCurie(t.prefixes[id], msg.TopicURI)
	if _, ok := t.subscriptions[topic]; !ok {
		t.subscriptions[topic] = make(map[string]bool)
	}
	t.subscriptions[topic].Add(id)
	t.subLock.Unlock()
	log.Debug("Client %s subscribed to topic: %s", id, topic)
}
Пример #10
0
func (c *Client) ReceiveWelcome() error {
	log.Trace("Receive welcome")
	var rec string
	err := websocket.Message.Receive(c.ws, &rec)
	if err != nil {
		return fmt.Errorf("Error receiving welcome message: %s", err)
	}
	if typ := ParseType(rec); typ != WELCOME {
		return fmt.Errorf("First message received was not welcome")
	}
	var msg WelcomeMsg
	err = json.Unmarshal([]byte(rec), &msg)
	if err != nil {
		return fmt.Errorf("Error unmarshalling welcome message: %s", err)
	}
	c.SessionId = msg.SessionId
	log.Debug("Session id: %s", c.SessionId)
	c.ProtocolVersion = msg.ProtocolVersion
	log.Debug("Protocol version: %d", c.ProtocolVersion)
	c.ServerIdent = msg.ServerIdent
	log.Debug("Server ident: %s", c.ServerIdent)
	return nil
}
Пример #11
0
// handleRequest is a wrapper for the actual route handler, simply to provide some
// debug output
func handleRequest(fn http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, req *http.Request) {

		//
		fn(rw, req)

		// must be after req returns
		getStatus := func(trw http.ResponseWriter) string {
			r, _ := regexp.Compile("status:([0-9]*)")
			return r.FindStringSubmatch(fmt.Sprintf("%+v", trw))[1]
		}

		getWrote := func(trw http.ResponseWriter) string {
			r, _ := regexp.Compile("written:([0-9]*)")
			return r.FindStringSubmatch(fmt.Sprintf("%+v", trw))[1]
		}

		lumber.Debug(`%v - [%v] %v %v %v(%s) - "User-Agent: %s"`,
			req.RemoteAddr, req.Proto, req.Method, req.RequestURI,
			getStatus(rw), getWrote(rw), // %v(%s)
			req.Header.Get("User-Agent"))
	}
}
Пример #12
0
// routes registers all api routes with the router
func routes() *pat.Router {
	lumber.Debug("Registering routes...\n")

	// create new router
	router := pat.New()

	// define ping
	router.Get("/ping", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte("pong\n"))
	})

	// blobs
	router.Add("HEAD", "/blobs/{blob}", handleRequest(getHead))
	router.Get("/blobs/{blob}", handleRequest(get))
	router.Post("/blobs/{blob}", handleRequest(create))
	router.Put("/blobs/{blob}", handleRequest(update))
	router.Delete("/blobs/{blob}", handleRequest(delete))
	router.Add("HEAD", "/blobs", handleRequest(list))
	router.Get("/blobs", handleRequest(list))

	//
	return router
}
Пример #13
0
func (t *Server) HandleWebsocket(conn *websocket.Conn) {
	defer conn.Close()

	log.Debug("Received websocket connection")

	tid, err := uuid.NewV4()
	if err != nil {
		log.Error("Could not create unique id, refusing client connection")
		return
	}
	id := tid.String()

	arr, err := CreateWelcome(id, TURNPIKE_SERVER_IDENT)
	if err != nil {
		log.Error("Error encoding welcome message")
		return
	}
	log.Debug("Sending welcome message: %s", arr)
	err = websocket.Message.Send(conn, string(arr))
	if err != nil {
		log.Error("Error sending welcome message, aborting connection: %s", err)
		return
	}

	c := make(chan string, serverBacklog)
	t.clients[id] = c

	go func() {
		for msg := range c {
			log.Trace("Sending message: %s", msg)
			err := websocket.Message.Send(conn, string(msg))
			if err != nil {
				log.Error("Error sending message: %s", err)
			}
		}
	}()

	for {
		var rec string
		err := websocket.Message.Receive(conn, &rec)
		if err != nil {
			if err != io.EOF {
				log.Error("Error receiving message, aborting connection: %s", err)
			}
			break
		}
		log.Trace("Message received: %s", rec)

		data := []byte(rec)

		switch typ := ParseType(rec); typ {
		case PREFIX:
			var msg PrefixMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling prefix message: %s", err)
			}
			t.handlePrefix(id, msg)
		case CALL:
			var msg CallMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling call message: %s", err)
			}
			t.handleCall(id, msg)
		case SUBSCRIBE:
			var msg SubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling subscribe message: %s", err)
			}
			t.handleSubscribe(id, msg)
		case UNSUBSCRIBE:
			var msg UnsubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling unsubscribe message: %s", err)
			}
			t.handleUnsubscribe(id, msg)
		case PUBLISH:
			var msg PublishMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling publish message: %s", err)
			}
			t.handlePublish(id, msg)
		case WELCOME, CALLRESULT, CALLERROR, EVENT:
			log.Error("Server -> client message received, ignored: %s", TypeString(typ))
		default:
			log.Error("Invalid message format, message dropped: %s", data)
		}
	}

	delete(t.clients, id)
	close(c)
}
Пример #14
0
func (t *Server) handlePublish(id string, msg PublishMsg) {
	log.Trace("Handling publish message")
	topic := CheckCurie(t.prefixes[id], msg.TopicURI)
	lm, ok := t.subscriptions[topic]
	if !ok {
		return
	}

	out, err := CreateEvent(topic, msg.Event)
	if err != nil {
		log.Error("Error creating event message: %s", err)
		return
	}

	var sendTo []string
	if len(msg.ExcludeList) > 0 || len(msg.EligibleList) > 0 {
		// this is super ugly, but I couldn't think of a better way...
		for tid := range lm {
			include := true
			for _, _tid := range msg.ExcludeList {
				if tid == _tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}

		for _, tid := range msg.EligibleList {
			include := true
			for _, _tid := range sendTo {
				if _tid == tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}
	} else {
		for tid := range lm {
			if tid == id && msg.ExcludeMe {
				continue
			}
			sendTo = append(sendTo, tid)
		}
	}

	log.Debug("Sending event messages")
	for _, tid := range sendTo {
		// we're not locking anything, so we need
		// to make sure the client didn't disconnecct in the
		// last few nanoseconds...
		if client, ok := t.clients[tid]; ok {
			client <- string(out)
		}
	}
}
Пример #15
0
// handleConnection takes an incoming connection from a mist client (or other client)
// and sets up a new subscription for that connection, and a 'publish Handler'
// that is used to publish messages to the data channel of the subscription
func handleConnection(conn net.Conn, errChan chan<- error) {

	// close the connection when we're done here
	defer conn.Close()

	// create a new client for each connection
	proxy := mist.NewProxy()
	defer proxy.Close()

	// add basic TCP command handlers for this connection
	handlers = GenerateHandlers()

	encoder := json.NewEncoder(conn)
	decoder := json.NewDecoder(conn)

	// publish mist messages (pong, etc.. and messages if subscriber attatched)
	// to connected tcp client (non-blocking)
	go func() {
		for msg := range proxy.Pipe {
			lumber.Trace("Got message - %#v", msg)
			// if the message fails to encode its probably a syntax issue and needs to
			// break the loop here because it will never be able to encode it; this will
			// disconnect the client.
			if err := encoder.Encode(msg); err != nil {
				errChan <- fmt.Errorf("Failed to pubilsh proxy.Pipe contents to TCP clients - %v", err)
				break
			}
		}
	}()

	// connection loop (blocking); continually read off the connection. Once something
	// is read, check to see if it's a message the client understands to be one of
	// its commands. If so attempt to execute the command.
	for {
		msg := mist.Message{}

		// if the message fails to decode its probably a syntax issue and needs to
		// break the loop here because it will never be able to decode it; this will
		// disconnect the client.
		if err := decoder.Decode(&msg); err != nil {
			switch err {
			case io.EOF:
				lumber.Debug("Client disconnected")
			case io.ErrUnexpectedEOF:
				lumber.Debug("Client disconnected unexpedtedly")
			default:
				errChan <- fmt.Errorf("Failed to decode message from TCP connection - %v", err)
			}
			return
		}

		// if an authenticator was passed, check for a token on connect to see if
		// auth commands are allowed
		if auth.DefaultAuth != nil && !proxy.Authenticated {

			// if the next input does not match the token then
			if msg.Data != authtoken {
				lumber.Debug("Client data doesn't match configured auth token")
				// break // allow connection w/o admin commands
				return // disconnect client
			}

			// todo: is this still used?
			// add auth commands ("admin" mode)
			for k, v := range auth.GenerateHandlers() {
				handlers[k] = v
			}

			// establish that the connection has already authenticated
			proxy.Authenticated = true
		}

		// look for the command
		handler, found := handlers[msg.Command]

		// if the command isn't found, return an error and wait for the next command
		if !found {
			lumber.Trace("Command '%v' not found", msg.Command)
			encoder.Encode(&mist.Message{Command: msg.Command, Tags: msg.Tags, Data: msg.Data, Error: "Unknown Command"})
			continue
		}

		// attempt to run the command; if the command fails return the error and wait
		// for the next command
		lumber.Trace("TCP Running '%v'...", msg.Command)
		if err := handler(proxy, msg); err != nil {
			lumber.Debug("TCP Failed to run '%v' - %v", msg.Command, err)
			encoder.Encode(&mist.Message{Command: msg.Command, Error: err.Error()})
			continue
		}
	}
}
Пример #16
0
// connect dials the remote mist server and handles any incoming responses back
// from mist
func (c *TCP) connect() error {

	// attempt to connect to the server
	conn, err := net.Dial("tcp", c.host)
	if err != nil {
		return fmt.Errorf("Failed to dial '%v' - %v", c.host, err)
	}

	// set the connection for the client
	c.conn = conn

	// create a new json encoder for the clients connection
	c.encoder = json.NewEncoder(c.conn)

	// if the client was created with a token, authentication is needed
	if c.token != "" {
		err = c.encoder.Encode(&mist.Message{Command: "auth", Data: c.token})
		if err != nil {
			return fmt.Errorf("Failed to send auth - %v", err)
		}
	}

	// ensure we are authorized/still connected (unauthorized clients get disconnected)
	c.Ping()
	decoder := json.NewDecoder(conn)
	msg := mist.Message{}
	if err := decoder.Decode(&msg); err != nil {
		conn.Close()
		close(c.messages)
		return fmt.Errorf("Ping failed, possibly bad token, or can't read from mist")
	}

	// connection loop (blocking); continually read off the connection. Once something
	// is read, check to see if it's a message the client understands to be one of
	// its commands. If so attempt to execute the command.
	go func() {

		for {
			msg := mist.Message{}

			// decode an array value (Message)
			if err := decoder.Decode(&msg); err != nil {
				switch err {
				case io.EOF:
					lumber.Debug("[mist client] Mist terminated connection")
				case io.ErrUnexpectedEOF:
					lumber.Debug("[mist client] Mist terminated connection unexpedtedly")
				default:
					lumber.Error("[mist client] Failed to get message from mist - %s", err.Error())
				}
				conn.Close()
				close(c.messages)
				return
			}
			c.messages <- msg // read from this using the .Messages() function
			lumber.Trace("[mist client] Received message - %#v", msg)
		}
	}()

	return nil
}