Example #1
0
// parseValue returns the integer or floating point value of the given update,
// or nil if it's not a numerical update.
func parseValue(update *openconfig.Update) (value interface{}) {
	decoder := json.NewDecoder(bytes.NewReader(update.Value.Value))
	decoder.UseNumber()
	err := decoder.Decode(&value)
	if err != nil {
		glog.Fatalf("Malformed JSON update %q in %s", update.Value.Value, update)
	}
	num, ok := value.(json.Number)
	if !ok {
		return nil
	}
	// Convert our json.Number to either an int64, uint64, or float64.
	if value, err = num.Int64(); err != nil {
		// num is either a large unsigned integer or a floating point.
		if strings.Contains(err.Error(), "value out of range") { // Sigh.
			value, err = strconv.ParseUint(num.String(), 10, 64)
		} else {
			value, err = num.Float64()
			if err != nil {
				glog.Fatalf("Malformed JSON number %q in %s", num, update)
			}
		}
	}
	return
}
Example #2
0
// Subscribe sends subscriptions, and consumes responses.
// The given publish function is used to publish SubscribeResponses received
// for the given subscriptions, when connected to the given host, with the
// given user/pass pair, or the client-side cert specified in the gRPC opts.
// This function does not normally return so it should probably be run in its
// own goroutine.  When this function returns, the given WaitGroup is marked
// as done.
func (c *Client) Subscribe(wg *sync.WaitGroup, subscriptions []string,
	publish PublishFunc) {
	defer wg.Done()
	stream, err := c.client.Subscribe(c.ctx)
	if err != nil {
		glog.Fatalf("Subscribe failed: %s", err)
	}
	defer stream.CloseSend()

	for _, path := range subscriptions {
		sub := &openconfig.SubscribeRequest{
			Request: &openconfig.SubscribeRequest_Subscribe{
				Subscribe: &openconfig.SubscriptionList{
					Subscription: []*openconfig.Subscription{
						&openconfig.Subscription{
							Path: &openconfig.Path{Element: strings.Split(path, "/")},
						},
					},
				},
			},
		}

		glog.Infof("Sending subscribe request: %s", sub)
		err = stream.Send(sub)
		if err != nil {
			glog.Fatalf("Failed to subscribe: %s", err)
		}
	}

	for {
		resp, err := stream.Recv()
		if err != nil {
			if err != io.EOF {
				glog.Fatalf("Error received from the server: %s", err)
			}
			return
		}
		switch resp := resp.Response.(type) {
		case *openconfig.SubscribeResponse_SyncResponse:
			if !resp.SyncResponse {
				panic("initial sync failed," +
					" check that you're using a client compatible with the server")
			}
		}
		glog.V(3).Info(resp)
		publish(c.device, resp)
	}
}
Example #3
0
func convertUpdate(update *openconfig.Update) interface{} {
	switch update.Value.Type {
	case openconfig.Type_JSON:
		var value interface{}
		err := json.Unmarshal(update.Value.Value, &value)
		if err != nil {
			glog.Fatalf("Malformed JSON update %q in %s", update.Value.Value, update)
		}
		return value
	case openconfig.Type_BYTES:
		return update.Value.Value
	default:
		glog.Fatalf("Unhandled type of value %v in %s", update.Value.Type, update)
		return nil
	}
}
Example #4
0
func bufferToRedis(addr string, notif *openconfig.Notification) {
	path := addr + "/" + joinPath(notif.Prefix)
	data := &redisData{key: path}

	if len(notif.Update) != 0 {
		hmset := make(map[string]string, len(notif.Update))

		// Updates to publish on the pub/sub.
		pub := make(map[string]interface{}, len(notif.Update))
		for _, update := range notif.Update {
			key := joinPath(update.Path)
			value := convertUpdate(update)
			pub[key] = value
			marshaledValue, err := json.Marshal(value)
			if err != nil {
				glog.Fatalf("Failed to JSON marshal update %#v", update)
			}
			hmset[key] = string(marshaledValue)
		}
		data.hmset = hmset
		data.pub = pub
	}

	if len(notif.Delete) != 0 {
		hdel := make([]string, len(notif.Delete))
		for i, del := range notif.Delete {
			hdel[i] = joinPath(del)
		}
		data.hdel = hdel
	}
	pushToRedis(data)
}
Example #5
0
func redisPublish(path, kind string, payload interface{}) {
	js, err := json.Marshal(map[string]interface{}{
		"kind":    kind,
		"payload": payload,
	})
	if err != nil {
		glog.Fatalf("JSON error: %s", err)
	}
	if reply := client.Publish(path, string(js)); reply.Err() != nil {
		glog.Fatal("Redis PUBLISH error: ", reply.Err())
	}
}
Example #6
0
// Get sends a get request and returns the responses
func (c *Client) Get(path string) []*openconfig.Notification {
	req := &openconfig.GetRequest{
		Path: []*openconfig.Path{
			{
				Element: strings.Split(path, "/"),
			},
		},
	}
	response, err := c.client.Get(c.ctx, req)
	if err != nil {
		glog.Fatalf("Get failed: %s", err)
	}
	return response.Notification
}
Example #7
0
func pbsToStream(pbs []*pb.LanzRecord) []byte {
	var r []byte

	for _, p := range pbs {
		b, err := proto.Marshal(p)
		if err != nil {
			glog.Fatalf("Can't marshal pb: %v", err)
		}

		bLen := uint64(len(b))
		s := make([]byte, binary.MaxVarintLen64)
		sLen := binary.PutUvarint(s, bLen)

		r = append(r, s[:sLen]...)
		r = append(r, b...)
	}

	return r
}
Example #8
0
// Run sets up the HTTP server and any handlers
func (s *server) Run() {
	http.HandleFunc("/debug", debugHandler)
	http.HandleFunc("/debug/latency", latencyHandler)

	var listener net.Listener
	var listenErr error
	err := netns.Do(s.vrfName, func() {
		listener, listenErr = net.Listen("tcp", s.serverName)
	})
	if err != nil {
		glog.Fatalf("Failed to go to network namespace for vrf %s: %s", s.vrfName, err)
	}
	if listenErr != nil {
		glog.Fatal("Could not start monitor server:", listenErr)
	}

	err = http.Serve(listener, nil)
	if err != nil {
		glog.Fatal("http serve returned with error:", err)
	}
}
Example #9
0
func pushToOpenTSDB(addr string, conn OpenTSDBConn, config *Config,
	notif *openconfig.Notification) {

	if notif.Timestamp <= 0 {
		glog.Fatalf("Invalid timestamp %d in %s", notif.Timestamp, notif)
	}

	host := addr[:strings.IndexRune(addr, ':')]
	prefix := "/" + strings.Join(notif.Prefix.Element, "/")
	for _, update := range notif.Update {
		if update.Value == nil || update.Value.Type != openconfig.Type_JSON {
			glog.V(9).Infof("Ignoring incompatible update value in %s", update)
			continue
		}

		value := parseValue(update)
		if value == nil {
			glog.V(9).Infof("Ignoring non-numeric value in %s", update)
			continue
		}

		path := prefix + "/" + strings.Join(update.Path.Element, "/")
		metricName, tags := config.Match(path)
		if metricName == "" {
			glog.V(8).Infof("Ignoring unmatched update at %s: %+v", path, update.Value)
			continue
		}
		tags["host"] = host

		conn.Put(&DataPoint{
			Metric:    metricName,
			Timestamp: uint64(notif.Timestamp),
			Value:     value,
			Tags:      tags,
		})
	}
}
Example #10
0
// New creates a new gRPC client and connects it
func New(username, password, addr string, opts []grpc.DialOption) *Client {
	device := addr
	if !strings.ContainsRune(addr, ':') {
		addr += ":" + defaultPort
	}
	conn, err := grpc.Dial(addr, opts...)
	if err != nil {
		glog.Fatalf("Failed to dial: %s", err)
	}
	glog.Infof("Connected to %s", addr)
	client := openconfig.NewOpenConfigClient(conn)

	ctx := context.Background()
	if username != "" {
		ctx = metadata.NewContext(ctx, metadata.Pairs(
			"username", username,
			"password", password))
	}
	return &Client{
		client: client,
		device: device,
		ctx:    ctx,
	}
}
Example #11
0
// ParseFlags registers some additional common flags,
// parses the flags, and returns the resulting gRPC options,
// and other settings to connect to the gRPC interface.
func ParseFlags() (username string, password string, subscriptions, addrs []string,
	opts []grpc.DialOption) {

	var (
		addrsFlag = flag.String("addrs", "localhost:6042",
			"Comma-separated list of addresses of OpenConfig gRPC servers")

		caFileFlag = flag.String("cafile", "",
			"Path to server TLS certificate file")

		certFileFlag = flag.String("certfile", "",
			"Path to client TLS certificate file")

		keyFileFlag = flag.String("keyfile", "",
			"Path to client TLS private key file")

		passwordFlag = flag.String("password", "",
			"Password to authenticate with")

		subscribeFlag = flag.String("subscribe", "",
			"Comma-separated list of paths to subscribe to upon connecting to the server")

		usernameFlag = flag.String("username", "",
			"Username to authenticate with")

		tlsFlag = flag.Bool("tls", false,
			"Enable TLS")
	)

	flag.Parse()
	if *tlsFlag || *caFileFlag != "" || *certFileFlag != "" {
		config := &tls.Config{}
		if *caFileFlag != "" {
			b, err := ioutil.ReadFile(*caFileFlag)
			if err != nil {
				glog.Fatal(err)
			}
			cp := x509.NewCertPool()
			if !cp.AppendCertsFromPEM(b) {
				glog.Fatalf("credentials: failed to append certificates")
			}
			config.RootCAs = cp
		} else {
			config.InsecureSkipVerify = true
		}
		if *certFileFlag != "" {
			if *keyFileFlag == "" {
				glog.Fatalf("Please provide both -certfile and -keyfile")
			}
			cert, err := tls.LoadX509KeyPair(*certFileFlag, *keyFileFlag)
			if err != nil {
				glog.Fatal(err)
			}
			config.Certificates = []tls.Certificate{cert}
		}
		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(config)))
	} else {
		opts = append(opts, grpc.WithInsecure())
	}
	addrs = strings.Split(*addrsFlag, ",")
	subscriptions = strings.Split(*subscribeFlag, ",")
	return *usernameFlag, *passwordFlag, subscriptions, addrs, opts
}