From 31523a49207ac8cad106903224c3dae5013b26b0 Mon Sep 17 00:00:00 2001 From: srinandan <13950006+srinandan@users.noreply.github.com> Date: Tue, 25 Jul 2023 09:31:22 -0700 Subject: [PATCH 1/2] feat: gen bundle for integration targets #235 --- cmd/apis/integrationapis.go | 13 ++-- cmd/apis/oascrtapis.go | 41 +++++++++++-- internal/bundlegen/generateapi.go | 60 ++++++++++++------- internal/bundlegen/generateint.go | 15 ++++- internal/bundlegen/options.go | 33 ++++++++++ internal/bundlegen/proxybundle/proxybundle.go | 49 ++++++++++----- 6 files changed, 167 insertions(+), 44 deletions(-) create mode 100644 internal/bundlegen/options.go diff --git a/cmd/apis/integrationapis.go b/cmd/apis/integrationapis.go index 3de0a1e64..4966b52e4 100644 --- a/cmd/apis/integrationapis.go +++ b/cmd/apis/integrationapis.go @@ -18,6 +18,7 @@ import ( "os" "internal/apiclient" + "internal/client/apis" "internal/bundlegen" "internal/bundlegen/proxybundle" @@ -40,15 +41,17 @@ var IntegrationCmd = &cobra.Command{ defer os.RemoveAll(tmpDir) - if err = bundlegen.GenerateIntegrationAPIProxy(name, integration, apitrigger); err != nil { + if err = bundlegen.GenerateIntegrationAPIProxy(name, apitrigger); err != nil { return err } + if err = proxybundle.GenerateIntegrationAPIProxyBundle(name, integration, apitrigger, true); err != nil { return err } - /*if _, err = apis.CreateProxy(name, tmpDir); err != nil { - return err - }*/ + + if importProxy { + _, err = apis.CreateProxy(name, tmpDir) + } return err }, } @@ -62,6 +65,8 @@ func init() { "", "Integration name") IntegrationCmd.Flags().StringVarP(&apitrigger, "trigger", "", "", "API Trigger name; don't include 'api_trigger/'") + IntegrationCmd.Flags().BoolVarP(&importProxy, "import", "", + true, "Import API Proxy after generation") _ = IntegrationCmd.MarkFlagRequired("name") _ = IntegrationCmd.MarkFlagRequired("integration") diff --git a/cmd/apis/oascrtapis.go b/cmd/apis/oascrtapis.go index ef90114a5..1e123e999 100644 --- a/cmd/apis/oascrtapis.go +++ b/cmd/apis/oascrtapis.go @@ -39,12 +39,23 @@ var OasCreateCmd = &cobra.Command{ if targetURL != "" && targetURLRef != "" { return fmt.Errorf("either target-url or target-url-ref must be passed, not both") } + if integration != "" && apitrigger == "" { + return fmt.Errorf("apitrigger must be passed if integration is set") + } + if integration == "" && apitrigger != "" { + return fmt.Errorf("integration must be passed if apitrigger is set") + } + if (targetURL != "" || targetURLRef != "") && (integration != "" || apitrigger != "") { + return fmt.Errorf("integration or apitrigger cannot be set if targetURL or targetURLRef is set") + } return apiclient.SetApigeeOrg(org) }, RunE: func(cmd *cobra.Command, args []string) (err error) { var content []byte var oasDocName string + integrationEndpoint := false + if oasFile != "" { oasDocName, content, err = bundle.LoadDocumentFromFile(oasFile, validateSpec, formatValidation) } else { @@ -54,11 +65,31 @@ var OasCreateCmd = &cobra.Command{ return err } + targetOptions := bundle.TargetOptions{ + IntegrationBackend: bundle.IntegrationBackendOptions{ + IntegrationName: integration, + TriggerName: apitrigger, + }, + HttpBackend: bundle.HttpBackendOptions{ + OasGoogleAcessTokenScopeLiteral: oasGoogleAcessTokenScopeLiteral, + OasGoogleIDTokenAudLiteral: oasGoogleIDTokenAudLiteral, + OasGoogleIDTokenAudRef: oasGoogleIDTokenAudRef, + OasTargetURLRef: targetURLRef, + TargetURL: targetURL, + }, + } + + // check if integrationEndpoint is selected + if integration != "" { + integrationEndpoint = true + } + // Generate the apiproxy struct err = bundle.GenerateAPIProxyDefFromOAS(name, oasDocName, skipPolicy, addCORS, + integrationEndpoint, oasGoogleAcessTokenScopeLiteral, oasGoogleIDTokenAudLiteral, oasGoogleIDTokenAudRef, @@ -75,11 +106,7 @@ var OasCreateCmd = &cobra.Command{ oasDocName, skipPolicy, addCORS, - oasGoogleAcessTokenScopeLiteral, - oasGoogleIDTokenAudLiteral, - oasGoogleIDTokenAudRef, - targetURLRef, - targetURL) + targetOptions) if err != nil { return err @@ -116,6 +143,10 @@ func init() { "", "Set a reference variable containing the target endpoint") OasCreateCmd.Flags().StringVarP(&targetURL, "target-url", "", "", "Set a target URL for the target endpoint") + OasCreateCmd.Flags().StringVarP(&integration, "integration", "i", + "", "Integration name") + OasCreateCmd.Flags().StringVarP(&apitrigger, "trigger", "", + "", "API Trigger name; don't include 'api_trigger/'") OasCreateCmd.Flags().BoolVarP(&importProxy, "import", "", true, "Import API Proxy after generation from spec") OasCreateCmd.Flags().BoolVarP(&validateSpec, "validate", "", diff --git a/internal/bundlegen/generateapi.go b/internal/bundlegen/generateapi.go index 909759750..708e1e1ff 100644 --- a/internal/bundlegen/generateapi.go +++ b/internal/bundlegen/generateapi.go @@ -208,11 +208,12 @@ func GenerateAPIProxyDefFromOAS(name string, oasDocName string, skipPolicy bool, addCORS bool, + integrationEndpoint bool, oasGoogleAcessTokenScopeLiteral string, - oasGoogleIdTokenAudLiteral string, - oasGoogleIdTokenAudRef string, - oasTargetUrlRef string, - targetUrl string, + oasGoogleIDTokenAudLiteral string, + oasGoogleIDTokenAudRef string, + oasTargetURLRef string, + targetURL string, ) (err error) { if doc == nil { return fmt.Errorf("the Open API document not loaded") @@ -231,7 +232,11 @@ func GenerateAPIProxyDefFromOAS(name string, apiproxy.SetCreatedAt() apiproxy.SetLastModifiedAt() apiproxy.SetConfigurationVersion() - apiproxy.AddTargetEndpoint(NoAuthTargetName) + if integrationEndpoint { + apiproxy.AddIntegrationEndpoint("default") + } else { + apiproxy.AddTargetEndpoint(NoAuthTargetName) + } apiproxy.AddProxyEndpoint("default") if !skipPolicy { @@ -250,25 +255,40 @@ func GenerateAPIProxyDefFromOAS(name string, apiproxy.SetBasePath(u.Path) - // if target is not set, derive it from the OAS file - if targetUrl == "" { - targets.NewTargetEndpoint(NoAuthTargetName, u.Scheme+"://"+u.Hostname()+u.Path, oasGoogleAcessTokenScopeLiteral, oasGoogleIdTokenAudLiteral, oasGoogleIdTokenAudRef) - } else { // an explicit target url is set - if _, err = url.Parse(targetUrl); err != nil { - return fmt.Errorf("invalid target url: %v", err) + // decide on the type of target + if integrationEndpoint { // assume an integration endpoint + proxies.AddStepToPreFlowRequest("set-integration-request") + apiproxy.AddPolicy("set-integration-request") + proxies.NewProxyEndpoint(u.Path, false) + } else { + // if target is not set, derive it from the OAS file + if targetURL == "" { + targets.NewTargetEndpoint(NoAuthTargetName, + u.Scheme+"://"+u.Hostname()+u.Path, + oasGoogleAcessTokenScopeLiteral, + oasGoogleIDTokenAudLiteral, + oasGoogleIDTokenAudRef) + } else { // an explicit target url is set + if _, err = url.Parse(targetURL); err != nil { + return fmt.Errorf("invalid target url: %v", err) + } + targets.NewTargetEndpoint(NoAuthTargetName, + targetURL, + oasGoogleAcessTokenScopeLiteral, + oasGoogleIDTokenAudLiteral, + oasGoogleIDTokenAudRef) + } + + // set a dynamic target url + if oasTargetURLRef != "" { + targets.AddStepToPreFlowRequest("Set-Target-1", NoAuthTargetName) + apiproxy.AddPolicy("Set-Target-1") + generateSetTarget = true } - targets.NewTargetEndpoint(NoAuthTargetName, targetUrl, oasGoogleAcessTokenScopeLiteral, oasGoogleIdTokenAudLiteral, oasGoogleIdTokenAudRef) - } - // set a dynamic target url - if oasTargetUrlRef != "" { - targets.AddStepToPreFlowRequest("Set-Target-1", NoAuthTargetName) - apiproxy.AddPolicy("Set-Target-1") - generateSetTarget = true + proxies.NewProxyEndpoint(u.Path, true) } - proxies.NewProxyEndpoint(u.Path, true) - // add any preflow security schemes if securityScheme := getSecurityRequirements(doc.Security); securityScheme.SchemeName != "" { if securityScheme.APIKeyPolicy.APIKeyPolicyEnabled { diff --git a/internal/bundlegen/generateint.go b/internal/bundlegen/generateint.go index 26e268c4d..a85868759 100644 --- a/internal/bundlegen/generateint.go +++ b/internal/bundlegen/generateint.go @@ -1,3 +1,17 @@ +// Copyright 2022 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 bundlegen import ( @@ -6,7 +20,6 @@ import ( ) func GenerateIntegrationAPIProxy(name string, - integration string, apitrigger string, ) (err error) { apiproxy.SetDisplayName(name) diff --git a/internal/bundlegen/options.go b/internal/bundlegen/options.go new file mode 100644 index 000000000..ce8635aa1 --- /dev/null +++ b/internal/bundlegen/options.go @@ -0,0 +1,33 @@ +// Copyright 2023 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 bundlegen + +type IntegrationBackendOptions struct { + IntegrationName string + TriggerName string +} + +type HttpBackendOptions struct { + OasGoogleAcessTokenScopeLiteral string + OasGoogleIDTokenAudLiteral string + OasGoogleIDTokenAudRef string + OasTargetURLRef string + TargetURL string +} + +type TargetOptions struct { + IntegrationBackend IntegrationBackendOptions + HttpBackend HttpBackendOptions +} diff --git a/internal/bundlegen/proxybundle/proxybundle.go b/internal/bundlegen/proxybundle/proxybundle.go index 1917df0e9..81e60b83c 100644 --- a/internal/bundlegen/proxybundle/proxybundle.go +++ b/internal/bundlegen/proxybundle/proxybundle.go @@ -48,13 +48,9 @@ func GenerateAPIProxyBundleFromOAS(name string, fileName string, skipPolicy bool, addCORS bool, - oasGoogleAcessTokenScopeLiteral string, - oasGoogleIdTokenAudLiteral string, - oasGoogleIdTokenAudRef string, - oasTargetUrlRef string, - targetUrl string, + targetOptions bundlegen.TargetOptions, ) (err error) { - var apiProxyData, proxyEndpointData, targetEndpointData string + var apiProxyData, proxyEndpointData, targetEndpointData, integrationEndpointData string const resourceType = "oas" tmpDir, err := os.MkdirTemp("", "proxy") @@ -82,6 +78,7 @@ func GenerateAPIProxyBundleFromOAS(name string, policiesDirPath := rootDir + string(os.PathSeparator) + "policies" targetDirPath := rootDir + string(os.PathSeparator) + "targets" resDirPath := rootDir + string(os.PathSeparator) + "resources" + string(os.PathSeparator) + resourceType //"oas" + integrationDirPath := rootDir + string(os.PathSeparator) + "integration-endpoints" if err = os.Mkdir(proxiesDirPath, os.ModePerm); err != nil { return err @@ -96,18 +93,33 @@ func GenerateAPIProxyBundleFromOAS(name string, return err } - if err = os.Mkdir(targetDirPath, os.ModePerm); err != nil { - return err - } + if targetOptions.IntegrationBackend.IntegrationName != "" { - for _, targetEndpoint := range targets.TargetEndpoints { - if targetEndpointData, err = target.GetTargetEndpoint(targetEndpoint); err != nil { + if err = os.Mkdir(integrationDirPath, os.ModePerm); err != nil { return err } - if err = writeXMLData(targetDirPath+string(os.PathSeparator)+targetEndpoint.Name+".xml", targetEndpointData); err != nil { + // assume there is an integration target + integrationEndpointData = target.GetIntegrationEndpoint() + if err = writeXMLData(integrationDirPath+string(os.PathSeparator)+"default.xml", integrationEndpointData); err != nil { return err } + + } else { + + if err = os.Mkdir(targetDirPath, os.ModePerm); err != nil { + return err + } + + for _, targetEndpoint := range targets.TargetEndpoints { + if targetEndpointData, err = target.GetTargetEndpoint(targetEndpoint); err != nil { + return err + } + + if err = writeXMLData(targetDirPath+string(os.PathSeparator)+targetEndpoint.Name+".xml", targetEndpointData); err != nil { + return err + } + } } if !skipPolicy { @@ -124,15 +136,24 @@ func GenerateAPIProxyBundleFromOAS(name string, } // add set target url - if targetUrl == "" { + if targetOptions.HttpBackend.TargetURL == "" { if genapi.GenerateSetTargetPolicy() { if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"Set-Target-1.xml", - policies.AddSetTargetEndpointRef(oasTargetUrlRef)); err != nil { + policies.AddSetTargetEndpointRef(targetOptions.HttpBackend.OasTargetURLRef)); err != nil { return err } } } + if targetOptions.IntegrationBackend.IntegrationName != "" { + // add set integration request policy + if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"set-integration-request.xml", + policies.AddSetIntegrationRequestPolicy(targetOptions.IntegrationBackend.IntegrationName, + targetOptions.IntegrationBackend.TriggerName)); err != nil { + return err + } + } + // add security policies for _, securityScheme := range genapi.GetSecuritySchemesList() { if securityScheme.APIKeyPolicy.APIKeyPolicyEnabled { From 4eb886900f9ebec680a9879702b0fe4a27e36430 Mon Sep 17 00:00:00 2001 From: srinandan <13950006+srinandan@users.noreply.github.com> Date: Tue, 25 Jul 2023 09:33:24 -0700 Subject: [PATCH 2/2] chore: add license and fix lint #236 --- .github/workflows/docker-cloudbuild.yml | 14 ++++++++++++++ .github/workflows/docker-publish.yml | 14 ++++++++++++++ cmd/utils/utils.go | 14 ++++++++++++++ internal/apiclient/httpclient.go | 2 +- internal/client/apis/apis.go | 4 +--- internal/client/developers/developers.go | 1 - internal/client/sharedflows/sharedflows.go | 1 - test/endpoints1.yaml | 14 ++++++++++++++ test/endpoints2.yaml | 14 ++++++++++++++ test/md.yaml | 4 ++-- .../policies/Verify-API-Key-1.xml | 16 ++++++++++++++++ test/sharedflowbundle/sharedflows/default.xml | 16 ++++++++++++++++ test/sharedflowbundle/test_flow.xml | 16 ++++++++++++++++ test/windfarm3-quota.yaml | 14 ++++++++++++++ 14 files changed, 136 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker-cloudbuild.yml b/.github/workflows/docker-cloudbuild.yml index 53680b74c..ac6fd925b 100644 --- a/.github/workflows/docker-cloudbuild.yml +++ b/.github/workflows/docker-cloudbuild.yml @@ -1,3 +1,17 @@ +# Copyright 2023 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. + name: Cloud Builder Docker # This workflow uses actions that are not certified by GitHub. diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 393519114..782e2f267 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,3 +1,17 @@ +# Copyright 2023 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. + name: Docker # This workflow uses actions that are not certified by GitHub. diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index 5b3d6b436..459eaf02e 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -1,3 +1,17 @@ +// Copyright 2023 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 utils import ( diff --git a/internal/apiclient/httpclient.go b/internal/apiclient/httpclient.go index 4cb4ddfa4..0bf2a1ae4 100644 --- a/internal/apiclient/httpclient.go +++ b/internal/apiclient/httpclient.go @@ -326,7 +326,7 @@ func HttpClient(params ...string) (respBody []byte, err error) { func PrettyPrint(contentType string, body []byte) error { if GetCmdPrintHttpResponseSetting() && ClientPrintHttpResponse.Get() { var prettyJSON bytes.Buffer - //pretty print only json responses with body + // pretty print only json responses with body if strings.Contains(contentType, "json") && len(body) > 0 { err := json.Indent(&prettyJSON, body, "", "\t") if err != nil { diff --git a/internal/client/apis/apis.go b/internal/client/apis/apis.go index 2e3c7adce..9c83f3a00 100644 --- a/internal/client/apis/apis.go +++ b/internal/client/apis/apis.go @@ -65,8 +65,7 @@ type violation struct { Description string `json:"description,omitempty"` } -type routingchanges struct { -} +type routingchanges struct{} type routingconflicts struct { EnvironmentGroup string `json:"environmentGroup,omitempty"` @@ -112,7 +111,6 @@ func DeleteProxyRevision(name string, revision int) (respBody []byte, err error) // DeployProxy func DeployProxy(name string, revision int, overrides bool, sequencedRollout bool, safeDeploy bool, serviceAccountName string) (respBody []byte, err error) { - if safeDeploy { var safeResp []byte d := deploychangereport{} diff --git a/internal/client/developers/developers.go b/internal/client/developers/developers.go index add2369b0..ffba71d99 100644 --- a/internal/client/developers/developers.go +++ b/internal/client/developers/developers.go @@ -168,7 +168,6 @@ func Export() (respBody []byte, err error) { // Import func Import(conn int, filePath string) error { - entities, err := ReadDevelopersFile(filePath) if err != nil { clilog.Error.Println("Error reading file: ", err) diff --git a/internal/client/sharedflows/sharedflows.go b/internal/client/sharedflows/sharedflows.go index fe097f1a1..ce77b1528 100644 --- a/internal/client/sharedflows/sharedflows.go +++ b/internal/client/sharedflows/sharedflows.go @@ -345,7 +345,6 @@ func Export(conn int, folder string, allRevisions bool) (err error) { lastRevision := maxRevision(proxy.Revision) jobChan <- revision{name: proxy.Name, rev: lastRevision} } - } close(jobChan) fanOutWg.Wait() diff --git a/test/endpoints1.yaml b/test/endpoints1.yaml index 2b140b00f..f44899f07 100644 --- a/test/endpoints1.yaml +++ b/test/endpoints1.yaml @@ -1,3 +1,17 @@ +# Copyright 2023 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. + swagger: '2.0' info: title: test - testing api gateway diff --git a/test/endpoints2.yaml b/test/endpoints2.yaml index 1c6f077ae..cdd3f083e 100644 --- a/test/endpoints2.yaml +++ b/test/endpoints2.yaml @@ -1,3 +1,17 @@ +# Copyright 2023 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. + swagger: "2.0" info: title: API Gateway + Cloud Run + Third party auth diff --git a/test/md.yaml b/test/md.yaml index 323094d25..3f78d3e74 100644 --- a/test/md.yaml +++ b/test/md.yaml @@ -18,10 +18,10 @@ info: title: Masterdata microservice description: | Masterdata microservice -servers: +servers: - url: https://my.example.com/md security: - - ApiKeyAuth: [] + - ApiKeyAuth: [] paths: '/': get: diff --git a/test/sharedflowbundle/policies/Verify-API-Key-1.xml b/test/sharedflowbundle/policies/Verify-API-Key-1.xml index f2b32de67..ee2f10227 100644 --- a/test/sharedflowbundle/policies/Verify-API-Key-1.xml +++ b/test/sharedflowbundle/policies/Verify-API-Key-1.xml @@ -1,4 +1,20 @@ + + Verify API Key-1 diff --git a/test/sharedflowbundle/sharedflows/default.xml b/test/sharedflowbundle/sharedflows/default.xml index 236a97c24..b543af6aa 100644 --- a/test/sharedflowbundle/sharedflows/default.xml +++ b/test/sharedflowbundle/sharedflows/default.xml @@ -1,4 +1,20 @@ + + Verify-API-Key-1 diff --git a/test/sharedflowbundle/test_flow.xml b/test/sharedflowbundle/test_flow.xml index 569ef9843..ddf00b712 100644 --- a/test/sharedflowbundle/test_flow.xml +++ b/test/sharedflowbundle/test_flow.xml @@ -1,3 +1,19 @@ + + test_flow undefined diff --git a/test/windfarm3-quota.yaml b/test/windfarm3-quota.yaml index 5c51fab6e..9e5b5b2d3 100644 --- a/test/windfarm3-quota.yaml +++ b/test/windfarm3-quota.yaml @@ -1,3 +1,17 @@ +# Copyright 2023 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. + openapi: 3.0.0 info: description: Get Windfarm info and status