From c41dfcc69317bc29204d114f17d738fb527c4b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Jochum?= Date: Wed, 30 Sep 2020 03:02:13 +0200 Subject: [PATCH] Add /v1/table/:name and /v1/table/:name/columns --- go.mod | 21 +----------- go.sum | 5 +++ lql/server.go | 1 + lql/v1.go | 12 ++++++- lql/v1ping.go | 2 +- lql/v1table.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 lql/v1table.go diff --git a/go.mod b/go.mod index 1a485c8..a8d47a4 100644 --- a/go.mod +++ b/go.mod @@ -4,31 +4,12 @@ go 1.15 require ( github.com/abbot/go-http-auth v0.4.0 - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 - github.com/go-openapi/spec v0.19.9 // indirect - github.com/go-openapi/swag v0.19.9 // indirect github.com/loopfz/gadgeto v0.10.1 - github.com/mailru/easyjson v0.7.6 // indirect - github.com/micro/micro/v2 v2.9.3 - github.com/micro/micro/v3 v3.0.0-beta.5 - github.com/mitchellh/go-homedir v1.1.0 - github.com/rgzr/sshtun v0.0.2 - github.com/sirupsen/logrus v1.6.0 + github.com/sirupsen/logrus v1.7.0 github.com/spf13/cobra v1.0.0 - github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.6.3 - github.com/stretchr/testify v1.6.1 - github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 - github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.7 github.com/toorop/gin-logrus v0.0.0-20200831135515-d2ee50d38dae - github.com/urfave/cli/v2 v2.2.0 // indirect github.com/wI2L/fizz v0.13.4 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a - golang.org/x/net v0.0.0-20200927032502-5d4f70055728 // indirect - golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c // indirect - golang.org/x/tools v0.0.0-20200928201943-a0ef9b62deab // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index f020a11..aaa1586 100644 --- a/go.sum +++ b/go.sum @@ -245,6 +245,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -538,6 +539,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -775,11 +778,13 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/lql/server.go b/lql/server.go index 0626c68..06ca1cf 100644 --- a/lql/server.go +++ b/lql/server.go @@ -20,6 +20,7 @@ type Server struct { } func NewServer(client *Client, logger *log.Logger, htpasswdPath string) (*Server, error) { + gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.Use(cors.Default()) engine.Use(ginlogrus.Logger(logger), gin.Recovery(), clientInjectorMiddleware(client)) diff --git a/lql/v1.go b/lql/v1.go index 685d0e4..b78d062 100644 --- a/lql/v1.go +++ b/lql/v1.go @@ -12,7 +12,7 @@ func v1Routes(grp *fizz.RouterGroup) { }, tonic.Handler(v1RawPost, 200)) grp.GET("/ping", []fizz.OperationOption{ - fizz.Summary("GET ping"), + fizz.Summary("GET Play ping-ping with the API"), fizz.Response("400", "Bad request", nil, nil), }, tonic.Handler(v1Ping, 200)) @@ -20,4 +20,14 @@ func v1Routes(grp *fizz.RouterGroup) { fizz.Summary("GET tactical overview data"), fizz.Response("400", "Bad request", nil, nil), }, tonic.Handler(v1StatsGetTacticalOverview, 200)) + + grp.GET("/table/:name", []fizz.OperationOption{ + fizz.Summary("GET a table from LQL"), + fizz.Response("400", "Bad request", nil, nil), + }, tonic.Handler(v1TableGet, 200)) + + grp.GET("/table/:name/columns", []fizz.OperationOption{ + fizz.Summary("GET a table columns from LQL"), + fizz.Response("400", "Bad request", nil, nil), + }, tonic.Handler(v1TableGetColumns, 200)) } diff --git a/lql/v1ping.go b/lql/v1ping.go index 63aa3f9..f20e4b3 100644 --- a/lql/v1ping.go +++ b/lql/v1ping.go @@ -16,5 +16,5 @@ Columns: name` return nil, err } - return gin.H{"message": "ok"}, nil + return gin.H{"message": "pong"}, nil } diff --git a/lql/v1table.go b/lql/v1table.go new file mode 100644 index 0000000..2c3c396 --- /dev/null +++ b/lql/v1table.go @@ -0,0 +1,86 @@ +package lql + +import ( + "fmt" + "strings" + + "github.com/gin-gonic/gin" +) + +var v1TableColumns = map[string][]string{} + +func init() { + v1TableColumns = make(map[string][]string, 1) // Increment this when you add tables + v1TableColumns["hosts"] = []string{ + "name", + "display_name", + "address", + "alias", + "tags", + "labels", + "groups", + "latency", + "parents", + } +} + +type v1TableGetParams struct { + Table string `path:"name"` + Columns *string `query:"columns" description:"Columns to return" validate:"omitempty"` + Limit *float64 `query:"limit" description:"Limit number of results" validate:"omitempty,min=0"` +} + +func v1TableGet(c *gin.Context, params *v1TableGetParams) ([]gin.H, error) { + client, err := GinGetLqlClient(c) + if err != nil { + return nil, err + } + user := c.GetString("user") + + columns := "" + if params.Columns != nil { + columns = strings.Join(strings.Split(*params.Columns, ","), " ") + } else if defaultCols, ok := v1TableColumns[params.Table]; ok { + columns = strings.Join(defaultCols, " ") + } else { + columns = "name" + } + + limit := 0 + if params.Limit != nil { + limit = int(*params.Limit) + } + + lines := []string{fmt.Sprintf("GET %s", params.Table), fmt.Sprintf("Columns: %s", columns)} + resp, err := client.Request(c, strings.Join(lines, "\n"), user, limit) + if err != nil { + return nil, err + } + + return resp, nil +} + +type v1TableGetColumnsParams struct { + Table string `path:"name"` +} + +func v1TableGetColumns(c *gin.Context, params *v1TableGetColumnsParams) ([]string, error) { + client, err := GinGetLqlClient(c) + if err != nil { + return nil, err + } + user := c.GetString("user") + + msg := fmt.Sprintf("GET columns\nColumns: name\nFilter: table = %s", params.Table) + resp, err := client.Request(c, msg, user, 0) + if err != nil { + return nil, err + } + + result := make([]string, len(resp)) + for i, item := range resp { + result[i] = item["name"].(string) + } + + return result, nil +}