From aa58e787f3f0be95cb26f6742b6269707589d591 Mon Sep 17 00:00:00 2001 From: Jakub Dyszkiewicz Date: Wed, 13 Nov 2019 14:49:28 +0100 Subject: [PATCH] feat(kuma-cp) validate envoy resource --- .../apis/mesh/proxytemplate_validator.go | 2 + .../apis/mesh/proxytemplate_validator_test.go | 53 ++++++++++++++++++- pkg/xds/generator/proxy_template.go | 27 +--------- pkg/xds/template/raw.go | 38 +++++++++++++ 4 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 pkg/xds/template/raw.go diff --git a/pkg/core/resources/apis/mesh/proxytemplate_validator.go b/pkg/core/resources/apis/mesh/proxytemplate_validator.go index 1a6447dd3e31..e7bfc813d5cd 100644 --- a/pkg/core/resources/apis/mesh/proxytemplate_validator.go +++ b/pkg/core/resources/apis/mesh/proxytemplate_validator.go @@ -54,6 +54,8 @@ func validateResources(resources []*v1alpha1.ProxyTemplateRawResource) validator } if resource.Resource == "" { verr.AddViolationAt(validators.RootedAt("resources").Index(i).Field("resource"), "cannot be empty") + } else if _, err := template.ResourceFromYaml(resource.Resource); err != nil { + verr.AddViolationAt(validators.RootedAt("resources").Index(i).Field("resource"), err.Error()) } } return verr diff --git a/pkg/core/resources/apis/mesh/proxytemplate_validator_test.go b/pkg/core/resources/apis/mesh/proxytemplate_validator_test.go index b9cf794704ac..53881c4e7a8a 100644 --- a/pkg/core/resources/apis/mesh/proxytemplate_validator_test.go +++ b/pkg/core/resources/apis/mesh/proxytemplate_validator_test.go @@ -23,7 +23,20 @@ var _ = Describe("ProxyTemplate", func() { resources: - name: additional version: v1 - resource: test` + resource: | + '@type': type.googleapis.com/envoy.api.v2.Cluster + connectTimeout: 5s + loadAssignment: + clusterName: localhost:8443 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 127.0.0.1 + portValue: 8443 + name: localhost:8443 + type: STATIC` proxyTemplate := mesh.ProxyTemplateResource{} @@ -126,6 +139,44 @@ var _ = Describe("ProxyTemplate", func() { - field: 'selectors[0]["service"]' message: value of tag cannot be empty`, }), + Entry("validation error from envoy protobuf resource", testCase{ + proxyTemplate: ` + selectors: + - match: + service: backend + resources: + - name: additional + version: v1 + resource: | + '@type': type.googleapis.com/envoy.api.v2.Cluster + loadAssignment: + clusterName: localhost:8443 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 127.0.0.1 + portValue: 8443`, + expected: ` + violations: + - field: resources[0].resource + message: 'invalid Cluster.Name: value length must be at least 1 bytes'`, + }), + Entry("invalid envoy resource", testCase{ + proxyTemplate: ` + selectors: + - match: + service: backend + resources: + - name: additional + version: v1 + resource: not-envoy-resource`, + expected: ` + violations: + - field: resources[0].resource + message: 'json: cannot unmarshal string into Go value of type map[string]*json.RawMessage'`, + }), ) }) }) diff --git a/pkg/xds/generator/proxy_template.go b/pkg/xds/generator/proxy_template.go index 7a44b99ade4a..1cb67c8d55b5 100644 --- a/pkg/xds/generator/proxy_template.go +++ b/pkg/xds/generator/proxy_template.go @@ -1,7 +1,6 @@ package generator import ( - "bytes" "fmt" "sort" "strings" @@ -15,10 +14,6 @@ import ( xds_context "github.com/Kong/kuma/pkg/xds/context" "github.com/Kong/kuma/pkg/xds/envoy" "github.com/Kong/kuma/pkg/xds/template" - "github.com/ghodss/yaml" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/ptypes" - any "github.com/golang/protobuf/ptypes/any" ) type TemplateProxyGenerator struct { @@ -51,33 +46,15 @@ type ProxyTemplateRawSource struct { func (s *ProxyTemplateRawSource) Generate(_ xds_context.Context, proxy *model.Proxy) ([]*Resource, error) { resources := make([]*Resource, 0, len(s.Resources)) for i, r := range s.Resources { - json, err := yaml.YAMLToJSON([]byte(r.Resource)) + res, err := template.ResourceFromYaml(r.Resource) if err != nil { - json = []byte(r.Resource) - } - - var anything any.Any - if err := (&jsonpb.Unmarshaler{}).Unmarshal(bytes.NewReader(json), &anything); err != nil { - return nil, fmt.Errorf("raw.resources[%d]{name=%q}.resource: %s", i, r.Name, err) - } - var dyn ptypes.DynamicAny - if err := ptypes.UnmarshalAny(&anything, &dyn); err != nil { return nil, fmt.Errorf("raw.resources[%d]{name=%q}.resource: %s", i, r.Name, err) } - p, ok := dyn.Message.(ResourcePayload) - if !ok { - return nil, fmt.Errorf("raw.resources[%d]{name=%q}.resource: xDS resource doesn't implement all required interfaces", i, r.Name) - } - if v, ok := p.(interface{ Validate() error }); ok { - if err := v.Validate(); err != nil { - return nil, fmt.Errorf("raw.resources[%d]{name=%q}.resource: %s", i, r.Name, err) - } - } resources = append(resources, &Resource{ Name: r.Name, Version: r.Version, - Resource: p, + Resource: res, }) } return resources, nil diff --git a/pkg/xds/template/raw.go b/pkg/xds/template/raw.go new file mode 100644 index 000000000000..cbc9f19f2fe8 --- /dev/null +++ b/pkg/xds/template/raw.go @@ -0,0 +1,38 @@ +package template + +import ( + "bytes" + "errors" + "github.com/envoyproxy/go-control-plane/pkg/cache" + "github.com/ghodss/yaml" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" +) + +func ResourceFromYaml(resYaml string) (proto.Message, error) { + json, err := yaml.YAMLToJSON([]byte(resYaml)) + if err != nil { + json = []byte(resYaml) + } + + var anything any.Any + if err := (&jsonpb.Unmarshaler{}).Unmarshal(bytes.NewReader(json), &anything); err != nil { + return nil, err + } + var dyn ptypes.DynamicAny + if err := ptypes.UnmarshalAny(&anything, &dyn); err != nil { + return nil, err + } + p, ok := dyn.Message.(cache.Resource) + if !ok { + return nil, errors.New("xDS resource doesn't implement all required interfaces") + } + if v, ok := p.(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return nil, err + } + } + return p, nil +}