From ed1cf353f39b8b8fda8a575cd07d3531b27d899b Mon Sep 17 00:00:00 2001 From: Miguel Mendoza Date: Wed, 23 Oct 2024 15:03:02 -0700 Subject: [PATCH] fix: add missing validation for HealthMonitor fixes apigee/apigee-go-gen#12 --- examples/yaml-first/petstore/apiproxy.yaml | 2 +- pkg/apigee/v1/apiproxy.go | 1 + pkg/apigee/v1/apiproxymodel_test.go | 6 +++ pkg/apigee/v1/header.go | 37 ++++++++++++++ pkg/apigee/v1/headers.go | 33 ++++++++++++ pkg/apigee/v1/healthmonitor.go | 43 ++++++++++++++++ pkg/apigee/v1/httpmonitor.go | 41 +++++++++++++++ pkg/apigee/v1/httpmonitor_request.go | 49 ++++++++++++++++++ pkg/apigee/v1/httptargetconnection.go | 1 + pkg/apigee/v1/responsecode.go | 36 +++++++++++++ pkg/apigee/v1/responsecodes.go | 33 ++++++++++++ pkg/apigee/v1/successresponse.go | 41 +++++++++++++++ pkg/apigee/v1/tcpmonitor.go | 37 ++++++++++++++ pkg/apigee/v1/testdata/.gitignore | 2 +- .../health-monitor-http/apiproxy.yaml | 51 +++++++++++++++++++ .../health-monitor-tcp/apiproxy.yaml | 37 ++++++++++++++ 16 files changed, 448 insertions(+), 2 deletions(-) create mode 100644 pkg/apigee/v1/header.go create mode 100644 pkg/apigee/v1/headers.go create mode 100644 pkg/apigee/v1/healthmonitor.go create mode 100644 pkg/apigee/v1/httpmonitor.go create mode 100644 pkg/apigee/v1/httpmonitor_request.go create mode 100644 pkg/apigee/v1/responsecode.go create mode 100644 pkg/apigee/v1/responsecodes.go create mode 100644 pkg/apigee/v1/successresponse.go create mode 100644 pkg/apigee/v1/tcpmonitor.go create mode 100644 pkg/apigee/v1/testdata/yaml-first/health-monitor-http/apiproxy.yaml create mode 100644 pkg/apigee/v1/testdata/yaml-first/health-monitor-tcp/apiproxy.yaml diff --git a/examples/yaml-first/petstore/apiproxy.yaml b/examples/yaml-first/petstore/apiproxy.yaml index 16cde70..c221eba 100755 --- a/examples/yaml-first/petstore/apiproxy.yaml +++ b/examples/yaml-first/petstore/apiproxy.yaml @@ -47,7 +47,7 @@ TargetEndpoints: - TargetEndpoint: .name: default HTTPTargetConnection: - URL: http://petstore.swagger.io/v1 + URL: https://petstore.swagger.io/v2 Resources: - Resource: Type: oas diff --git a/pkg/apigee/v1/apiproxy.go b/pkg/apigee/v1/apiproxy.go index 7b7486e..908d465 100644 --- a/pkg/apigee/v1/apiproxy.go +++ b/pkg/apigee/v1/apiproxy.go @@ -32,6 +32,7 @@ type APIProxy struct { Spec *Deprecated `xml:"Spec"` ConfigurationVersion *Deprecated `xml:"ConfigurationVersion"` BasePaths *Deprecated `xml:"BasePaths"` + Basepaths *Deprecated `xml:"Basepaths"` Policies *Deprecated `xml:"Policies"` Resources *Deprecated `xml:"Resources"` ProxyEndpoints *Deprecated `xml:"ProxyEndpoints"` diff --git a/pkg/apigee/v1/apiproxymodel_test.go b/pkg/apigee/v1/apiproxymodel_test.go index 95f5fb4..e3f4a84 100644 --- a/pkg/apigee/v1/apiproxymodel_test.go +++ b/pkg/apigee/v1/apiproxymodel_test.go @@ -38,6 +38,12 @@ func TestNewAPIProxyModel(t *testing.T) { { "postclient", }, + { + "health-monitor-http", + }, + { + "health-monitor-tcp", + }, } for _, tt := range tests { ttDir := filepath.Join("testdata", "yaml-first", tt.name) diff --git a/pkg/apigee/v1/header.go b/pkg/apigee/v1/header.go new file mode 100644 index 0000000..b5e89e6 --- /dev/null +++ b/pkg/apigee/v1/header.go @@ -0,0 +1,37 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type Header struct { + Name string `xml:"name,attr"` + Value string `xml:",cdata"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateHeader(v *Header, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.Header", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + return nil +} diff --git a/pkg/apigee/v1/headers.go b/pkg/apigee/v1/headers.go new file mode 100644 index 0000000..55f65d2 --- /dev/null +++ b/pkg/apigee/v1/headers.go @@ -0,0 +1,33 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type HeadersList []*Header + +func ValidateHeaders(v *HeadersList, path string) []error { + if v == nil { + return nil + } + + for i, vv := range *v { + errs := ValidateHeader(vv, fmt.Sprintf("%s.Headers.%v", path, i)) + if len(errs) > 0 { + return errs + } + } + return nil +} diff --git a/pkg/apigee/v1/healthmonitor.go b/pkg/apigee/v1/healthmonitor.go new file mode 100644 index 0000000..df31e56 --- /dev/null +++ b/pkg/apigee/v1/healthmonitor.go @@ -0,0 +1,43 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type HealthMonitor struct { + IsEnabled bool `xml:"Enforce,omitempty"` + IntervalInSec int `xml:"IntervalInSec"` + TCPMonitor *TCPMonitor `xml:"TCPMonitor,omitempty"` + HTTPMonitor *HTTPMonitor `xml:"HTTPMonitor,omitempty"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateHealthMonitor(v *HealthMonitor, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.HealthMonitor", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + var subErrors []error + subErrors = append(subErrors, ValidateTCPMonitor(v.TCPMonitor, subPath)...) + subErrors = append(subErrors, ValidateHTTPMonitor(v.HTTPMonitor, subPath)...) + + return subErrors +} diff --git a/pkg/apigee/v1/httpmonitor.go b/pkg/apigee/v1/httpmonitor.go new file mode 100644 index 0000000..2662ef6 --- /dev/null +++ b/pkg/apigee/v1/httpmonitor.go @@ -0,0 +1,41 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type HTTPMonitor struct { + Request *HttpMonitorRequest `xml:"Request"` + SuccessResponse *SuccessResponse `xml:"SuccessResponse,omitempty"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateHTTPMonitor(v *HTTPMonitor, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.HTTPMonitor", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + var subErrors []error + subErrors = append(subErrors, ValidateHttpMonitorRequest(v.Request, subPath)...) + subErrors = append(subErrors, ValidateSuccessResponse(v.SuccessResponse, subPath)...) + + return subErrors +} diff --git a/pkg/apigee/v1/httpmonitor_request.go b/pkg/apigee/v1/httpmonitor_request.go new file mode 100644 index 0000000..1fa238f --- /dev/null +++ b/pkg/apigee/v1/httpmonitor_request.go @@ -0,0 +1,49 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type HttpMonitorRequest struct { + ConnectTimeoutInSec int `xml:"ConnectTimeoutInSec,omitempty"` + SocketReadTimeoutInSec int `xml:"SocketReadTimeoutInSec,omitempty"` + Port int `xml:"Port,omitempty"` + Verb string `xml:"Verb,omitempty"` + Path string `xml:"Path,omitempty"` + UseTargetServerSSLInfo bool `xml:"UseTargetServerSSLInfo,omitempty"` + IncludeHealthCheckIdHeader bool `xml:"IncludeHealthCheckIdHeader,omitempty"` + Payload string `xml:"Payload,omitempty"` + Headers HeadersList `xml:"Header,omitempty"` + IsSSL bool `xml:"IsSSL,omitempty"` + TrustAllSSL bool `xml:"TrustAllSSL,omitempty"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateHttpMonitorRequest(v *HttpMonitorRequest, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.Request", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + var subErrors []error + subErrors = append(subErrors, ValidateHeaders(&v.Headers, subPath)...) + + return subErrors +} diff --git a/pkg/apigee/v1/httptargetconnection.go b/pkg/apigee/v1/httptargetconnection.go index 9a06d68..3185697 100644 --- a/pkg/apigee/v1/httptargetconnection.go +++ b/pkg/apigee/v1/httptargetconnection.go @@ -23,6 +23,7 @@ type HTTPTargetConnection struct { LoadBalancer *LoadBalancer `xml:"LoadBalancer,omitempty"` SSLInfo *SSLInfo `xml:"SSLInfo,omitempty"` Properties *Properties `xml:"Properties"` + HealthMonitor *HealthMonitor `xml:"HealthMonitor,omitempty"` UnknownNode AnyList `xml:",any"` } diff --git a/pkg/apigee/v1/responsecode.go b/pkg/apigee/v1/responsecode.go new file mode 100644 index 0000000..ee02900 --- /dev/null +++ b/pkg/apigee/v1/responsecode.go @@ -0,0 +1,36 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type ResponseCode struct { + Value int `xml:",cdata"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateResponseCode(v *ResponseCode, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.ResponseCode", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + return nil +} diff --git a/pkg/apigee/v1/responsecodes.go b/pkg/apigee/v1/responsecodes.go new file mode 100644 index 0000000..b3bc4ea --- /dev/null +++ b/pkg/apigee/v1/responsecodes.go @@ -0,0 +1,33 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type ResponseCodeList []*ResponseCode + +func ValidateResponseCodes(v *ResponseCodeList, path string) []error { + if v == nil { + return nil + } + + for i, vv := range *v { + errs := ValidateResponseCode(vv, fmt.Sprintf("%s.ResponseCodes.%v", path, i)) + if len(errs) > 0 { + return errs + } + } + return nil +} diff --git a/pkg/apigee/v1/successresponse.go b/pkg/apigee/v1/successresponse.go new file mode 100644 index 0000000..e80148d --- /dev/null +++ b/pkg/apigee/v1/successresponse.go @@ -0,0 +1,41 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type SuccessResponse struct { + ResponseCodes ResponseCodeList `xml:"ResponseCode,omitempty"` + Headers HeadersList `xml:"Header,omitempty"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateSuccessResponse(v *SuccessResponse, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.SuccessResponse", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + var subErrors []error + subErrors = append(subErrors, ValidateHeaders(&v.Headers, subPath)...) + subErrors = append(subErrors, ValidateResponseCodes(&v.ResponseCodes, subPath)...) + + return subErrors +} diff --git a/pkg/apigee/v1/tcpmonitor.go b/pkg/apigee/v1/tcpmonitor.go new file mode 100644 index 0000000..e0d8565 --- /dev/null +++ b/pkg/apigee/v1/tcpmonitor.go @@ -0,0 +1,37 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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. + +package v1 + +import "fmt" + +type TCPMonitor struct { + ConnectTimeoutInSec int `xml:"IntervalInSec"` + Port int `xml:"Port,omitempty"` + + UnknownNode AnyList `xml:",any"` +} + +func ValidateTCPMonitor(v *TCPMonitor, path string) []error { + if v == nil { + return nil + } + + subPath := fmt.Sprintf("%s.TCPMonitor", path) + if len(v.UnknownNode) > 0 { + return []error{&UnknownNodeError{subPath, v.UnknownNode[0]}} + } + + return nil +} diff --git a/pkg/apigee/v1/testdata/.gitignore b/pkg/apigee/v1/testdata/.gitignore index d04f10c..12b4ea3 100644 --- a/pkg/apigee/v1/testdata/.gitignore +++ b/pkg/apigee/v1/testdata/.gitignore @@ -11,4 +11,4 @@ # 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. -out-*.yaml \ No newline at end of file +**/out-*.yaml \ No newline at end of file diff --git a/pkg/apigee/v1/testdata/yaml-first/health-monitor-http/apiproxy.yaml b/pkg/apigee/v1/testdata/yaml-first/health-monitor-http/apiproxy.yaml new file mode 100644 index 0000000..995bdba --- /dev/null +++ b/pkg/apigee/v1/testdata/yaml-first/health-monitor-http/apiproxy.yaml @@ -0,0 +1,51 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +APIProxy: + .revision: 1 + .name: httpbin +Policies: [] +ProxyEndpoints: + - ProxyEndpoint: + .name: default + Flows: [] + HTTPProxyConnection: + BasePath: /httpbin + RouteRule: + .name: default + TargetEndpoint: default +TargetEndpoints: + - TargetEndpoint: + .name: default + HTTPTargetConnection: + URL: https://httpbin.org + HealthMonitor: + IsEnabled: true + IntervalInSec: 5 + HTTPMonitor: + Request: + UseTargetServerSSLInfo: true + ConnectTimeoutInSec: 10 + SocketReadTimeoutInSec: 30 + Port: 80 + Verb: GET + Path: /json + Header: + .name: Authorization + -Data: Basic 12e98yfw87etf + IncludeHealthCheckIdHeader: true + SuccessResponse: + ResponseCode: 200 + Header: + .name: ImOK + -Data: YourOK \ No newline at end of file diff --git a/pkg/apigee/v1/testdata/yaml-first/health-monitor-tcp/apiproxy.yaml b/pkg/apigee/v1/testdata/yaml-first/health-monitor-tcp/apiproxy.yaml new file mode 100644 index 0000000..8728ae8 --- /dev/null +++ b/pkg/apigee/v1/testdata/yaml-first/health-monitor-tcp/apiproxy.yaml @@ -0,0 +1,37 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +APIProxy: + .revision: 1 + .name: httpbin +Policies: [] +ProxyEndpoints: + - ProxyEndpoint: + .name: default + Flows: [] + HTTPProxyConnection: + BasePath: /httpbin + RouteRule: + .name: default + TargetEndpoint: default +TargetEndpoints: + - TargetEndpoint: + .name: default + HTTPTargetConnection: + URL: https://httpbin.org + HealthMonitor: + IsEnabled: true + IntervalInSec: 5 + TCPMonitor: + ConnectTimeoutInSec: 10 + Port: 80 \ No newline at end of file