forked from cerc-io/ipld-eth-server
Update dependencies
- uses newer version of go-ethereum required for go1.11
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2018 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
package influxlib
|
||||
|
||||
//Connection type.
|
||||
const (
|
||||
HTTP = "HTTP"
|
||||
UDP = "UDP"
|
||||
)
|
||||
|
||||
//InfluxConfig is a configuration struct for influxlib.
|
||||
type InfluxConfig struct {
|
||||
Hostname string
|
||||
Port uint16
|
||||
Protocol string
|
||||
Database string
|
||||
RetentionPolicy string
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
/*
|
||||
Package: influxlib
|
||||
Title: Influx DB Library
|
||||
Authors: ssdaily, manojm321, senkrish, kthommandra
|
||||
Email: influxdb-dev@arista.com
|
||||
|
||||
Description: The main purpose of influxlib is to provide users with a simple
|
||||
and easy interface through which to connect to influxdb. It removed a lot of
|
||||
the need to run the same setup and tear down code to connect the the service.
|
||||
|
||||
Example Code:
|
||||
|
||||
connection, err := influxlib.Connect(&influxlib.InfluxConfig {
|
||||
Hostname: conf.Host,
|
||||
Port: conf.Port,
|
||||
Protocol: influxlib.UDP,
|
||||
Database, conf.AlertDB,
|
||||
})
|
||||
|
||||
tags := map[string]string {
|
||||
"tag1": someStruct.Tag["host"],
|
||||
"tag2": someStruct.Tag["tag2"],
|
||||
}
|
||||
|
||||
fields := map[string]interface{} {
|
||||
"field1": someStruct.Somefield,
|
||||
"field2": someStruct.Somefield2,
|
||||
}
|
||||
|
||||
connection.WritePoint("measurement", tags, fields)
|
||||
*/
|
||||
|
||||
package influxlib
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
// Copyright (c) 2018 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
package influxlib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
influxdb "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
// Row is defined as a map where the key (string) is the name of the
|
||||
// column (field name) and the value is left as an interface to
|
||||
// accept any value.
|
||||
type Row map[string]interface{}
|
||||
|
||||
// InfluxDBConnection is an object that the wrapper uses.
|
||||
// Holds a client of the type v2.Client and the configuration
|
||||
type InfluxDBConnection struct {
|
||||
Client influxdb.Client
|
||||
Config *InfluxConfig
|
||||
}
|
||||
|
||||
// Point represents a datapoint to be written.
|
||||
// Measurement:
|
||||
// The measurement to write to
|
||||
// Tags:
|
||||
// A dictionary of tags in the form string=string
|
||||
// Fields:
|
||||
// A dictionary of fields(keys) with their associated values
|
||||
type Point struct {
|
||||
Measurement string
|
||||
Tags map[string]string
|
||||
Fields map[string]interface{}
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
// Connect takes an InfluxConfig and establishes a connection
|
||||
// to InfluxDB. It returns an InfluxDBConnection structure.
|
||||
// InfluxConfig may be nil for a default connection.
|
||||
func Connect(config *InfluxConfig) (*InfluxDBConnection, error) {
|
||||
var con influxdb.Client
|
||||
var err error
|
||||
|
||||
switch config.Protocol {
|
||||
case HTTP:
|
||||
addr := fmt.Sprintf("http://%s:%v", config.Hostname, config.Port)
|
||||
con, err = influxdb.NewHTTPClient(influxdb.HTTPConfig{
|
||||
Addr: addr,
|
||||
Timeout: 1 * time.Second,
|
||||
})
|
||||
case UDP:
|
||||
addr := fmt.Sprintf("%s:%v", config.Hostname, config.Port)
|
||||
con, err = influxdb.NewUDPClient(influxdb.UDPConfig{
|
||||
Addr: addr,
|
||||
})
|
||||
default:
|
||||
return nil, errors.New("Invalid Protocol")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InfluxDBConnection{Client: con, Config: config}, nil
|
||||
}
|
||||
|
||||
// RecordBatchPoints takes in a slice of influxlib.Point and writes them to the
|
||||
// database.
|
||||
func (conn *InfluxDBConnection) RecordBatchPoints(points []Point) error {
|
||||
var err error
|
||||
bp, err := influxdb.NewBatchPoints(influxdb.BatchPointsConfig{
|
||||
Database: conn.Config.Database,
|
||||
Precision: "ns",
|
||||
RetentionPolicy: conn.Config.RetentionPolicy,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var influxPoints []*influxdb.Point
|
||||
|
||||
for _, p := range points {
|
||||
if p.Timestamp.IsZero() {
|
||||
p.Timestamp = time.Now()
|
||||
}
|
||||
|
||||
point, err := influxdb.NewPoint(p.Measurement, p.Tags, p.Fields,
|
||||
p.Timestamp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
influxPoints = append(influxPoints, point)
|
||||
}
|
||||
|
||||
bp.AddPoints(influxPoints)
|
||||
|
||||
if err = conn.Client.Write(bp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WritePoint stores a datapoint to the database.
|
||||
// Measurement:
|
||||
// The measurement to write to
|
||||
// Tags:
|
||||
// A dictionary of tags in the form string=string
|
||||
// Fields:
|
||||
// A dictionary of fields(keys) with their associated values
|
||||
func (conn *InfluxDBConnection) WritePoint(measurement string,
|
||||
tags map[string]string, fields map[string]interface{}) error {
|
||||
return conn.RecordPoint(Point{
|
||||
Measurement: measurement,
|
||||
Tags: tags,
|
||||
Fields: fields,
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
// RecordPoint implements the same as WritePoint but used a point struct
|
||||
// as the argument instead.
|
||||
func (conn *InfluxDBConnection) RecordPoint(p Point) error {
|
||||
return conn.RecordBatchPoints([]Point{p})
|
||||
}
|
||||
|
||||
// Query sends a query to the influxCli and returns a slice of
|
||||
// rows. Rows are of type map[string]interface{}
|
||||
func (conn *InfluxDBConnection) Query(query string) ([]Row, error) {
|
||||
q := influxdb.NewQuery(query, conn.Config.Database, "ns")
|
||||
var rows []Row
|
||||
var index = 0
|
||||
|
||||
response, err := conn.Client.Query(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Error() != nil {
|
||||
return nil, response.Error()
|
||||
}
|
||||
|
||||
// The intent here is to combine the separate client v2
|
||||
// series into a single array. As a result queries that
|
||||
// utilize "group by" will be combined into a single
|
||||
// array. And the tag value will be added to the query.
|
||||
// Similar to what you would expect from a SQL query
|
||||
for _, result := range response.Results {
|
||||
for _, series := range result.Series {
|
||||
columnNames := series.Columns
|
||||
for _, row := range series.Values {
|
||||
rows = append(rows, make(Row))
|
||||
for columnIdx, value := range row {
|
||||
rows[index][columnNames[columnIdx]] = value
|
||||
}
|
||||
for tagKey, tagValue := range series.Tags {
|
||||
rows[index][tagKey] = tagValue
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
// Close closes the connection opened by Connect()
|
||||
func (conn *InfluxDBConnection) Close() {
|
||||
conn.Client.Close()
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Copyright (c) 2018 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
package influxlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testFields(line string, fields map[string]interface{},
|
||||
t *testing.T) {
|
||||
for k, v := range fields {
|
||||
formatString := "%s=%v"
|
||||
|
||||
if _, ok := v.(string); ok {
|
||||
formatString = "%s=%q"
|
||||
}
|
||||
assert.Contains(t, line, fmt.Sprintf(formatString, k, v),
|
||||
fmt.Sprintf(formatString+" expected in %s", k, v, line))
|
||||
}
|
||||
}
|
||||
|
||||
func testTags(line string, tags map[string]string,
|
||||
t *testing.T) {
|
||||
for k, v := range tags {
|
||||
assert.Contains(t, line, fmt.Sprintf("%s=%s", k, v),
|
||||
fmt.Sprintf("%s=%s expected in %s", k, v, line))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicWrite(t *testing.T) {
|
||||
testConn, _ := NewMockConnection()
|
||||
|
||||
measurement := "TestData"
|
||||
tags := map[string]string{
|
||||
"tag1": "Happy",
|
||||
"tag2": "Valentines",
|
||||
"tag3": "Day",
|
||||
}
|
||||
fields := map[string]interface{}{
|
||||
"Data1": 1234,
|
||||
"Data2": "apples",
|
||||
"Data3": 5.34,
|
||||
}
|
||||
|
||||
err := testConn.WritePoint(measurement, tags, fields)
|
||||
assert.NoError(t, err)
|
||||
|
||||
line, err := GetTestBuffer(testConn)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, line, measurement,
|
||||
fmt.Sprintf("%s does not appear in %s", measurement, line))
|
||||
testTags(line, tags, t)
|
||||
testFields(line, fields, t)
|
||||
}
|
||||
|
||||
func TestConnectionToHostFailure(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
var err error
|
||||
|
||||
config := &InfluxConfig{
|
||||
Port: 8086,
|
||||
Protocol: HTTP,
|
||||
Database: "test",
|
||||
}
|
||||
config.Hostname = "this is fake.com"
|
||||
_, err = Connect(config)
|
||||
assert.Error(err)
|
||||
config.Hostname = "\\-Fake.Url.Com"
|
||||
_, err = Connect(config)
|
||||
assert.Error(err)
|
||||
}
|
||||
|
||||
func TestWriteFailure(t *testing.T) {
|
||||
con, _ := NewMockConnection()
|
||||
|
||||
measurement := "TestData"
|
||||
tags := map[string]string{
|
||||
"tag1": "hi",
|
||||
}
|
||||
data := map[string]interface{}{
|
||||
"Data1": "cats",
|
||||
}
|
||||
err := con.WritePoint(measurement, tags, data)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fc, _ := con.Client.(*fakeClient)
|
||||
fc.failAll = true
|
||||
|
||||
err = con.WritePoint(measurement, tags, data)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
query := "SELECT * FROM 'system' LIMIT 50;"
|
||||
|
||||
con, _ := NewMockConnection()
|
||||
|
||||
_, err := con.Query(query)
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAddAndWriteBatchPoints(t *testing.T) {
|
||||
testConn, _ := NewMockConnection()
|
||||
|
||||
measurement := "TestData"
|
||||
points := []Point{
|
||||
Point{
|
||||
Measurement: measurement,
|
||||
Tags: map[string]string{
|
||||
"tag1": "Happy",
|
||||
"tag2": "Valentines",
|
||||
"tag3": "Day",
|
||||
},
|
||||
Fields: map[string]interface{}{
|
||||
"Data1": 1234,
|
||||
"Data2": "apples",
|
||||
"Data3": 5.34,
|
||||
},
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
Point{
|
||||
Measurement: measurement,
|
||||
Tags: map[string]string{
|
||||
"tag1": "Happy",
|
||||
"tag2": "New",
|
||||
"tag3": "Year",
|
||||
},
|
||||
Fields: map[string]interface{}{
|
||||
"Data1": 5678,
|
||||
"Data2": "bananas",
|
||||
"Data3": 3.14,
|
||||
},
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
err := testConn.RecordBatchPoints(points)
|
||||
assert.NoError(t, err)
|
||||
|
||||
line, err := GetTestBuffer(testConn)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Contains(t, line, measurement,
|
||||
fmt.Sprintf("%s does not appear in %s", measurement, line))
|
||||
for _, p := range points {
|
||||
testTags(line, p.Tags, t)
|
||||
testFields(line, p.Fields, t)
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2018 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
package influxlib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
influx "github.com/influxdata/influxdb/client/v2"
|
||||
)
|
||||
|
||||
// This will serve as a fake client object to test off of.
|
||||
// The idea is to provide a way to test the Influx Wrapper
|
||||
// without having it connected to the database.
|
||||
type fakeClient struct {
|
||||
writer bytes.Buffer
|
||||
failAll bool
|
||||
}
|
||||
|
||||
func (w *fakeClient) Ping(timeout time.Duration) (time.Duration,
|
||||
string, error) {
|
||||
return 0, "", nil
|
||||
}
|
||||
|
||||
func (w *fakeClient) Query(q influx.Query) (*influx.Response, error) {
|
||||
if w.failAll {
|
||||
return nil, errors.New("quering points failed")
|
||||
}
|
||||
|
||||
return &influx.Response{Results: nil, Err: ""}, nil
|
||||
}
|
||||
|
||||
func (w *fakeClient) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *fakeClient) Write(bp influx.BatchPoints) error {
|
||||
if w.failAll {
|
||||
return errors.New("writing point failed")
|
||||
}
|
||||
w.writer.Reset()
|
||||
for _, p := range bp.Points() {
|
||||
fmt.Fprintf(&w.writer, p.String()+"\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *fakeClient) qString() string {
|
||||
return w.writer.String()
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
// NewMockConnection returns an influxDBConnection with
|
||||
// a "fake" client for offline testing.
|
||||
func NewMockConnection() (*InfluxDBConnection, error) {
|
||||
client := new(fakeClient)
|
||||
config := &InfluxConfig{
|
||||
Hostname: "localhost",
|
||||
Port: 8086,
|
||||
Protocol: HTTP,
|
||||
Database: "Test",
|
||||
}
|
||||
return &InfluxDBConnection{client, config}, nil
|
||||
}
|
||||
|
||||
// GetTestBuffer returns the string that would normally
|
||||
// be written to influx DB
|
||||
func GetTestBuffer(con *InfluxDBConnection) (string, error) {
|
||||
fc, ok := con.Client.(*fakeClient)
|
||||
if !ok {
|
||||
return "", errors.New("Expected a fake client but recieved a real one")
|
||||
}
|
||||
return fc.qString(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user