Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added REST API for retrieving JSON schema for VPP-Agent configuration #1784

Merged
merged 11 commits into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,9 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


Licenses for 3rd party libraries included in code:

1. library protoc-gen-jsonschema (https://github.com/chrusty/protoc-gen-jsonschema) -
License: Apache License Version 2.0, January 2004 (full license included in plugins/restapi/jsonschema/LICENSE)
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ If you are interested in contributing, please see the [contribution guidelines][

[![GitHub license](https://img.shields.io/badge/license-Apache%20license%202.0-blue.svg)](https://github.com/ligato/vpp-agent/blob/master/LICENSE)

## Modified 3rd party tools included

- [protoc-gen-jsonschema][tool-included-jsonchema] ([code location in this repository][local-place-for-jsonchema])

[agentctl]: cmd/agentctl
[cn-infra]: https://github.com/ligato/cn-infra
[contiv-vpp]: https://github.com/contiv/vpp
Expand All @@ -131,3 +135,5 @@ If you are interested in contributing, please see the [contribution guidelines][
[vpp]: https://fd.io/vppproject/vpptech/
[vpp-agent]: https://hub.docker.com/r/ligato/vpp-agent
[vpp-agent-arm64]: https://hub.docker.com/r/ligato/vpp-agent-arm64
[tool-included-jsonchema]: https://github.com/chrusty/protoc-gen-jsonschema/tree/de75f1b59c4e0f5d5edf7be2a18d1c8e4d81b17a
[local-place-for-jsonchema]: plugins/restapi/jsonschema
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.13
require (
git.fd.io/govpp.git v0.3.6-0.20200907135408-e517439567ad
github.com/Shopify/sarama v1.20.1 // indirect
github.com/alecthomas/jsonschema v0.0.0-20200217214135-7152f22193c9
github.com/alicebob/miniredis v2.5.0+incompatible // indirect
github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2
github.com/coreos/bbolt v1.3.3 // indirect
Expand All @@ -26,6 +27,7 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/grpc-ecosystem/grpc-gateway v1.11.3 // indirect
github.com/hashicorp/go-uuid v1.0.1 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0
github.com/jhump/protoreflect v1.7.0
github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936
Expand All @@ -44,6 +46,9 @@ require (
github.com/unrolled/render v0.0.0-20180914162206-b9786414de4d
github.com/vishvananda/netlink v0.0.0-20180910184128-56b1bd27a9a3
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.1.0
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036 // indirect
go.ligato.io/cn-infra/v2 v2.5.0-alpha.0.20200313154441-b0d4c1b11c73
go.uber.org/multierr v1.2.0 // indirect
Expand Down
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ github.com/Shopify/sarama v1.20.1/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Songmu/prompter v0.0.0-20150725163906-b5721e8d5566/go.mod h1:fNhSFBGC+sg+dZ7AqDHgq+xYiom23TeTESzUbO7PIrE=
github.com/alecthomas/jsonschema v0.0.0-20200217214135-7152f22193c9 h1:h+KAZEUnNceFhqyH46BgwH4lk8m6pdR/3x3h7IPn7VA=
github.com/alecthomas/jsonschema v0.0.0-20200217214135-7152f22193c9/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down Expand Up @@ -51,6 +53,8 @@ github.com/bsm/sarama-cluster v2.1.15+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJ
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chrusty/protoc-gen-jsonschema v0.0.0-20201201182816-de75f1b59c4e h1:VEDA+FrTIUnlSpMlo2i1e0L1hP45vek2ED+blYdOrxg=
github.com/chrusty/protoc-gen-jsonschema v0.0.0-20201201182816-de75f1b59c4e/go.mod h1:qYuJI3Nz/kjHcigPikCSSeh+pRGcCiT1U6qzWGEmaJ4=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
Expand Down Expand Up @@ -266,6 +270,8 @@ github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 h1:IIVxLyDUYErC950b8k
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6/go.mod h1:JslaLRrzGsOKJgFEPBP65Whn+rdwDQSk0I0MCRFe2Zw=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
Expand All @@ -281,6 +287,7 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
Expand Down Expand Up @@ -447,6 +454,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8=
Expand All @@ -464,6 +472,14 @@ github.com/vishvananda/netlink v0.0.0-20180910184128-56b1bd27a9a3/go.mod h1:+SR5
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/willfaught/gockle v0.0.0-20160623235217-4f254e1e0f0a/go.mod h1:NLcF+3nDpXVIZatjn5Z97gKzFFVU7TzgbAcs8G7/Jrs=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
Expand Down Expand Up @@ -560,6 +576,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
124 changes: 124 additions & 0 deletions plugins/restapi/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,33 @@
package restapi

import (
"bytes"
"context"
"fmt"
"net/http"
"runtime"
"strings"

"github.com/go-errors/errors"
"github.com/golang/protobuf/proto"
protoc_plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
"github.com/unrolled/render"

"go.ligato.io/cn-infra/v2/logging/logrus"
"go.ligato.io/vpp-agent/v3/client"
"go.ligato.io/vpp-agent/v3/cmd/agentctl/api/types"
"go.ligato.io/vpp-agent/v3/pkg/version"
"go.ligato.io/vpp-agent/v3/plugins/configurator"
"go.ligato.io/vpp-agent/v3/plugins/restapi/jsonschema/converter"
"go.ligato.io/vpp-agent/v3/plugins/restapi/resturl"
interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)

const internalErrorLogPrefix = "500 Internal server error: "

var (
// ErrHandlerUnavailable represents error returned when particular
// handler is not available
Expand All @@ -40,6 +52,7 @@ var (

func (p *Plugin) registerInfoHandlers() {
p.HTTPHandlers.RegisterHTTPHandler(resturl.Version, p.versionHandler, GET)
p.HTTPHandlers.RegisterHTTPHandler(resturl.JSONSchema, p.jsonSchemaHandler, GET)
}

// Registers ABF REST handler
Expand Down Expand Up @@ -315,6 +328,117 @@ func (p *Plugin) registerHTTPHandler(key, method string, f func() (interface{},
p.HTTPHandlers.RegisterHTTPHandler(key, handlerFunc, method)
}

// jsonSchemaHandler returns JSON schema of VPP-Agent configuration.
func (p *Plugin) jsonSchemaHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
// create FileDescriptorProto for dynamic Config holding all VPP-Agent configuration
knownModels, err := client.LocalClient.KnownModels("config") // locally registered models
if err != nil {
errMsg := fmt.Sprintf("can't get registered models: %v\n", err)
p.Log.Error(internalErrorLogPrefix + errMsg)
p.logError(formatter.JSON(w, http.StatusInternalServerError, errMsg))
return
}
config, err := client.NewDynamicConfig(knownModels)
if err != nil {
errMsg := fmt.Sprintf("can't create dynamic config due to: %v\n", err)
p.Log.Error(internalErrorLogPrefix + errMsg)
p.logError(formatter.JSON(w, http.StatusInternalServerError, errMsg))
return
}
dynConfigFileDescProto := protodesc.ToFileDescriptorProto(config.ProtoReflect().Descriptor().ParentFile())

// create list of all FileDescriptorProtos (imports should be before converted proto file -> dynConfig is last)
fileDescriptorProtos := allFileDescriptorProtos(knownModels)
fileDescriptorProtos = append(fileDescriptorProtos, dynConfigFileDescProto)

// creating input for protoc's plugin (code extracted in plugins/restapi/jsonschema) that can convert
// FileDescriptorProtos to JSONSchema
params := "messages=[Dynamic_config]" + // targeting only the main config message (proto file has also other messages)
",disallow_additional_properties" + // additional unknown json fields makes configuration applying fail
",proto_and_json_fieldnames" // allow also proto names for fields
cgReq := &protoc_plugin.CodeGeneratorRequest{
ProtoFile: fileDescriptorProtos,
FileToGenerate: []string{dynConfigFileDescProto.GetName()},
Parameter: &params,
CompilerVersion: nil, // compiler version is not need in this protoc plugin
}
cgReqMarshalled, err := proto.Marshal(cgReq)
if err != nil {
errMsg := fmt.Sprintf("can't proto marshal CodeGeneratorRequest: %v\n", err)
p.Log.Error(internalErrorLogPrefix + errMsg)
p.logError(formatter.JSON(w, http.StatusInternalServerError, errMsg))
return
}

// use JSON schema converter and handle error cases
p.Log.Debug("Processing code generator request")
protoConverter := converter.New(logrus.DefaultLogger().StandardLogger())
res, err := protoConverter.ConvertFrom(bytes.NewReader(cgReqMarshalled))
if err != nil {
if res == nil {
errMsg := fmt.Sprintf("failed to read registered model configuration input: %v\n", err)
p.Log.Error(internalErrorLogPrefix + errMsg)
p.logError(formatter.JSON(w, http.StatusInternalServerError, errMsg))
return
}
errMsg := fmt.Sprintf("failed generate JSON schema: %v (%v)\n", res.Error, err)
p.Log.Error(internalErrorLogPrefix + errMsg)
p.logError(formatter.JSON(w, http.StatusInternalServerError, errMsg))
return
}

// extract json schema
// (protoc_plugin.CodeGeneratorResponse could have cut the file content into multiple pieces
// for performance optimization (due to godoc), but we know that all pieces are only one file
// due to requesting one file -> join all content together)
var sb strings.Builder
for _, file := range res.File {
sb.WriteString(file.GetContent())
}

// writing response
// (jsonschema is in raw form (string) and non of the available format renders supports raw data output
// with customizable content type setting in header -> custom handling)
w.Header().Set(render.ContentType, render.ContentJSON+"; charset=UTF-8")
w.Write([]byte(sb.String())) // will also call WriteHeader(http.StatusOK) automatically
}
}

// allImports retrieves all imports from given FileDescriptor including transitive imports (import
// duplication can occur)
func allImports(fileDesc protoreflect.FileDescriptor) []protoreflect.FileDescriptor {
result := make([]protoreflect.FileDescriptor, 0)
imports := fileDesc.Imports()
for i := 0; i < imports.Len(); i++ {
currentImport := imports.Get(i).FileDescriptor
result = append(result, currentImport)
result = append(result, allImports(currentImport)...)
}
return result
}

// allFileDescriptorProtos retrieves all FileDescriptorProtos related to given models (including
// all imported proto files)
func allFileDescriptorProtos(knownModels []*client.ModelInfo) []*descriptorpb.FileDescriptorProto {
// extract all FileDescriptors for given known models (including direct and transitive file imports)
fileDescriptors := make(map[string]protoreflect.FileDescriptor) // using map for deduplication
for _, knownModel := range knownModels {
protoFile := knownModel.MessageDescriptor.ParentFile()
fileDescriptors[protoFile.Path()] = protoFile
for _, importProtoFile := range allImports(protoFile) {
fileDescriptors[importProtoFile.Path()] = importProtoFile
}
}

// convert retrieved FileDescriptors to FileDescriptorProtos
fileDescriptorProtos := make([]*descriptorpb.FileDescriptorProto, 0, len(knownModels))
for _, fileDescriptor := range fileDescriptors {
fileDescriptorProtos = append(fileDescriptorProtos, protodesc.ToFileDescriptorProto(fileDescriptor))
}
return fileDescriptorProtos
}

// versionHandler returns version of Agent.
func (p *Plugin) versionHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
Expand Down
Loading