From edfd50b13fa0b5d7037fe67ae53b4537eed963ea Mon Sep 17 00:00:00 2001 From: Jacek Ewertowski Date: Mon, 4 Jul 2022 10:45:56 +0200 Subject: [PATCH] [ior] MAISTRA-1400 Add IOR to Pilot (#556) * [ior] MAISTRA-1400 Add IOR to Pilot * [MAISTRA-1089][MAISTRA-1400][MAISTRA-1744][MAISTRA-1811]: Add IOR to Pilot (#135) (#240) * MAISTRA-1400: Add IOR to Pilot (#135) * MAISTRA-1400: Add IOR to Pilot * [MAISTRA-1744] Add route annotation propagation (#158) * MAISTRA-1811 Store resourceVersion of reconciled Gateway resource (#190) * MAISTRA-1089 Add support for IOR routes in all namespaces (#193) * MAISTRA-2131: ior: honor Gateway's httpsRedirect (#276) If Gateway's httpsRedirect is set to true, create the OpenShift Route with Insecure Policy set to `Redirect`. Manual cherrypick from https://github.com/maistra/istio/pull/269. * MAISTRA-2149: Make IOR robust in multiple replicas (#282) In scenarios where multiple replicas of istiod are running, only one IOR should be in charge of keeping routes in sync with Istio Gateways. We achieve this by making sure IOR only runs in the leader replica. Also, because leader election is not 100% acurate, meaning that for a small window of time there might be two instances being the leader - which could lead to duplicated routes being created if a new gateway is created in that time frame - we also change the way the Route name is created: Instead of having a generateName field, we now explicitly pass a name to the Route object to be created. Being deterministic, it allows the Route creation to fail when there's already a Route object with the same name (created by the other leader in that time frame). Use an exclusive leader ID for IOR * Manual cherrypick of https://github.com/maistra/istio/pull/275 * MAISTRA-1813: Add unit tests for IOR (#286) * MAISTRA-2051 fixes for maistra install * MAISTRA-2164: Refactor IOR internals (#295) Instead of doing lots of API calls on every event - this does not scale well with lots of namespaces - keep the state in memory, by doing an initial synchronization on start up and updating it when receiving events. The initial synchronization is more complex, as we have to deal with asynchronous events (e.g., we have to wait for the Gateway store to be warmed up). Once it's initialized, handling events as they arrive becomes trivial. Tests that make sure we do not make more calls to the API server than the necessary were added, to avoid regressions. * MAISTRA-2205: Add an option to opt-out for automatic route creation If the Istio Gateway contains the annotation `maistra.io/manageRoute: false` then IOR ignores it and doesn't attempt to create or manage route(s) for this Gateway. Also, ignore Gateways with the annotation `istio: egressgateway` as these are not meant to have routes. * Add integration test for IOR Signed-off-by: Jacek Ewertowski * OSSM-1442: IOR: Ignore UPDATE events if resourceVersions are the same (#516) * OSSM-1442: IOR: Ignore UPDATE events if resourceVersions are the same For some obscure reason, it looks like we may receive UPDATE events with the new object being equal to the old one. As IOR always delete and recreate routes when receiving an UPDATE event, this might lead to some service downtime, given for a few moments the route will not exist. We guard against this behavior by comparing the `resourceVersion` field of the new object and the one stored in the Route object. * Add test Co-authored-by: Brian Avery Co-authored-by: Jonh Wendell Fix debug log formatting OSSM-1800: Copy gateway labels to routes Simplify the comparison of resource versions We store the gateway resource version (the whole metadata actually) in the `syncRoute` object. There's no need to loop over the routes to perform the comparison. This also fix the corner case where the gateway has one host and for some reason OCP rejects the creation of the route (e.g., when hostname is already taken). In this case the `syncRoute` object exists with zero routes in it. Thus the loop is a no-op and the function wrongly returns with an error of `eventDuplicatedMessage`. By comparing directly using the `syncRoute.metadata` we fix this. OSSM-1105: Support namespace portion in gateway hostnames They are not used by routes, so we essentially ignore the namespace part - anything on the left side of a "namespace/hostname" string. OSSM-1650 Make sure initialSync and event loop behave the same (#551) --- go.mod | 5 +- go.sum | 13 +- .../github.com/openshift/client-go/LICENSE | 191 ++ pilot/pkg/bootstrap/configcontroller.go | 29 + pilot/pkg/config/kube/ior/client.go | 59 + pilot/pkg/config/kube/ior/fake.go | 255 ++ pilot/pkg/config/kube/ior/ior.go | 100 + pilot/pkg/config/kube/ior/ior_test.go | 777 +++++ pilot/pkg/config/kube/ior/route.go | 624 ++++ pilot/pkg/features/pilot.go | 3 + pilot/pkg/leaderelection/leaderelection.go | 1 + pkg/kube/client.go | 2 +- tests/integration/servicemesh/main_test.go | 2 + .../servicemesh/maistra/maistra.go | 187 +- .../integration/servicemesh/router/router.go | 52 + .../router/testdata/route_crd.yaml | 44 + .../servicemesh/router/testdata/router.yaml | 54 + .../router/testdata/router_rbac.yaml | 68 + tests/integration/servicemesh/smmr_test.go | 83 +- .../github.com/openshift/api/route/v1/doc.go | 8 + .../openshift/api/route/v1/generated.pb.go | 3039 +++++++++++++++++ .../openshift/api/route/v1/generated.proto | 241 ++ .../openshift/api/route/v1/legacy.go | 22 + .../openshift/api/route/v1/register.go | 39 + .../openshift/api/route/v1/types.go | 280 ++ .../api/route/v1/zz_generated.deepcopy.go | 240 ++ .../v1/zz_generated.swagger_doc_generated.go | 128 + vendor/github.com/openshift/client-go/LICENSE | 191 ++ .../route/clientset/versioned/scheme/doc.go | 4 + .../clientset/versioned/scheme/register.go | 40 + .../clientset/versioned/typed/route/v1/doc.go | 4 + .../typed/route/v1/generated_expansion.go | 5 + .../versioned/typed/route/v1/route.go | 179 + .../versioned/typed/route/v1/route_client.go | 73 + vendor/modules.txt | 9 +- 35 files changed, 6944 insertions(+), 107 deletions(-) create mode 100644 licenses/github.com/openshift/client-go/LICENSE create mode 100644 pilot/pkg/config/kube/ior/client.go create mode 100644 pilot/pkg/config/kube/ior/fake.go create mode 100644 pilot/pkg/config/kube/ior/ior.go create mode 100644 pilot/pkg/config/kube/ior/ior_test.go create mode 100644 pilot/pkg/config/kube/ior/route.go create mode 100644 tests/integration/servicemesh/router/router.go create mode 100644 tests/integration/servicemesh/router/testdata/route_crd.yaml create mode 100644 tests/integration/servicemesh/router/testdata/router.yaml create mode 100644 tests/integration/servicemesh/router/testdata/router_rbac.yaml create mode 100644 vendor/github.com/openshift/api/route/v1/doc.go create mode 100644 vendor/github.com/openshift/api/route/v1/generated.pb.go create mode 100644 vendor/github.com/openshift/api/route/v1/generated.proto create mode 100644 vendor/github.com/openshift/api/route/v1/legacy.go create mode 100644 vendor/github.com/openshift/api/route/v1/register.go create mode 100644 vendor/github.com/openshift/api/route/v1/types.go create mode 100644 vendor/github.com/openshift/api/route/v1/zz_generated.deepcopy.go create mode 100644 vendor/github.com/openshift/api/route/v1/zz_generated.swagger_doc_generated.go create mode 100644 vendor/github.com/openshift/client-go/LICENSE create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go create mode 100644 vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go diff --git a/go.mod b/go.mod index 4cdd5020593..28dcc37e79e 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,8 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/moby/buildkit v0.10.1 github.com/onsi/gomega v1.19.0 - github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd + github.com/openshift/api v0.0.0-20200929171550-c99a4deebbe5 + github.com/openshift/client-go v0.0.0-20200929181438-91d71ef2122c github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_model v0.2.0 @@ -65,6 +66,7 @@ require ( github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.11.0 + github.com/stretchr/testify v1.7.1 github.com/vishvananda/netlink v1.2.0-beta github.com/yl2chen/cidranger v1.0.2 go.opencensus.io v0.23.0 @@ -218,7 +220,6 @@ require ( github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - github.com/stretchr/testify v1.7.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/vbatts/tar-split v0.11.2 // indirect github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect diff --git a/go.sum b/go.sum index aaed07e6a5d..5941bddecc5 100644 --- a/go.sum +++ b/go.sum @@ -1570,9 +1570,11 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd h1:MV2FH/cm1wqoVCIL98GT46CMnXZw9faUoIzdZ4nfZw0= -github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd/go.mod h1:vWmWTm4y7XR3wkLR+bDDjRbvkBfx2yP7yve6kfb7+Ts= -github.com/openshift/build-machinery-go v0.0.0-20200713135615-1f43d26dccc7/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= +github.com/openshift/api v0.0.0-20200929171550-c99a4deebbe5 h1:ZyeIVj2qV9fNF4SKVMAIhCSdGOnQcOxYDah2wXVqeiY= +github.com/openshift/api v0.0.0-20200929171550-c99a4deebbe5/go.mod h1:Si/I9UGeRR3qzg01YWPmtlr0GeGk2fnuggXJRmjAZ6U= +github.com/openshift/build-machinery-go v0.0.0-20200819073603-48aa266c95f7/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= +github.com/openshift/client-go v0.0.0-20200929181438-91d71ef2122c h1:DQTWW8DGRN7fu5qwEPcbdP9hAxXi7dm5cvi0hrdR3UE= +github.com/openshift/client-go v0.0.0-20200929181438-91d71ef2122c/go.mod h1:MwESrlhzumQGcGtPCpz/WjDrlvhu1fMNlLBcNYjO0fY= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -2548,7 +2550,6 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200102140908-9497f49d5709/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200115044656-831fdb1e1868/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -2953,7 +2954,6 @@ istio.io/pkg v0.0.0-20220728185106-cbb9bd2a0124/go.mod h1:kcBYN5TiyGFM2bs4b7K81j k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= @@ -2981,7 +2981,6 @@ k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9 k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= k8s.io/apimachinery v0.18.1/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= @@ -3032,9 +3031,9 @@ k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= k8s.io/cloud-provider v0.17.4/go.mod h1:XEjKDzfD+b9MTLXQFlDGkk6Ho8SGMpaU8Uugx/KNK9U= k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= diff --git a/licenses/github.com/openshift/client-go/LICENSE b/licenses/github.com/openshift/client-go/LICENSE new file mode 100644 index 00000000000..c4ea8b6f9d8 --- /dev/null +++ b/licenses/github.com/openshift/client-go/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2014 Red Hat, Inc. + + 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. diff --git a/pilot/pkg/bootstrap/configcontroller.go b/pilot/pkg/bootstrap/configcontroller.go index b3c0f1ffff9..100e5c667fb 100644 --- a/pilot/pkg/bootstrap/configcontroller.go +++ b/pilot/pkg/bootstrap/configcontroller.go @@ -24,6 +24,7 @@ import ( "istio.io/istio/pilot/pkg/config/kube/gateway" "istio.io/istio/pilot/pkg/config/kube/ingress" ingressv1 "istio.io/istio/pilot/pkg/config/kube/ingressv1" + "istio.io/istio/pilot/pkg/config/kube/ior" "istio.io/istio/pilot/pkg/config/memory" configmonitor "istio.io/istio/pilot/pkg/config/monitor" "istio.io/istio/pilot/pkg/controller/workloadentry" @@ -140,6 +141,8 @@ func (s *Server) initConfigController(args *PilotArgs) error { // Create the config store. s.environment.ConfigStore = model.MakeIstioStore(s.configController) + s.startIOR(args) + // Defer starting the controller until after the service is created. s.addStartFunc(func(stop <-chan struct{}) error { go s.configController.Run(stop) @@ -149,6 +152,32 @@ func (s *Server) initConfigController(args *PilotArgs) error { return nil } +// startIOR tries to start IOR, if it's enabled. If it encounters any failure, it logs an error and continue +func (s *Server) startIOR(args *PilotArgs) { + if !features.EnableIOR { + return + } + + routerClient, err := ior.NewRouterClient() + if err != nil { + ior.IORLog.Errorf("error creating an openshift router client: %v", err) + return + } + + iorKubeClient := ior.NewKubeClient(s.kubeClient) + + s.addStartFunc(func(stop <-chan struct{}) error { + go leaderelection. + NewLeaderElection(args.Namespace, args.PodName, leaderelection.IORController, args.Revision, s.kubeClient). + AddRunFunction(func(stop <-chan struct{}) { + if err := ior.Register(iorKubeClient, routerClient, s.configController, args.Namespace, s.kubeClient.GetMemberRoll(), stop, nil); err != nil { + ior.IORLog.Error(err) + } + }).Run(stop) + return nil + }) +} + func (s *Server) initK8SConfigStore(args *PilotArgs) error { if s.kubeClient == nil { return nil diff --git a/pilot/pkg/config/kube/ior/client.go b/pilot/pkg/config/kube/ior/client.go new file mode 100644 index 00000000000..5314b06f652 --- /dev/null +++ b/pilot/pkg/config/kube/ior/client.go @@ -0,0 +1,59 @@ +// Copyright Red Hat, Inc. +// +// 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 ior + +import ( + "strings" + "time" + + "istio.io/istio/pkg/kube" +) + +// KubeClient is an extension of `kube.Client` with auxiliary functions for IOR +type KubeClient interface { + IsRouteSupported() bool + GetActualClient() kube.Client + GetHandleEventTimeout() time.Duration +} + +type kubeClient struct { + client kube.Client +} + +// NewKubeClient creates the IOR version of KubeClient +func NewKubeClient(client kube.Client) KubeClient { + return &kubeClient{client: client} +} + +func (c *kubeClient) IsRouteSupported() bool { + _, s, _ := c.client.Kube().Discovery().ServerGroupsAndResources() + // This may fail if any api service is down, but the result will still be populated, so we skip the error + for _, res := range s { + for _, api := range res.APIResources { + if api.Kind == "Route" && strings.HasPrefix(res.GroupVersion, "route.openshift.io/") { + return true + } + } + } + return false +} + +func (c *kubeClient) GetActualClient() kube.Client { + return c.client +} + +func (c *kubeClient) GetHandleEventTimeout() time.Duration { + return 10 * time.Second +} diff --git a/pilot/pkg/config/kube/ior/fake.go b/pilot/pkg/config/kube/ior/fake.go new file mode 100644 index 00000000000..34d837b479a --- /dev/null +++ b/pilot/pkg/config/kube/ior/fake.go @@ -0,0 +1,255 @@ +// Copyright Red Hat, Inc. +// +// 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 ior + +import ( + "fmt" + "strings" + "sync" + "time" + + v1 "github.com/openshift/api/route/v1" + routev1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/rest" + + "istio.io/istio/pkg/kube" + "istio.io/istio/pkg/servicemesh/controller" +) + +// FakeRouter implements routev1.RouteInterface +type FakeRouter struct { + routes map[string]*v1.Route + routesLock sync.Mutex +} + +// FakeRouterClient implements routev1.RouteV1Interface +type FakeRouterClient struct { + routesByNamespace map[string]routev1.RouteInterface + routesByNamespaceLock sync.Mutex +} + +type fakeKubeClient struct { + client kube.Client +} + +// NewFakeKubeClient creates a new FakeKubeClient +func NewFakeKubeClient(client kube.Client) KubeClient { + return &fakeKubeClient{client: client} +} + +func (c *fakeKubeClient) IsRouteSupported() bool { + return true +} + +func (c *fakeKubeClient) GetActualClient() kube.Client { + return c.client +} + +func (c *fakeKubeClient) GetHandleEventTimeout() time.Duration { + return time.Millisecond +} + +// NewFakeRouterClient creates a new FakeRouterClient +func NewFakeRouterClient() routev1.RouteV1Interface { + return &FakeRouterClient{ + routesByNamespace: make(map[string]routev1.RouteInterface), + } +} + +// NewFakeRouter creates a new FakeRouter +func NewFakeRouter() routev1.RouteInterface { + return &FakeRouter{ + routes: make(map[string]*v1.Route), + } +} + +// RESTClient implements routev1.RouteV1Interface +func (rc *FakeRouterClient) RESTClient() rest.Interface { + panic("not implemented") +} + +// Routes implements routev1.RouteV1Interface +func (rc *FakeRouterClient) Routes(namespace string) routev1.RouteInterface { + rc.routesByNamespaceLock.Lock() + defer rc.routesByNamespaceLock.Unlock() + + if _, ok := rc.routesByNamespace[namespace]; !ok { + rc.routesByNamespace[namespace] = NewFakeRouter() + } + + countCallsIncrement("routes") + return rc.routesByNamespace[namespace] +} + +var generatedHostNumber int + +// Create implements routev1.RouteInterface +func (fk *FakeRouter) Create(ctx context.Context, route *v1.Route, opts metav1.CreateOptions) (*v1.Route, error) { + fk.routesLock.Lock() + defer fk.routesLock.Unlock() + + if strings.Contains(route.Spec.Host, "/") { + return nil, fmt.Errorf("invalid hostname") + } + + if route.Spec.Host == "" { + generatedHostNumber++ + route.Spec.Host = fmt.Sprintf("generated-host%d.com", generatedHostNumber) + } + + fk.routes[route.Name] = route + + countCallsIncrement("create") + return route, nil +} + +// Update implements routev1.RouteInterface +func (fk *FakeRouter) Update(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (*v1.Route, error) { + panic("not implemented") +} + +// UpdateStatus implements routev1.RouteInterface +func (fk *FakeRouter) UpdateStatus(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (*v1.Route, error) { + panic("not implemented") +} + +// Delete implements routev1.RouteInterface +func (fk *FakeRouter) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + fk.routesLock.Lock() + defer fk.routesLock.Unlock() + + if _, ok := fk.routes[name]; !ok { + return fmt.Errorf("route %s not found", name) + } + + delete(fk.routes, name) + + countCallsIncrement("delete") + return nil +} + +// DeleteCollection implements routev1.RouteInterface +func (fk *FakeRouter) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + panic("not implemented") +} + +// Get implements routev1.RouteInterface +func (fk *FakeRouter) Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Route, error) { + panic("not implemented") +} + +// List implements routev1.RouteInterface +func (fk *FakeRouter) List(ctx context.Context, opts metav1.ListOptions) (*v1.RouteList, error) { + fk.routesLock.Lock() + defer fk.routesLock.Unlock() + + var items []v1.Route + for _, route := range fk.routes { + items = append(items, *route) + } + result := &v1.RouteList{Items: items} + + countCallsIncrement("list") + return result, nil +} + +// Watch Create implements routev1.RouteInterface +func (fk *FakeRouter) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + panic("not implemented") +} + +// Patch implements routev1.RouteInterface +func (fk *FakeRouter) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, + subresources ...string, +) (result *v1.Route, err error) { + panic("not implemented") +} + +// fakeMemberRollController implements controller.MemberRollController +type fakeMemberRollController struct { + listeners []controller.MemberRollListener + namespaces []string + lock sync.Mutex +} + +func newFakeMemberRollController() *fakeMemberRollController { + return &fakeMemberRollController{} +} + +// Register implements controller.MemberRollController +func (fk *fakeMemberRollController) Register(listener controller.MemberRollListener, name string) { + fk.lock.Lock() + defer fk.lock.Unlock() + + if listener == nil { + return + } + fk.listeners = append(fk.listeners, listener) +} + +// Start implements controller.MemberRollController +func (fk *fakeMemberRollController) Start(stopCh <-chan struct{}) { + panic("not implemented") +} + +func (fk *fakeMemberRollController) addNamespaces(namespaces ...string) { + fk.namespaces = append(fk.namespaces, namespaces...) + fk.invokeListeners() +} + +func (fk *fakeMemberRollController) setNamespaces(namespaces ...string) { + fk.namespaces = namespaces + fk.invokeListeners() +} + +func (fk *fakeMemberRollController) invokeListeners() { + fk.lock.Lock() + defer fk.lock.Unlock() + + for _, l := range fk.listeners { + l.SetNamespaces(fk.namespaces...) + } +} + +var ( + countCalls = map[string]int{} + countCallsLock sync.Mutex +) + +func countCallsReset() { + countCallsLock.Lock() + defer countCallsLock.Unlock() + countCalls = map[string]int{} +} + +func countCallsGet(k string) int { + countCallsLock.Lock() + defer countCallsLock.Unlock() + v, ok := countCalls[k] + if !ok { + v = 0 + } + return v +} + +func countCallsIncrement(k string) { + countCallsLock.Lock() + defer countCallsLock.Unlock() + countCalls[k]++ +} diff --git a/pilot/pkg/config/kube/ior/ior.go b/pilot/pkg/config/kube/ior/ior.go new file mode 100644 index 00000000000..38ac5df5ea9 --- /dev/null +++ b/pilot/pkg/config/kube/ior/ior.go @@ -0,0 +1,100 @@ +// Copyright Red Hat, Inc. +// +// 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 ior + +import ( + "fmt" + "sync" + + routev1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/schema/collections" + "istio.io/istio/pkg/servicemesh/controller" + "istio.io/pkg/log" +) + +// IORLog is IOR-scoped log +var IORLog = log.RegisterScope("ior", "IOR logging", 0) + +// Register configures IOR component to respond to Gateway creations and removals +func Register( + k8sClient KubeClient, + routerClient routev1.RouteV1Interface, + store model.ConfigStoreController, + pilotNamespace string, + mrc controller.MemberRollController, + stop <-chan struct{}, + errorChannel chan error, +) error { + IORLog.Info("Registering IOR component") + + r, err := newRoute(k8sClient, routerClient, store, pilotNamespace, mrc, stop) + if err != nil { + return err + } + r.errorChannel = errorChannel + + alive := true + var aliveLock sync.Mutex + go func(stop <-chan struct{}) { + // Stop responding to events when we are no longer a leader. + // Two notes here: + // (1) There's no such method "UnregisterEventHandler()" + // (2) It might take a few seconds to this channel to be closed. So, both pods might be leader for a few seconds. + <-stop + IORLog.Info("This pod is no longer a leader. IOR stopped responding") + aliveLock.Lock() + alive = false + aliveLock.Unlock() + }(stop) + + IORLog.Debugf("Registering IOR into Istio's Gateway broadcast") + kind := collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind() + store.RegisterEventHandler(kind, func(old, curr config.Config, event model.Event) { + aliveLock.Lock() + defer aliveLock.Unlock() + if !alive { + return + } + + // encapsulate in goroutine to not slow down processing because of waiting for mutex + go func() { + _, ok := curr.Spec.(*networking.Gateway) + if !ok { + IORLog.Errorf("could not decode object as Gateway. Object = %v", curr) + return + } + + debugMessage := fmt.Sprintf("Event %v arrived:", event) + if event == model.EventUpdate { + debugMessage += fmt.Sprintf("\tOld object: %v", old) + } + debugMessage += fmt.Sprintf("\tNew object: %v", curr) + IORLog.Debug(debugMessage) + + if err := r.handleEvent(event, curr); err != nil { + IORLog.Errora(err) + if r.errorChannel != nil { + r.errorChannel <- err + } + } + }() + }) + + return nil +} diff --git a/pilot/pkg/config/kube/ior/ior_test.go b/pilot/pkg/config/kube/ior/ior_test.go new file mode 100644 index 00000000000..8068d159769 --- /dev/null +++ b/pilot/pkg/config/kube/ior/ior_test.go @@ -0,0 +1,777 @@ +// Copyright Red Hat, Inc. +// +// 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 ior + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + routeapiv1 "github.com/openshift/api/route/v1" + routev1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + "github.com/stretchr/testify/assert" + k8sioapicorev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" + + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/config/kube/crdclient" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/schema/collections" + "istio.io/istio/pkg/kube" + memberroll "istio.io/istio/pkg/servicemesh/controller" + "istio.io/istio/pkg/test/util/retry" + "istio.io/pkg/log" +) + +const prefixedLabel = maistraPrefix + "fake" + +func initClients(t *testing.T, + stop <-chan struct{}, + errorChannel chan error, + mrc memberroll.MemberRollController, + register bool, +) (model.ConfigStoreController, KubeClient, routev1.RouteV1Interface) { + t.Helper() + + k8sClient := kube.NewFakeClient() + iorKubeClient := NewFakeKubeClient(k8sClient) + routerClient := NewFakeRouterClient() + store, err := crdclient.New(k8sClient, "", "", false) + if err != nil { + t.Fatal(err) + } + + go store.Run(stop) + k8sClient.RunAndWait(stop) + cache.WaitForCacheSync(stop, store.HasSynced) + retry.UntilSuccessOrFail(t, func() error { + if !store.HasSynced() { + return fmt.Errorf("store has not synced yet") + } + return nil + }, retry.Timeout(time.Second)) + + if register { + if err := Register(iorKubeClient, routerClient, store, "istio-system", mrc, stop, errorChannel); err != nil { + t.Fatal(err) + } + } + + return store, iorKubeClient, routerClient +} + +func TestCreate(t *testing.T) { + cases := []struct { + testName string + ns string + hosts []string + gwSelector map[string]string + expectedRoutes int + expectedError string + tls bool + annotations map[string]string + }{ + { + "One host", + "istio-system", + []string{"one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Two hosts", + "istio-system", + []string{"two.org", "three.com"}, + map[string]string{"istio": "ingressgateway"}, + 2, + "", + false, + nil, + }, + { + "Wildcard 1", + "istio-system", + []string{"*"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Wildcard 2", + "istio-system", + []string{"*.a.com"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Invalid gateway", + "istio-system", + []string{"fail.com"}, + map[string]string{"istio": "nonexistent"}, + 0, + "could not find a service that matches the gateway selector `istio=nonexistent'", + false, + nil, + }, + { + "TLS 1", + "istio-system", + []string{"one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + true, + nil, + }, + { + "Non-existing namespace", + "non-existing", + []string{"fail.com"}, + map[string]string{"istio": "ingressgateway"}, + 0, + "could not handle the ADD event for non-existing", + false, + nil, + }, + { + "Gateway not managed", + "istio-system", + []string{"notmanaged.org"}, + map[string]string{"istio": "ingressgateway"}, + 0, + "", + false, + map[string]string{ShouldManageRouteAnnotation: "false", "foo": "bar"}, + }, + { + "Gateway explicitly managed", + "istio-system", + []string{"explicitlymanaged.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + map[string]string{ShouldManageRouteAnnotation: "TRUE", "foo": "bar"}, + }, + { + "Gateway explicitly managed with an invalid value", + "istio-system", + []string{"explicitlymanaged.org"}, + map[string]string{"istio": "ingressgateway"}, + 0, + fmt.Sprintf("could not parse annotation %q:", ShouldManageRouteAnnotation), + false, + map[string]string{ShouldManageRouteAnnotation: "ABC", "foo": "bar"}, + }, + { + "Egress gateway must be ignored", + "istio-system", + []string{"egress.org"}, + map[string]string{"istio": "egressgateway"}, + 0, + "", + false, + nil, + }, + { + "Host with all namespaces", + "istio-system", + []string{"*/one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Host with current namespace", + "istio-system", + []string{"./one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Host with a specific namespace", + "istio-system", + []string{"ns1/one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + { + "Host with a namespace and wildcard", + "istio-system", + []string{"*/*.one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + nil, + }, + } + + IORLog.SetOutputLevel(log.DebugLevel) + + var stop chan struct{} + var errorChannel chan error + var store model.ConfigStoreController + var k8sClient KubeClient + var routerClient routev1.RouteV1Interface + var mrc *fakeMemberRollController + controlPlaneNs := "istio-system" + + for _, testType := range []string{"initialSync", "events"} { + if testType == "events" { + stop = make(chan struct{}) + defer func() { close(stop) }() + errorChannel = make(chan error) + mrc = newFakeMemberRollController() + store, k8sClient, routerClient = initClients(t, stop, errorChannel, mrc, true) + mrc.setNamespaces(controlPlaneNs) + + createIngressGateway(t, k8sClient.GetActualClient(), controlPlaneNs, map[string]string{"istio": "ingressgateway"}) + } + + for i, c := range cases { + t.Run(testType+"-"+c.testName, func(t *testing.T) { + if testType == "initialSync" { + stop = make(chan struct{}) + defer func() { close(stop) }() + errorChannel = make(chan error) + mrc = newFakeMemberRollController() + store, k8sClient, routerClient = initClients(t, stop, errorChannel, mrc, false) + createIngressGateway(t, k8sClient.GetActualClient(), controlPlaneNs, map[string]string{"istio": "ingressgateway"}) + if err := Register(k8sClient, routerClient, store, controlPlaneNs, mrc, stop, errorChannel); err != nil { + t.Fatal(err) + } + } + gatewayName := fmt.Sprintf("gw%d", i) + createGateway(t, store, c.ns, gatewayName, c.hosts, c.gwSelector, c.tls, c.annotations) + if testType == "initialSync" { + mrc.setNamespaces(controlPlaneNs) + } + list, _ := getRoutes(t, routerClient, controlPlaneNs, c.expectedRoutes, time.Second) + if err := getError(errorChannel); err != nil { + if c.expectedError == "" { + t.Fatal(err) + } + + if !strings.Contains(err.Error(), c.expectedError) { + t.Fatalf("expected error message containing `%s', got: %s", c.expectedError, err.Error()) + } + + // Error is expected and matches the golden string, nothing to do + } else { + if c.expectedError != "" { + t.Fatalf("expected error message containing `%s', got success", c.expectedError) + } + + // Only continue the validation if any route is expected to be created + if c.expectedRoutes > 0 { + validateRoutes(t, c.hosts, list, gatewayName, c.tls) + + // Remove the gateway and expect all routes get removed + deleteGateway(t, store, c.ns, gatewayName) + _, _ = getRoutes(t, routerClient, c.ns, 0, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + } + } + }) + } + } +} + +func validateRoutes(t *testing.T, hosts []string, list *routeapiv1.RouteList, gatewayName string, tls bool) { + for _, host := range hosts { + route := findRouteByHost(list, host) + if route == nil { + t.Fatalf("could not find a route with hostname %s", host) + } + + // Check metadata + if route.Labels[gatewayNameLabel] != gatewayName { + t.Fatalf("wrong label, expecting %s, got %s", gatewayName, route.Annotations[gatewayNameLabel]) + } + if route.Annotations["foo"] != "bar" { + t.Fatal("gateway annotations were not copied to route") + } + if _, found := route.Annotations[ShouldManageRouteAnnotation]; found { + t.Fatalf("annotation %q should not be copied to the route", ShouldManageRouteAnnotation) + } + if route.Labels["foo"] != "bar" { + t.Fatal("gateway labels were not copied to route") + } + if _, found := route.Labels[prefixedLabel]; found { + t.Fatalf("label %q should not be copied to the route", prefixedLabel) + } + + // Check hostname + if host == "*" && route.Spec.Host == "*" { + t.Fatal("Route's host wrongly set to *") + } + if strings.Contains(host, "*.") && !strings.Contains(route.Spec.Host, "wildcard.") { + t.Fatal("Route's host wrongly not set to wildcard.") + } + + // TLS + if tls { + if route.Spec.TLS.InsecureEdgeTerminationPolicy != routeapiv1.InsecureEdgeTerminationPolicyRedirect { + t.Fatalf("wrong InsecureEdgeTerminationPolicy: %v", route.Spec.TLS.InsecureEdgeTerminationPolicy) + } + if route.Spec.TLS.Termination != routeapiv1.TLSTerminationPassthrough { + t.Fatalf("wrong Termination: %v", route.Spec.TLS.Termination) + } + } + } +} + +func TestEdit(t *testing.T) { + cases := []struct { + testName string + ns string + hosts []string + gwSelector map[string]string + expectedRoutes int + expectedError string + tls bool + }{ + { + "One host", + "istio-system", + []string{"def.com"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + }, + { + "Two hosts", + "istio-system", + []string{"ghi.org", "jkl.com"}, + map[string]string{"istio": "ingressgateway"}, + 2, + "", + false, + }, + { + "Wildcard 1", + "istio-system", + []string{"*"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + }, + { + "Wildcard 2", + "istio-system", + []string{"*.a.com"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + false, + }, + { + "TLS 1", + "istio-system", + []string{"one.org"}, + map[string]string{"istio": "ingressgateway"}, + 1, + "", + true, + }, + } + + stop := make(chan struct{}) + defer func() { close(stop) }() + errorChannel := make(chan error) + mrc := newFakeMemberRollController() + store, k8sClient, routerClient := initClients(t, stop, errorChannel, mrc, true) + + controlPlane := "istio-system" + createIngressGateway(t, k8sClient.GetActualClient(), controlPlane, map[string]string{"istio": "ingressgateway"}) + createGateway(t, store, controlPlane, "gw", []string{"abc.com"}, map[string]string{"istio": "ingressgateway"}, false, nil) + mrc.setNamespaces("istio-system") + + list, _ := getRoutes(t, routerClient, controlPlane, 1, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + + for i, c := range cases { + t.Run(c.testName, func(t *testing.T) { + editGateway(t, store, c.ns, "gw", c.hosts, c.gwSelector, c.tls, fmt.Sprintf("%d", i+2)) + list, _ = getRoutes(t, routerClient, controlPlane, c.expectedRoutes, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + + validateRoutes(t, c.hosts, list, "gw", c.tls) + }) + } +} + +// TestPerf makes sure we are not doing more API calls than necessary +func TestPerf(t *testing.T) { + IORLog.SetOutputLevel(log.DebugLevel) + countCallsReset() + + stop := make(chan struct{}) + defer func() { close(stop) }() + errorChannel := make(chan error) + mrc := newFakeMemberRollController() + store, k8sClient, routerClient := initClients(t, stop, errorChannel, mrc, true) + + // Create a bunch of namespaces and gateways, and make sure they don't take too long to be created + createIngressGateway(t, k8sClient.GetActualClient(), "istio-system", map[string]string{"istio": "ingressgateway"}) + qty := 100 + qtyNamespaces := qty + 1 + createGateways(t, store, 1, qty) + mrc.setNamespaces(generateNamespaces(qty)...) + + // It takes ~ 2s on my laptop, it's slower on prow + _, ignore := getRoutes(t, routerClient, "istio-system", qty, time.Minute) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + assert.Equal(t, qty, countCallsGet("create"), "wrong number of calls to client.Routes().Create()") + assert.Equal(t, 0, countCallsGet("delete"), "wrong number of calls to client.Routes().Delete()") + assert.Equal(t, qtyNamespaces, countCallsGet("list")-ignore, "wrong number of calls to client.Routes().List()") + // qty=number of Create() calls; qtyNamespaces=number of List() calls + assert.Equal(t, qty+qtyNamespaces, countCallsGet("routes")-ignore, "wrong number of calls to client.Routes()") + + // Now we have a lot of routes created, let's create one more gateway. We don't expect a lot of new API calls + countCallsReset() + createGateway(t, store, "ns1", "gw-ns1-1", []string{"instant.com"}, map[string]string{"istio": "ingressgateway"}, false, nil) + _, ignore = getRoutes(t, routerClient, "istio-system", qty+1, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + assert.Equal(t, 1, countCallsGet("create"), "wrong number of calls to client.Routes().Create()") + assert.Equal(t, 0, countCallsGet("delete"), "wrong number of calls to client.Routes().Delete()") + assert.Equal(t, 0, countCallsGet("list")-ignore, "wrong number of calls to client.Routes().List()") + assert.Equal(t, 1, countCallsGet("routes")-ignore, "wrong number of calls to client.Routes()") + + // Editing. We don't expect a lot of new API calls + countCallsReset() + editGateway(t, store, "ns1", "gw-ns1-1", []string{"edited.com", "edited-other.com"}, map[string]string{"istio": "ingressgateway"}, false, "2") + _, ignore = getRoutes(t, routerClient, "istio-system", qty+2, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + assert.Equal(t, 2, countCallsGet("create"), "wrong number of calls to client.Routes().Create()") + assert.Equal(t, 1, countCallsGet("delete"), "wrong number of calls to client.Routes().Delete()") + assert.Equal(t, 0, countCallsGet("list")-ignore, "wrong number of calls to client.Routes().List()") + assert.Equal(t, 3, countCallsGet("routes")-ignore, "wrong number of calls to client.Routes()") + + // Same for deletion. We don't expect a lot of new API calls + countCallsReset() + deleteGateway(t, store, "ns1", "gw-ns1-1") + _, ignore = getRoutes(t, routerClient, "istio-system", qty, time.Second) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } + assert.Equal(t, 0, countCallsGet("create"), "wrong number of calls to client.Routes().Create()") + assert.Equal(t, 2, countCallsGet("delete"), "wrong number of calls to client.Routes().Delete()") + assert.Equal(t, 0, countCallsGet("list")-ignore, "wrong number of calls to client.Routes().List()") + assert.Equal(t, 2, countCallsGet("routes")-ignore, "wrong number of calls to client.Routes()") +} + +// TestConcurrency makes sure IOR can respond to events even when doing its initial sync +func TestConcurrency(t *testing.T) { + IORLog.SetOutputLevel(log.DebugLevel) + stop := make(chan struct{}) + defer func() { close(stop) }() + errorChannel := make(chan error) + mrc := newFakeMemberRollController() + store, k8sClient, routerClient := initClients(t, stop, errorChannel, mrc, true) + + // Create a bunch of namespaces and gateways + createIngressGateway(t, k8sClient.GetActualClient(), "istio-system", map[string]string{"istio": "ingressgateway"}) + qty := 50 + createGateways(t, store, 1, qty) + mrc.setNamespaces(generateNamespaces(qty)...) + + // At the same time, while IOR is processing those initial `qty` gateways, create `qty` more + go func() { + mrc.setNamespaces(generateNamespaces(qty * 2)...) + createGateways(t, store, qty+1, qty*2) + }() + + // And expect all `qty * 2` gateways to be created + _, _ = getRoutes(t, routerClient, "istio-system", (qty * 2), time.Minute) + if err := getError(errorChannel); err != nil { + t.Fatal(err) + } +} + +func TestDuplicateUpdateEvents(t *testing.T) { + IORLog.SetOutputLevel(log.DebugLevel) + stop := make(chan struct{}) + defer func() { close(stop) }() + errorChannel := make(chan error) + mrc := newFakeMemberRollController() + store, k8sClient, routerClient := initClients(t, stop, errorChannel, mrc, false) + + r, err := newRoute(k8sClient, routerClient, store, "istio-system", mrc, stop) + if err != nil { + t.Fatal(err) + } + + mrc.setNamespaces("istio-system") + createIngressGateway(t, k8sClient.GetActualClient(), "istio-system", map[string]string{"istio": "ingressgateway"}) + + cfg := config.Config{ + Meta: config.Meta{ + GroupVersionKind: collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind(), + Namespace: "istio-system", + Name: "a", + ResourceVersion: "1", + }, + Spec: &networking.Gateway{ + Servers: []*networking.Server{ + { + Hosts: []string{"a.com"}, + }, + }, + }, + } + + // Create the first router, should work just fine + err = r.handleEvent(model.EventAdd, cfg) + if err != nil { + t.Fatal(err) + } + func() { + r.gatewaysLock.Lock() + defer r.gatewaysLock.Unlock() + if len(r.gatewaysMap) != 1 { + t.Fatal("error creating the first route") + } + }() + + // Simulate an UPDATE event with the same data, should be ignored + err = r.handleEvent(model.EventUpdate, cfg) + if err == nil { + t.Fatalf("expecting the error: %q, but got nothing", eventDuplicatedMessage) + } + if msg := err.Error(); msg != eventDuplicatedMessage { + t.Fatalf("expecting the error: %q, but got %q", eventDuplicatedMessage, msg) + } +} + +func generateNamespaces(qty int) []string { + var result []string + + for i := 1; i <= qty; i++ { + result = append(result, fmt.Sprintf("ns%d", i)) + } + + return append(result, "istio-system") +} + +func createGateways(t *testing.T, store model.ConfigStoreController, begin, end int) { + for i := begin; i <= end; i++ { + createGateway(t, + store, + fmt.Sprintf("ns%d", i), + fmt.Sprintf("gw-ns%d", i), + []string{fmt.Sprintf("d%d.com", i)}, + map[string]string{"istio": "ingressgateway"}, + false, + nil) + } +} + +// getError tries to read an error from the error channel. +// It tries 3 times beforing returning nil, in case of there's no error in the channel, +// this is to give some time to async functions to run and fill the channel properly +func getError(errorChannel chan error) error { + for i := 1; i < 3; i++ { + select { + case err := <-errorChannel: + return err + default: + } + time.Sleep(10 * time.Millisecond) + } + return nil +} + +// getRoutes is a helper function that keeps trying getting a list of routes until it gets `size` items. +// It returns the list of routes itself and the number of retries it run +func getRoutes(t *testing.T, routerClient routev1.RouteV1Interface, ns string, size int, timeout time.Duration) (*routeapiv1.RouteList, int) { + var list *routeapiv1.RouteList + + t.Helper() + count := 0 + + retry.UntilSuccessOrFail(t, func() error { + var err error + + time.Sleep(time.Millisecond * 100) + list, err = routerClient.Routes(ns).List(context.TODO(), v1.ListOptions{}) + count++ + if err != nil { + return err + } + if len(list.Items) != size { + return fmt.Errorf("expected %d route(s), got %d", size, len(list.Items)) + } + return nil + }, retry.Timeout(timeout)) + + return list, count +} + +func findRouteByHost(list *routeapiv1.RouteList, host string) *routeapiv1.Route { + for _, route := range list.Items { + if route.Annotations[originalHostAnnotation] == host { + return &route + } + } + return nil +} + +func createIngressGateway(t *testing.T, client kube.Client, ns string, labels map[string]string) { + t.Helper() + createPod(t, client, ns, labels) + createService(t, client, ns, labels) +} + +func createPod(t *testing.T, client kube.Client, ns string, labels map[string]string) { + t.Helper() + + _, err := client.Kube().CoreV1().Pods(ns).Create(context.TODO(), &k8sioapicorev1.Pod{ + ObjectMeta: v1.ObjectMeta{ + Labels: labels, + }, + }, v1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } +} + +func createService(t *testing.T, client kube.Client, ns string, labels map[string]string) { + t.Helper() + + _, err := client.Kube().CoreV1().Services(ns).Create(context.TODO(), &k8sioapicorev1.Service{ + ObjectMeta: v1.ObjectMeta{ + Labels: labels, + }, + }, v1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } +} + +func createGateway(t *testing.T, store model.ConfigStoreController, ns string, name string, hosts []string, gwSelector map[string]string, + tls bool, annotations map[string]string, +) { + t.Helper() + + var tlsConfig *networking.ServerTLSSettings + if tls { + tlsConfig = &networking.ServerTLSSettings{HttpsRedirect: true} + } + + if annotations == nil { + annotations = map[string]string{"foo": "bar"} + } + + _, err := store.Create(config.Config{ + Meta: config.Meta{ + GroupVersionKind: collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind(), + Namespace: ns, + Name: name, + Annotations: annotations, + Labels: map[string]string{"foo": "bar", prefixedLabel: "present"}, + ResourceVersion: "1", + }, + Spec: &networking.Gateway{ + Selector: gwSelector, + Servers: []*networking.Server{ + { + Hosts: hosts, + Tls: tlsConfig, + }, + }, + }, + }) + if err != nil { + t.Fatal(err) + } +} + +func editGateway(t *testing.T, store model.ConfigStoreController, ns string, name string, hosts []string, + gwSelector map[string]string, tls bool, resource string, +) { + t.Helper() + + var tlsConfig *networking.ServerTLSSettings + if tls { + tlsConfig = &networking.ServerTLSSettings{HttpsRedirect: true} + } + _, err := store.Update(config.Config{ + Meta: config.Meta{ + GroupVersionKind: collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind(), + Namespace: ns, + Name: name, + Annotations: map[string]string{"foo": "bar"}, + Labels: map[string]string{"foo": "bar", prefixedLabel: "present"}, + ResourceVersion: resource, + }, + Spec: &networking.Gateway{ + Selector: gwSelector, + Servers: []*networking.Server{ + { + Hosts: hosts, + Tls: tlsConfig, + }, + }, + }, + }) + if err != nil { + t.Fatal(err) + } +} + +func deleteGateway(t *testing.T, store model.ConfigStoreController, ns string, name string) { + t.Helper() + + err := store.Delete(collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind(), name, ns, nil) + if err != nil { + t.Fatal(err) + } +} diff --git a/pilot/pkg/config/kube/ior/route.go b/pilot/pkg/config/kube/ior/route.go new file mode 100644 index 00000000000..556d607771f --- /dev/null +++ b/pilot/pkg/config/kube/ior/route.go @@ -0,0 +1,624 @@ +// Copyright Red Hat, Inc. +// +// 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 ior + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "strconv" + "strings" + "sync" + "time" + + "github.com/hashicorp/go-multierror" + v1 "github.com/openshift/api/route/v1" + routev1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/schema/collections" + "istio.io/istio/pkg/kube" + "istio.io/istio/pkg/servicemesh/controller" +) + +const ( + maistraPrefix = "maistra.io/" + generatedByLabel = maistraPrefix + "generated-by" + generatedByValue = "ior" + originalHostAnnotation = maistraPrefix + "original-host" + gatewayNameLabel = maistraPrefix + "gateway-name" + gatewayNamespaceLabel = maistraPrefix + "gateway-namespace" + gatewayResourceVersionLabel = maistraPrefix + "gateway-resourceVersion" + ShouldManageRouteAnnotation = maistraPrefix + "manageRoute" + + eventDuplicatedMessage = "event UPDATE arrived but resourceVersions are the same - ignoring" +) + +type syncRoutes struct { + metadata config.Meta + gateway *networking.Gateway + routes []*v1.Route +} + +// route manages the integration between Istio Gateways and OpenShift Routes +type route struct { + pilotNamespace string + routerClient routev1.RouteV1Interface + kubeClient kubernetes.Interface + store model.ConfigStoreController + gatewaysMap map[string]*syncRoutes + gatewaysLock sync.Mutex + initialSyncRun chan struct{} + alive bool + stop <-chan struct{} + handleEventTimeout time.Duration + errorChannel chan error + + // memberroll functionality + mrc controller.MemberRollController + namespaceLock sync.Mutex + namespaces []string + gotInitialUpdate bool +} + +// NewRouterClient returns an OpenShift client for Routers +func NewRouterClient() (routev1.RouteV1Interface, error) { + config, err := kube.BuildClientConfig("", "") + if err != nil { + return nil, err + } + + client, err := routev1.NewForConfig(config) + if err != nil { + return nil, err + } + + return client, nil +} + +// newRoute returns a new instance of Route object +func newRoute( + kubeClient KubeClient, + routerClient routev1.RouteV1Interface, + store model.ConfigStoreController, + pilotNamespace string, + mrc controller.MemberRollController, + stop <-chan struct{}, +) (*route, error) { + if !kubeClient.IsRouteSupported() { + return nil, fmt.Errorf("routes are not supported in this cluster") + } + + r := &route{} + + r.kubeClient = kubeClient.GetActualClient().Kube() + r.routerClient = routerClient + r.pilotNamespace = pilotNamespace + r.store = store + r.mrc = mrc + r.namespaces = []string{pilotNamespace} + r.stop = stop + r.initialSyncRun = make(chan struct{}) + r.handleEventTimeout = kubeClient.GetHandleEventTimeout() + + if r.mrc != nil { + IORLog.Debugf("Registering IOR into SMMR broadcast") + r.alive = true + r.mrc.Register(r, "ior") + + go func(stop <-chan struct{}) { + <-stop + r.alive = false + IORLog.Debugf("Unregistering IOR from SMMR broadcast") + }(stop) + } + + return r, nil +} + +// initialSync runs on initialization only. +// +// It lists all Istio Gateways (source of truth) and OpenShift Routes, compares them and makes the necessary adjustments +// (creation and/or removal of routes) so that gateways and routes be in sync. +func (r *route) initialSync(initialNamespaces []string) error { + var result *multierror.Error + r.gatewaysMap = make(map[string]*syncRoutes) + + r.gatewaysLock.Lock() + defer r.gatewaysLock.Unlock() + + // List the gateways and put them into the gatewaysMap + // The store must be synced otherwise we might get an empty list + // We enforce this before calling this function in UpdateNamespaces() + configs, err := r.store.List(collections.IstioNetworkingV1Alpha3Gateways.Resource().GroupVersionKind(), model.NamespaceAll) + if err != nil { + return fmt.Errorf("could not get list of Gateways: %s", err) + } + IORLog.Debugf("initialSync() - Got %d Gateway(s)", len(configs)) + + for i, cfg := range configs { + if err := r.ensureNamespaceExists(cfg); err != nil { + result = multierror.Append(result, err) + continue + } + manageRoute, err := isManagedByIOR(cfg) + if err != nil { + result = multierror.Append(result, err) + continue + } + if !manageRoute { + IORLog.Debugf("initialSync() - Ignoring Gateway %s/%s as it is not managed by Istiod", cfg.Namespace, cfg.Name) + continue + } + + IORLog.Debugf("initialSync() - Parsing Gateway [%d] %s/%s", i+1, cfg.Namespace, cfg.Name) + r.addNewSyncRoute(cfg) + } + + // List the routes and put them into a map. Map key is the route object name + routes := map[string]v1.Route{} + for _, ns := range initialNamespaces { + IORLog.Debugf("initialSync() - Listing routes in ns %s", ns) + routeList, err := r.routerClient.Routes(ns).List(context.TODO(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", generatedByLabel, generatedByValue), + }) + if err != nil { + return fmt.Errorf("could not get list of Routes in namespace %s: %s", ns, err) + } + for _, route := range routeList.Items { + routes[route.Name] = route + } + } + IORLog.Debugf("initialSync() - Got %d route(s) across all %d namespace(s)", len(routes), len(initialNamespaces)) + + // Now that we have maps and routes mapped we can compare them (Gateways are the source of truth) + for _, syncRoute := range r.gatewaysMap { + for _, server := range syncRoute.gateway.Servers { + for _, host := range server.Hosts { + actualHost, _ := getActualHost(host, false) + routeName := getRouteName(syncRoute.metadata.Namespace, syncRoute.metadata.Name, actualHost) + route, ok := routes[routeName] + if ok { + // A route for this host was found, remove its entry in this map so that in the end only orphan routes are left + delete(routes, routeName) + + // Route matches, no need to create one. Put it in the gatewaysMap and move to the next one + if syncRoute.metadata.ResourceVersion == route.Labels[gatewayResourceVersionLabel] { + syncRoute.routes = append(syncRoute.routes, &route) + continue + } + + // Route does not match, remove it. + result = multierror.Append(result, r.deleteRoute(&route)) + } + + // Route is not found or was removed above because it didn't match. We need to create one now. + route2, err := r.createRoute(syncRoute.metadata, syncRoute.gateway, host, server.Tls) + if err != nil { + result = multierror.Append(result, err) + } else { + // Put it in the gatewaysMap and move to the next one + syncRoute.routes = append(syncRoute.routes, route2) + } + } + } + } + + // At this point there are routes for every hostname in every Gateway. + // The `routes` map should only contain "orphan" routes, i.e., routes that do not belong to any Gateway + // + for _, route := range routes { + result = multierror.Append(result, r.deleteRoute(&route)) + } + + return result.ErrorOrNil() +} + +func gatewaysMapKey(namespace, name string) string { + return namespace + "/" + name +} + +// addNewSyncRoute creates a new syncRoutes and adds it to the gatewaysMap +// Must be called with gatewaysLock locked +func (r *route) addNewSyncRoute(cfg config.Config) *syncRoutes { + gw := cfg.Spec.(*networking.Gateway) + syncRoute := &syncRoutes{ + metadata: cfg.Meta, + gateway: gw, + } + + r.gatewaysMap[gatewaysMapKey(cfg.Namespace, cfg.Name)] = syncRoute + return syncRoute +} + +// ensureNamespaceExists makes sure the gateway namespace is present in r.namespaces +// r.namespaces is updated by the SMMR controller, in SetNamespaces() +// This handles the case where an ADD event comes before SetNamespaces() is called and +// the unlikely case an ADD event arrives for a gateway whose namespace does not belong to the SMMR at all +func (r *route) ensureNamespaceExists(cfg config.Config) error { + timeout := time.After(r.handleEventTimeout) // production default is 10s, but test default is only 1ms + + for { + r.namespaceLock.Lock() + namespaces := r.namespaces + r.namespaceLock.Unlock() + + for _, ns := range namespaces { + if ns == cfg.Namespace { + IORLog.Debugf("Namespace %s found in SMMR", cfg.Namespace) + return nil + } + } + + select { + case <-timeout: + IORLog.Debugf("Namespace %s not found in SMMR. Aborting.", cfg.Namespace) + return fmt.Errorf("could not handle the ADD event for %s/%s: SMMR does not recognize this namespace", cfg.Namespace, cfg.Name) + default: + IORLog.Debugf("Namespace %s not found in SMMR, trying again", cfg.Namespace) + } + time.Sleep(100 * time.Millisecond) + } +} + +func (r *route) handleAdd(cfg config.Config) error { + var result *multierror.Error + + if err := r.ensureNamespaceExists(cfg); err != nil { + return err + } + + r.gatewaysLock.Lock() + defer r.gatewaysLock.Unlock() + + if _, ok := r.gatewaysMap[gatewaysMapKey(cfg.Namespace, cfg.Name)]; ok { + IORLog.Infof("gateway %s/%s already exists, not creating route(s) for it", cfg.Namespace, cfg.Name) + return nil + } + + syncRoute := r.addNewSyncRoute(cfg) + + for _, server := range syncRoute.gateway.Servers { + for _, host := range server.Hosts { + route, err := r.createRoute(cfg.Meta, syncRoute.gateway, host, server.Tls) + if err != nil { + result = multierror.Append(result, err) + } else { + syncRoute.routes = append(syncRoute.routes, route) + } + } + } + + return result.ErrorOrNil() +} + +func isManagedByIOR(cfg config.Config) (bool, error) { + // We don't manage egress gateways, but we can only look for the default label here. + // Users can still use generic labels (e.g. "app: my-ingressgateway" as in the istio docs) to refer to the gateway pod + gw := cfg.Spec.(*networking.Gateway) + if istioLabel, ok := gw.Selector["istio"]; ok && istioLabel == "egressgateway" { + return false, nil + } + + manageRouteValue, ok := cfg.Annotations[ShouldManageRouteAnnotation] + if !ok { + // Manage routes by default, when annotation is not found. + return true, nil + } + + manageRoute, err := strconv.ParseBool(manageRouteValue) + if err != nil { + return false, fmt.Errorf("could not parse annotation %q: %s", ShouldManageRouteAnnotation, err) + } + + return manageRoute, nil +} + +func (r *route) handleDel(cfg config.Config) error { + var result *multierror.Error + + r.gatewaysLock.Lock() + defer r.gatewaysLock.Unlock() + + key := gatewaysMapKey(cfg.Namespace, cfg.Name) + syncRoute, ok := r.gatewaysMap[key] + if !ok { + return fmt.Errorf("could not find an internal reference to gateway %s/%s", cfg.Namespace, cfg.Name) + } + + IORLog.Debugf("The gateway %s/%s has %d route(s) associated with it. Removing them now.", cfg.Namespace, cfg.Name, len(syncRoute.routes)) + for _, route := range syncRoute.routes { + result = multierror.Append(result, r.deleteRoute(route)) + } + + delete(r.gatewaysMap, key) + + return result.ErrorOrNil() +} + +func (r *route) verifyResourceVersions(cfg config.Config) error { + r.gatewaysLock.Lock() + defer r.gatewaysLock.Unlock() + + key := gatewaysMapKey(cfg.Namespace, cfg.Name) + syncRoute, ok := r.gatewaysMap[key] + if !ok { + return fmt.Errorf("could not find an internal reference to gateway %s/%s", cfg.Namespace, cfg.Name) + } + + if syncRoute.metadata.ResourceVersion != cfg.ResourceVersion { + return nil + } + + return fmt.Errorf(eventDuplicatedMessage) +} + +func (r *route) handleEvent(event model.Event, cfg config.Config) error { + // Block until initial sync has finished + <-r.initialSyncRun + + manageRoute, err := isManagedByIOR(cfg) + if err != nil { + return err + } + if !manageRoute { + IORLog.Infof("Ignoring Gateway %s/%s as it is not managed by Istiod", cfg.Namespace, cfg.Name) + return nil + } + + switch event { + case model.EventAdd: + return r.handleAdd(cfg) + + case model.EventUpdate: + if err = r.verifyResourceVersions(cfg); err != nil { + return err + } + + var result *multierror.Error + result = multierror.Append(result, r.handleDel(cfg)) + result = multierror.Append(result, r.handleAdd(cfg)) + return result.ErrorOrNil() + + case model.EventDelete: + return r.handleDel(cfg) + } + + return fmt.Errorf("unknown event type %s", event) +} + +// Trigerred by SMMR controller when SMMR changes +func (r *route) SetNamespaces(namespaces ...string) { + if !r.alive { + return + } + + IORLog.Debugf("UpdateNamespaces(%v)", namespaces) + r.namespaceLock.Lock() + r.namespaces = namespaces + r.namespaceLock.Unlock() + + if r.gotInitialUpdate { + return + } + r.gotInitialUpdate = true + + // In the first update we perform an initial sync + go func() { + // But only after gateway store cache is synced + IORLog.Debug("Waiting for the Gateway store cache to sync before performing our initial sync") + if !cache.WaitForNamedCacheSync("Gateways", r.stop, r.store.HasSynced) { + IORLog.Infof("Failed to sync Gateway store cache. Not performing initial sync.") + return + } + IORLog.Debug("Gateway store cache synced. Performing our initial sync now") + + if err := r.initialSync(namespaces); err != nil { + IORLog.Errora(err) + if r.errorChannel != nil { + r.errorChannel <- err + } + } + IORLog.Debug("Initial sync finished") + close(r.initialSyncRun) + }() +} + +func getHost(route v1.Route) string { + if host := route.ObjectMeta.Annotations[originalHostAnnotation]; host != "" { + return host + } + return route.Spec.Host +} + +func (r *route) deleteRoute(route *v1.Route) error { + var immediate int64 + host := getHost(*route) + err := r.routerClient.Routes(route.Namespace).Delete(context.TODO(), route.ObjectMeta.Name, metav1.DeleteOptions{GracePeriodSeconds: &immediate}) + if err != nil { + return fmt.Errorf("error deleting route %s/%s: %s", route.ObjectMeta.Namespace, route.ObjectMeta.Name, err) + } + + IORLog.Infof("Deleted route %s/%s (gateway hostname: %s)", route.ObjectMeta.Namespace, route.ObjectMeta.Name, host) + return nil +} + +func (r *route) createRoute(metadata config.Meta, gateway *networking.Gateway, originalHost string, tls *networking.ServerTLSSettings) (*v1.Route, error) { + IORLog.Debugf("Creating route for hostname %s", originalHost) + actualHost, wildcard := getActualHost(originalHost, true) + + var tlsConfig *v1.TLSConfig + targetPort := "http2" + if tls != nil { + tlsConfig = &v1.TLSConfig{Termination: v1.TLSTerminationPassthrough} + targetPort = "https" + if tls.HttpsRedirect { + tlsConfig.InsecureEdgeTerminationPolicy = v1.InsecureEdgeTerminationPolicyRedirect + } + } + + serviceNamespace, serviceName, err := r.findService(gateway) + if err != nil { + return nil, err + } + + // Copy annotations + annotations := map[string]string{ + originalHostAnnotation: originalHost, + } + for keyName, keyValue := range metadata.Annotations { + if !strings.HasPrefix(keyName, "kubectl.kubernetes.io") && keyName != ShouldManageRouteAnnotation { + annotations[keyName] = keyValue + } + } + + // Copy labels + labels := map[string]string{ + generatedByLabel: generatedByValue, + gatewayNamespaceLabel: metadata.Namespace, + gatewayNameLabel: metadata.Name, + gatewayResourceVersionLabel: metadata.ResourceVersion, + } + for keyName, keyValue := range metadata.Labels { + if !strings.HasPrefix(keyName, maistraPrefix) { + labels[keyName] = keyValue + } + } + + nr, err := r.routerClient.Routes(serviceNamespace).Create(context.TODO(), &v1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: getRouteName(metadata.Namespace, metadata.Name, actualHost), + Namespace: serviceNamespace, + Labels: labels, + Annotations: annotations, + }, + Spec: v1.RouteSpec{ + Host: actualHost, + Port: &v1.RoutePort{ + TargetPort: intstr.IntOrString{ + Type: intstr.String, + StrVal: targetPort, + }, + }, + To: v1.RouteTargetReference{ + Name: serviceName, + }, + TLS: tlsConfig, + WildcardPolicy: wildcard, + }, + }, metav1.CreateOptions{}) + if err != nil { + return nil, fmt.Errorf("error creating a route for the host %s (gateway: %s/%s): %s", originalHost, metadata.Namespace, metadata.Name, err) + } + + IORLog.Infof("Created route %s/%s for hostname %s (gateway: %s/%s)", + nr.ObjectMeta.Namespace, nr.ObjectMeta.Name, + nr.Spec.Host, + metadata.Namespace, metadata.Name) + + return nr, nil +} + +// findService tries to find a service that matches with the given gateway selector +// Returns the namespace and service name that is a match, or an error +func (r *route) findService(gateway *networking.Gateway) (string, string, error) { + r.namespaceLock.Lock() + namespaces := r.namespaces + r.namespaceLock.Unlock() + + gwSelector := labels.SelectorFromSet(gateway.Selector) + + for _, ns := range namespaces { + // Get the list of pods that match the gateway selector + podList, err := r.kubeClient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: gwSelector.String()}) + if err != nil { + return "", "", fmt.Errorf("could not get the list of pods in namespace %s: %v", ns, err) + } + + // Get the list of services in this namespace + svcList, err := r.kubeClient.CoreV1().Services(ns).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return "", "", fmt.Errorf("could not get the list of services in namespace %s: %v", ns, err) + } + + // Look for a service whose selector matches the pod labels + for _, pod := range podList.Items { + podLabels := labels.Set(pod.ObjectMeta.Labels) + + for _, svc := range svcList.Items { + svcSelector := labels.SelectorFromSet(svc.Spec.Selector) + if svcSelector.Matches(podLabels) { + return ns, svc.Name, nil + } + } + } + } + + return "", "", fmt.Errorf("could not find a service that matches the gateway selector `%s'. Namespaces where we looked at: %v", + gwSelector.String(), namespaces) +} + +func getRouteName(namespace, name, actualHost string) string { + return fmt.Sprintf("%s-%s-%s", namespace, name, hostHash(actualHost)) +} + +// getActualHost returns the actual hostname to be used in the route +// `emitWarning` should be false when this function is used internally, without user interaction +// It also returns the route's WildcardPolicy based on the hostname +func getActualHost(originalHost string, emitWarning bool) (string, v1.WildcardPolicyType) { + wildcard := v1.WildcardPolicyNone + + if strings.Contains(originalHost, "/") { + originalHost = strings.SplitN(originalHost, "/", 2)[1] + IORLog.Debugf("Hostname contains a namespace part. Ignoring it and considering the %q portion.", originalHost) + } + + actualHost := originalHost + + if originalHost == "*" { + actualHost = "" + if emitWarning { + IORLog.Warn("Hostname * is not supported at the moment. Letting OpenShift create it instead.") + } + } else if strings.HasPrefix(originalHost, "*.") { + // FIXME: Update link below to version 4.5 when it's out + // Wildcards are not enabled by default in OCP 3.x. + // See https://docs.openshift.com/container-platform/3.11/install_config/router/default_haproxy_router.html#using-wildcard-routes + // FIXME(2): Is there a way to check if OCP supports wildcard and print out a warning if not? + wildcard = v1.WildcardPolicySubdomain + actualHost = "wildcard." + strings.TrimPrefix(originalHost, "*.") + } + + return actualHost, wildcard +} + +// hostHash applies a sha256 on the host and truncate it to the first 8 bytes +// This gives enough uniqueness for a given hostname +func hostHash(name string) string { + if name == "" { + name = "star" + } + + hash := sha256.Sum256([]byte(name)) + return hex.EncodeToString(hash[:8]) +} diff --git a/pilot/pkg/features/pilot.go b/pilot/pkg/features/pilot.go index e491d4436a7..b2fc81b8ebb 100644 --- a/pilot/pkg/features/pilot.go +++ b/pilot/pkg/features/pilot.go @@ -633,6 +633,9 @@ var ( CanonicalServiceForMeshExternalServiceEntry = env.RegisterBoolVar("LABEL_CANONICAL_SERVICES_FOR_MESH_EXTERNAL_SERVICE_ENTRIES", false, "If enabled, metadata representing canonical services for ServiceEntry resources with a location of mesh_external will be populated"+ "in the cluster metadata for those endpoints.").Get() + + EnableIOR = env.RegisterBoolVar("ENABLE_IOR", false, + "Whether to enable IOR component, which provides integration between Istio Gateways and OpenShift Routes").Get() ) // EnableEndpointSliceController returns the value of the feature flag and whether it was actually specified. diff --git a/pilot/pkg/leaderelection/leaderelection.go b/pilot/pkg/leaderelection/leaderelection.go index be2e500b289..d340823f338 100644 --- a/pilot/pkg/leaderelection/leaderelection.go +++ b/pilot/pkg/leaderelection/leaderelection.go @@ -50,6 +50,7 @@ const ( GatewayDeploymentController = "istio-gateway-deployment-leader" StatusController = "istio-status-leader" AnalyzeController = "istio-analyze-leader" + IORController = "ior-leader" ) // Leader election key prefix for remote istiod managed clusters diff --git a/pkg/kube/client.go b/pkg/kube/client.go index effe53325f5..050040bbdec 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -569,10 +569,10 @@ func (c *client) RunAndWait(stop <-chan struct{}) { if features.EnableGatewayAPI { c.gatewayapiInformer.Start(stop) } + c.extInformer.Start(stop) if c.memberRoll != nil { c.memberRoll.Start(stop) } - c.extInformer.Start(stop) if c.fastSync { // WaitForCacheSync will virtually never be synced on the first call, as its called immediately after Start() // This triggers a 100ms delay per call, which is often called 2-3 times in a test, delaying tests. diff --git a/tests/integration/servicemesh/main_test.go b/tests/integration/servicemesh/main_test.go index c1c59a4f76c..83bd35dfe1c 100644 --- a/tests/integration/servicemesh/main_test.go +++ b/tests/integration/servicemesh/main_test.go @@ -23,6 +23,7 @@ import ( "istio.io/istio/pkg/test/framework" "istio.io/istio/pkg/test/framework/components/istio" "istio.io/istio/tests/integration/servicemesh/maistra" + "istio.io/istio/tests/integration/servicemesh/router" ) var i istio.Instance @@ -32,6 +33,7 @@ func TestMain(m *testing.M) { framework. NewSuite(m). RequireMaxClusters(1). + Setup(router.InstallOpenShiftRouter). Setup(maistra.ApplyServiceMeshCRDs). Setup(istio.Setup(&i, nil)). Setup(maistra.Install). diff --git a/tests/integration/servicemesh/maistra/maistra.go b/tests/integration/servicemesh/maistra/maistra.go index 260b6b88982..8c279ad57b2 100644 --- a/tests/integration/servicemesh/maistra/maistra.go +++ b/tests/integration/servicemesh/maistra/maistra.go @@ -27,7 +27,7 @@ import ( "strings" "time" - v1 "k8s.io/api/apps/v1" + appsv1 "k8s.io/api/apps/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -106,7 +106,7 @@ func Install(ctx resource.Context) error { if err := applyRolesToMemberNamespaces(ctx.Clusters().Default(), "istio-system"); err != nil { return err } - if err := patchIstiodArgs(kubeClient); err != nil { + if err := patchIstiodArgs(kubeClient, defaultMaistraSettings); err != nil { return err } if _, err := waitForIstiod(kubeClient, istiod.Generation); err != nil { @@ -115,8 +115,82 @@ func Install(ctx resource.Context) error { return nil } -func waitForIstiod(kubeClient kubernetes.Interface, lastSeenGeneration int64) (*v1.Deployment, error) { - var istiod *v1.Deployment +func EnableIOR(ctx resource.Context) error { + kubeClient := ctx.Clusters().Default().Kube() + istiod, err := waitForIstiod(kubeClient, 0) + if err != nil { + return err + } + if err := patchIstiodArgs(kubeClient, enableIOR); err != nil { + return err + } + if _, err := waitForIstiod(kubeClient, istiod.Generation); err != nil { + return err + } + return nil +} + +func ApplyServiceMeshMemberRoll(ctx framework.TestContext, memberNamespaces ...string) error { + memberRollYAML := ` +apiVersion: maistra.io/v1 +kind: ServiceMeshMemberRoll +metadata: + name: default +spec: + members: +` + for _, ns := range memberNamespaces { + memberRollYAML += fmt.Sprintf(" - %s\n", ns) + } + if err := retry.UntilSuccess(func() error { + if err := ctx.ConfigIstio().YAML("istio-system", memberRollYAML).Apply(); err != nil { + return fmt.Errorf("failed to apply SMMR resource: %s", err) + } + return nil + }, retry.Timeout(10*time.Second), retry.Delay(time.Second)); err != nil { + return err + } + + if err := applyRolesToMemberNamespaces(ctx.Clusters().Default(), memberNamespaces...); err != nil { + return err + } + return updateServiceMeshMemberRollStatus(ctx.Clusters().Default(), memberNamespaces...) +} + +func updateServiceMeshMemberRollStatus(c cluster.Cluster, memberNamespaces ...string) error { + client, err := maistrav1.NewForConfig(c.RESTConfig()) + if err != nil { + return fmt.Errorf("failed to create client for maistra resources: %s", err) + } + + return retry.UntilSuccess(func() error { + smmr, err := client.ServiceMeshMemberRolls("istio-system").Get(context.TODO(), "default", metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get SMMR default: %s", err) + } + smmr.Status.ConfiguredMembers = memberNamespaces + _, err = client.ServiceMeshMemberRolls("istio-system").UpdateStatus(context.TODO(), smmr, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to update SMMR default: %s", err) + } + return nil + }, retry.Timeout(10*time.Second)) +} + +func applyRolesToMemberNamespaces(c cluster.Cluster, namespaces ...string) error { + for _, ns := range namespaces { + if err := c.ApplyYAMLFiles( + ns, + filepath.Join(env.IstioSrc, "tests/integration/servicemesh/smmr/testdata/role.yaml"), + filepath.Join(env.IstioSrc, "tests/integration/servicemesh/smmr/testdata/rolebinding.yaml")); err != nil { + return fmt.Errorf("failed to apply Roles and RoleBindings: %s", err) + } + } + return nil +} + +func waitForIstiod(kubeClient kubernetes.Interface, lastSeenGeneration int64) (*appsv1.Deployment, error) { + var istiod *appsv1.Deployment err := retry.UntilSuccess(func() error { var err error istiod, err = kubeClient.AppsV1().Deployments("istio-system").Get(context.TODO(), "istiod", metav1.GetOptions{}) @@ -137,8 +211,18 @@ func waitForIstiod(kubeClient kubernetes.Interface, lastSeenGeneration int64) (* return istiod, nil } -func patchIstiodArgs(kubeClient kubernetes.Interface) error { - patch := `[ +func patchIstiodArgs(kubeClient kubernetes.Interface, patch string) error { + return retry.UntilSuccess(func() error { + _, err := kubeClient.AppsV1().Deployments("istio-system"). + Patch(context.TODO(), "istiod", types.JSONPatchType, []byte(patch), metav1.PatchOptions{}) + if err != nil { + return fmt.Errorf("failed to patch istiod deployment: %v", err) + } + return nil + }, retry.Timeout(10*time.Second), retry.Delay(time.Second)) +} + +const defaultMaistraSettings = `[ { "op": "add", "path": "/spec/template/spec/containers/0/args/1", @@ -163,7 +247,7 @@ func patchIstiodArgs(kubeClient kubernetes.Interface) error { "op": "add", "path": "/spec/template/spec/containers/0/env/1", "value": { - "name": "PILOT_ENABLE_GATEWAY_API", + "name": "ENABLE_IOR", "value": "false" } }, @@ -171,7 +255,7 @@ func patchIstiodArgs(kubeClient kubernetes.Interface) error { "op": "add", "path": "/spec/template/spec/containers/0/env/2", "value": { - "name": "PILOT_ENABLE_GATEWAY_API_STATUS", + "name": "PILOT_ENABLE_GATEWAY_API", "value": "false" } }, @@ -179,7 +263,7 @@ func patchIstiodArgs(kubeClient kubernetes.Interface) error { "op": "add", "path": "/spec/template/spec/containers/0/env/3", "value": { - "name": "PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER", + "name": "PILOT_ENABLE_GATEWAY_API_STATUS", "value": "false" } }, @@ -187,13 +271,21 @@ func patchIstiodArgs(kubeClient kubernetes.Interface) error { "op": "add", "path": "/spec/template/spec/containers/0/env/4", "value": { - "name": "PRIORITIZED_LEADER_ELECTION", + "name": "PILOT_ENABLE_GATEWAY_API_DEPLOYMENT_CONTROLLER", "value": "false" } }, { "op": "add", "path": "/spec/template/spec/containers/0/env/5", + "value": { + "name": "PRIORITIZED_LEADER_ELECTION", + "value": "false" + } + }, + { + "op": "add", + "path": "/spec/template/spec/containers/0/env/6", "value": { "name": "INJECTION_WEBHOOK_CONFIG_NAME", "value": "" @@ -201,78 +293,21 @@ func patchIstiodArgs(kubeClient kubernetes.Interface) error { }, { "op": "add", - "path": "/spec/template/spec/containers/0/env/6", + "path": "/spec/template/spec/containers/0/env/7", "value": { "name": "VALIDATION_WEBHOOK_CONFIG_NAME", "value": "" } } ]` - return retry.UntilSuccess(func() error { - _, err := kubeClient.AppsV1().Deployments("istio-system"). - Patch(context.TODO(), "istiod", types.JSONPatchType, []byte(patch), metav1.PatchOptions{}) - if err != nil { - return fmt.Errorf("failed to patch istiod deployment: %v", err) - } - return nil - }, retry.Timeout(10*time.Second), retry.Delay(time.Second)) -} -func ApplyServiceMeshMemberRoll(ctx framework.TestContext, memberNamespaces ...string) error { - memberRollYAML := ` -apiVersion: maistra.io/v1 -kind: ServiceMeshMemberRoll -metadata: - name: default -spec: - members: -` - for _, ns := range memberNamespaces { - memberRollYAML += fmt.Sprintf(" - %s\n", ns) - } - if err := retry.UntilSuccess(func() error { - if err := ctx.ConfigIstio().YAML("istio-system", memberRollYAML).Apply(); err != nil { - return fmt.Errorf("failed to apply SMMR resource: %s", err) - } - return nil - }, retry.Timeout(10*time.Second), retry.Delay(time.Second)); err != nil { - return err - } - - if err := applyRolesToMemberNamespaces(ctx.Clusters().Default(), memberNamespaces...); err != nil { - return err - } - return updateServiceMeshMemberRollStatus(ctx.Clusters().Default(), memberNamespaces...) -} - -func updateServiceMeshMemberRollStatus(c cluster.Cluster, memberNamespaces ...string) error { - client, err := maistrav1.NewForConfig(c.RESTConfig()) - if err != nil { - return fmt.Errorf("failed to create client for maistra resources: %s", err) - } - - return retry.UntilSuccess(func() error { - smmr, err := client.ServiceMeshMemberRolls("istio-system").Get(context.TODO(), "default", metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("failed to get SMMR default: %s", err) - } - smmr.Status.ConfiguredMembers = memberNamespaces - _, err = client.ServiceMeshMemberRolls("istio-system").UpdateStatus(context.TODO(), smmr, metav1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("failed to update SMMR default: %s", err) - } - return nil - }, retry.Timeout(10*time.Second)) -} - -func applyRolesToMemberNamespaces(c cluster.Cluster, namespaces ...string) error { - for _, ns := range namespaces { - if err := c.ApplyYAMLFiles( - ns, - filepath.Join(env.IstioSrc, "tests/integration/servicemesh/smmr/testdata/role.yaml"), - filepath.Join(env.IstioSrc, "tests/integration/servicemesh/smmr/testdata/rolebinding.yaml")); err != nil { - return fmt.Errorf("failed to apply Roles and RoleBindings: %s", err) +const enableIOR = `[ + { + "op": "replace", + "path": "/spec/template/spec/containers/0/env/1", + "value": { + "name": "ENABLE_IOR", + "value": "true" } } - return nil -} +]` diff --git a/tests/integration/servicemesh/router/router.go b/tests/integration/servicemesh/router/router.go new file mode 100644 index 00000000000..fc1ec4e9627 --- /dev/null +++ b/tests/integration/servicemesh/router/router.go @@ -0,0 +1,52 @@ +//go:build integ +// +build integ + +// +// Copyright Red Hat, Inc. +// +// 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 router + +import ( + "context" + "path/filepath" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "istio.io/istio/pkg/test/env" + "istio.io/istio/pkg/test/framework/resource" +) + +func InstallOpenShiftRouter(ctx resource.Context) error { + c := ctx.Clusters().Default() + openshiftIngressNs := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "openshift-ingress", + }, + } + if _, err := c.Kube().CoreV1().Namespaces().Create(context.Background(), openshiftIngressNs, metav1.CreateOptions{}); err != nil { + return err + } + if err := c.ApplyYAMLFiles("", filepath.Join(env.IstioSrc, "tests/integration/servicemesh/router/testdata/route_crd.yaml")); err != nil { + return err + } + if err := c.ApplyYAMLFiles("", filepath.Join(env.IstioSrc, "tests/integration/servicemesh/router/testdata/router.yaml")); err != nil { + return err + } + if err := c.ApplyYAMLFiles("", filepath.Join(env.IstioSrc, "tests/integration/servicemesh/router/testdata/router_rbac.yaml")); err != nil { + return err + } + return nil +} diff --git a/tests/integration/servicemesh/router/testdata/route_crd.yaml b/tests/integration/servicemesh/router/testdata/route_crd.yaml new file mode 100644 index 00000000000..4d1c5e1f0b0 --- /dev/null +++ b/tests/integration/servicemesh/router/testdata/route_crd.yaml @@ -0,0 +1,44 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: routes.route.openshift.io +spec: + # group name to use for REST API: /apis// + group: route.openshift.io + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - name: Host + type: string + jsonPath: .status.ingress[0].host + - name: Admitted + type: string + jsonPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status + - name: Service + type: string + jsonPath: .spec.to.name + - name: TLS + type: string + jsonPath: .spec.tls.type + subresources: + # enable spec/status + status: {} + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: routes + # singular name to be used as an alias on the CLI and for display + singular: route + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: Route diff --git a/tests/integration/servicemesh/router/testdata/router.yaml b/tests/integration/servicemesh/router/testdata/router.yaml new file mode 100644 index 00000000000..80b31450c61 --- /dev/null +++ b/tests/integration/servicemesh/router/testdata/router.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ingress-router + namespace: openshift-ingress + labels: + k8s-app: ingress-router +spec: + selector: + matchLabels: + k8s-app: ingress-router + template: + metadata: + labels: + k8s-app: ingress-router + spec: + serviceAccountName: ingress-router + containers: + - env: + - name: ROUTER_LISTEN_ADDR + value: 0.0.0.0:1936 + - name: ROUTER_METRICS_TYPE + value: haproxy + - name: ROUTER_SERVICE_HTTPS_PORT + value: "443" + - name: ROUTER_SERVICE_HTTP_PORT + value: "80" + - name: ROUTER_THREADS + value: "4" + image: openshift/origin-haproxy-router:v4.0.0 + livenessProbe: + httpGet: + host: localhost + path: /healthz + port: 1936 + initialDelaySeconds: 10 + name: router + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 1936 + name: stats + protocol: TCP + readinessProbe: + httpGet: + host: localhost + path: healthz/ready + port: 1936 + initialDelaySeconds: 10 + resources: + requests: + cpu: 100m + memory: 256Mi + hostNetwork: true \ No newline at end of file diff --git a/tests/integration/servicemesh/router/testdata/router_rbac.yaml b/tests/integration/servicemesh/router/testdata/router_rbac.yaml new file mode 100644 index 00000000000..ac28607f3fa --- /dev/null +++ b/tests/integration/servicemesh/router/testdata/router_rbac.yaml @@ -0,0 +1,68 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: openshift-ingress-router +rules: + - apiGroups: + - "" + resources: + - namespaces + - services + - endpoints + verbs: + - get + - list + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - list + - watch + - apiGroups: + - route.openshift.io + resources: + - routes/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: openshift-ingress-router +roleRef: + apiGroup: "" + kind: ClusterRole + name: openshift-ingress-router +subjects: + - kind: ServiceAccount + namespace: openshift-ingress + name: ingress-router +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: openshift-ingress-router-auth-delegator +roleRef: + apiGroup: "" + kind: ClusterRole + name: system:auth-delegator +subjects: + - kind: ServiceAccount + namespace: openshift-ingress + name: ingress-router + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-ingress +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ingress-router + namespace: openshift-ingress diff --git a/tests/integration/servicemesh/smmr_test.go b/tests/integration/servicemesh/smmr_test.go index a9cab087059..0ea5165fbc2 100644 --- a/tests/integration/servicemesh/smmr_test.go +++ b/tests/integration/servicemesh/smmr_test.go @@ -21,9 +21,14 @@ import ( "context" "encoding/json" "fmt" + "strings" "testing" "time" + routeapiv1 "github.com/openshift/api/route/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "istio.io/istio/pilot/pkg/config/kube/ior" "istio.io/istio/pkg/test/framework" "istio.io/istio/pkg/test/framework/components/istioctl" "istio.io/istio/pkg/test/framework/components/namespace" @@ -31,6 +36,8 @@ import ( "istio.io/istio/tests/integration/servicemesh/maistra" ) +const gatewayName = "common-gateway" + func TestSMMR(t *testing.T) { framework.NewTest(t). Run(func(ctx framework.TestContext) { @@ -41,20 +48,29 @@ func TestSMMR(t *testing.T) { applyVirtualServiceOrFail(ctx, namespaceA, namespaceGateway, "a") applyVirtualServiceOrFail(ctx, namespaceB, namespaceGateway, "b") - if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceA); err != nil { - ctx.Fatalf("failed to create ServiceMeshMemberRoll: %s", err) - } - verifyThatIngressHasVirtualHostForMember(ctx, "a") + ctx.NewSubTest("JoiningMesh").Run(func(t framework.TestContext) { + if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceA); err != nil { + t.Fatalf("failed to create ServiceMeshMemberRoll: %s", err) + } + verifyThatIngressHasVirtualHostForMember(t, "a") - if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceA, namespaceB); err != nil { - ctx.Fatalf("failed to add member to ServiceMeshMemberRoll: %s", err) - } - verifyThatIngressHasVirtualHostForMember(ctx, "a", "b") + if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceA, namespaceB); err != nil { + t.Fatalf("failed to add member to ServiceMeshMemberRoll: %s", err) + } + verifyThatIngressHasVirtualHostForMember(t, "a", "b") - if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceB); err != nil { - ctx.Fatalf("failed to create ServiceMeshMemberRoll: %s", err) - } - verifyThatIngressHasVirtualHostForMember(ctx, "b") + if err := maistra.ApplyServiceMeshMemberRoll(ctx, namespaceGateway, namespaceB); err != nil { + t.Fatalf("failed to create ServiceMeshMemberRoll: %s", err) + } + verifyThatIngressHasVirtualHostForMember(t, "b") + }) + + ctx.NewSubTest("RouteCreation").Run(func(t framework.TestContext) { + if err := maistra.EnableIOR(t); err != nil { + t.Fatalf("failed to enable IOR: %s", err) + } + verifyThatRouteExistsOrFail(t, namespaceGateway, gatewayName, "a.maistra.io") + }) }) } @@ -94,6 +110,35 @@ func verifyThatIngressHasVirtualHostForMember(ctx framework.TestContext, expecte }, retry.Timeout(10*time.Second)) } +func verifyThatRouteExistsOrFail(ctx framework.TestContext, expectedGwNs, expectedGwName, expectedHost string) { + routerClient, err := ior.NewRouterClient() + if err != nil { + ctx.Fatalf("failed to create Router client: %s", err) + } + var routes *routeapiv1.RouteList + retry.UntilSuccessOrFail(ctx, func() error { + routes, err = routerClient.Routes("istio-system").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to get Routes: %s", err) + } + if len(routes.Items) == 0 { + return fmt.Errorf("no Routes found") + } + return nil + }, retry.Timeout(10*time.Second)) + + found := false + for _, route := range routes.Items { + if route.Spec.Host == expectedHost && strings.HasPrefix(route.Name, fmt.Sprintf("%s-%s-", expectedGwNs, expectedGwName)) { + found = true + break + } + } + if !found { + ctx.Fatalf("failed to find Route for host %s", expectedHost) + } +} + type RouteConfig struct { Name string `json:"name"` VirtualHosts []*VirtualHost `json:"virtualHosts"` @@ -132,11 +177,11 @@ func getPodName(ctx framework.TestContext, namespace, appName string) (string, e } func applyGatewayOrFail(ctx framework.TestContext, ns string, hosts ...string) { - gwYAML := ` + gwYAML := fmt.Sprintf(` apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: - name: common-gateway + name: %s spec: selector: istio: ingressgateway @@ -146,14 +191,14 @@ spec: name: http protocol: HTTP hosts: -` +`, gatewayName) for _, host := range hosts { gwYAML += fmt.Sprintf(" - %s.maistra.io\n", host) } // retry because of flaky validation webhook retry.UntilSuccessOrFail(ctx, func() error { return ctx.ConfigIstio().YAML(ns, gwYAML).Apply() - }, retry.Timeout(3*time.Second)) + }, retry.Timeout(30*time.Second)) } func applyVirtualServiceOrFail(ctx framework.TestContext, ns, gatewayNs, virtualServiceName string) { @@ -166,16 +211,16 @@ spec: hosts: - "%s.maistra.io" gateways: - - %s/common-gateway + - %s/%s http: - route: - destination: host: localhost port: number: 8080 -`, virtualServiceName, virtualServiceName, gatewayNs) +`, virtualServiceName, virtualServiceName, gatewayNs, gatewayName) // retry because of flaky validation webhook retry.UntilSuccessOrFail(ctx, func() error { return ctx.ConfigIstio().YAML(ns, vsYAML).Apply() - }, retry.Timeout(3*time.Second)) + }, retry.Timeout(30*time.Second)) } diff --git a/vendor/github.com/openshift/api/route/v1/doc.go b/vendor/github.com/openshift/api/route/v1/doc.go new file mode 100644 index 00000000000..e56fbbd8d1f --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/doc.go @@ -0,0 +1,8 @@ +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/openshift/origin/pkg/route/apis/route +// +k8s:defaulter-gen=TypeMeta +// +k8s:openapi-gen=true + +// +groupName=route.openshift.io +// Package v1 is the v1 version of the API. +package v1 diff --git a/vendor/github.com/openshift/api/route/v1/generated.pb.go b/vendor/github.com/openshift/api/route/v1/generated.pb.go new file mode 100644 index 00000000000..977fa2618d5 --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/generated.pb.go @@ -0,0 +1,3039 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/openshift/api/route/v1/generated.proto + +package v1 + +import ( + fmt "fmt" + + io "io" + + proto "github.com/gogo/protobuf/proto" + + k8s_io_api_core_v1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +func (m *Route) Reset() { *m = Route{} } +func (*Route) ProtoMessage() {} +func (*Route) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{0} +} +func (m *Route) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Route) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *Route) XXX_Merge(src proto.Message) { + xxx_messageInfo_Route.Merge(m, src) +} +func (m *Route) XXX_Size() int { + return m.Size() +} +func (m *Route) XXX_DiscardUnknown() { + xxx_messageInfo_Route.DiscardUnknown(m) +} + +var xxx_messageInfo_Route proto.InternalMessageInfo + +func (m *RouteIngress) Reset() { *m = RouteIngress{} } +func (*RouteIngress) ProtoMessage() {} +func (*RouteIngress) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{1} +} +func (m *RouteIngress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteIngress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteIngress) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteIngress.Merge(m, src) +} +func (m *RouteIngress) XXX_Size() int { + return m.Size() +} +func (m *RouteIngress) XXX_DiscardUnknown() { + xxx_messageInfo_RouteIngress.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteIngress proto.InternalMessageInfo + +func (m *RouteIngressCondition) Reset() { *m = RouteIngressCondition{} } +func (*RouteIngressCondition) ProtoMessage() {} +func (*RouteIngressCondition) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{2} +} +func (m *RouteIngressCondition) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteIngressCondition) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteIngressCondition) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteIngressCondition.Merge(m, src) +} +func (m *RouteIngressCondition) XXX_Size() int { + return m.Size() +} +func (m *RouteIngressCondition) XXX_DiscardUnknown() { + xxx_messageInfo_RouteIngressCondition.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteIngressCondition proto.InternalMessageInfo + +func (m *RouteList) Reset() { *m = RouteList{} } +func (*RouteList) ProtoMessage() {} +func (*RouteList) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{3} +} +func (m *RouteList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteList) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteList.Merge(m, src) +} +func (m *RouteList) XXX_Size() int { + return m.Size() +} +func (m *RouteList) XXX_DiscardUnknown() { + xxx_messageInfo_RouteList.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteList proto.InternalMessageInfo + +func (m *RoutePort) Reset() { *m = RoutePort{} } +func (*RoutePort) ProtoMessage() {} +func (*RoutePort) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{4} +} +func (m *RoutePort) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutePort) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RoutePort) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutePort.Merge(m, src) +} +func (m *RoutePort) XXX_Size() int { + return m.Size() +} +func (m *RoutePort) XXX_DiscardUnknown() { + xxx_messageInfo_RoutePort.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutePort proto.InternalMessageInfo + +func (m *RouteSpec) Reset() { *m = RouteSpec{} } +func (*RouteSpec) ProtoMessage() {} +func (*RouteSpec) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{5} +} +func (m *RouteSpec) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteSpec) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteSpec.Merge(m, src) +} +func (m *RouteSpec) XXX_Size() int { + return m.Size() +} +func (m *RouteSpec) XXX_DiscardUnknown() { + xxx_messageInfo_RouteSpec.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteSpec proto.InternalMessageInfo + +func (m *RouteStatus) Reset() { *m = RouteStatus{} } +func (*RouteStatus) ProtoMessage() {} +func (*RouteStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{6} +} +func (m *RouteStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteStatus.Merge(m, src) +} +func (m *RouteStatus) XXX_Size() int { + return m.Size() +} +func (m *RouteStatus) XXX_DiscardUnknown() { + xxx_messageInfo_RouteStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteStatus proto.InternalMessageInfo + +func (m *RouteTargetReference) Reset() { *m = RouteTargetReference{} } +func (*RouteTargetReference) ProtoMessage() {} +func (*RouteTargetReference) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{7} +} +func (m *RouteTargetReference) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteTargetReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouteTargetReference) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteTargetReference.Merge(m, src) +} +func (m *RouteTargetReference) XXX_Size() int { + return m.Size() +} +func (m *RouteTargetReference) XXX_DiscardUnknown() { + xxx_messageInfo_RouteTargetReference.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteTargetReference proto.InternalMessageInfo + +func (m *RouterShard) Reset() { *m = RouterShard{} } +func (*RouterShard) ProtoMessage() {} +func (*RouterShard) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{8} +} +func (m *RouterShard) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouterShard) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *RouterShard) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouterShard.Merge(m, src) +} +func (m *RouterShard) XXX_Size() int { + return m.Size() +} +func (m *RouterShard) XXX_DiscardUnknown() { + xxx_messageInfo_RouterShard.DiscardUnknown(m) +} + +var xxx_messageInfo_RouterShard proto.InternalMessageInfo + +func (m *TLSConfig) Reset() { *m = TLSConfig{} } +func (*TLSConfig) ProtoMessage() {} +func (*TLSConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_373b8fa7ff738721, []int{9} +} +func (m *TLSConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TLSConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TLSConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_TLSConfig.Merge(m, src) +} +func (m *TLSConfig) XXX_Size() int { + return m.Size() +} +func (m *TLSConfig) XXX_DiscardUnknown() { + xxx_messageInfo_TLSConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_TLSConfig proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Route)(nil), "github.com.openshift.api.route.v1.Route") + proto.RegisterType((*RouteIngress)(nil), "github.com.openshift.api.route.v1.RouteIngress") + proto.RegisterType((*RouteIngressCondition)(nil), "github.com.openshift.api.route.v1.RouteIngressCondition") + proto.RegisterType((*RouteList)(nil), "github.com.openshift.api.route.v1.RouteList") + proto.RegisterType((*RoutePort)(nil), "github.com.openshift.api.route.v1.RoutePort") + proto.RegisterType((*RouteSpec)(nil), "github.com.openshift.api.route.v1.RouteSpec") + proto.RegisterType((*RouteStatus)(nil), "github.com.openshift.api.route.v1.RouteStatus") + proto.RegisterType((*RouteTargetReference)(nil), "github.com.openshift.api.route.v1.RouteTargetReference") + proto.RegisterType((*RouterShard)(nil), "github.com.openshift.api.route.v1.RouterShard") + proto.RegisterType((*TLSConfig)(nil), "github.com.openshift.api.route.v1.TLSConfig") +} + +func init() { + proto.RegisterFile("github.com/openshift/api/route/v1/generated.proto", fileDescriptor_373b8fa7ff738721) +} + +var fileDescriptor_373b8fa7ff738721 = []byte{ + // 1163 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xfa, 0x5f, 0xe2, 0x71, 0x1b, 0xc8, 0x40, 0xa9, 0x1b, 0x29, 0x76, 0xba, 0x07, 0x94, + 0xa2, 0xb2, 0x4b, 0x42, 0x81, 0x4a, 0x88, 0x43, 0x9d, 0x22, 0x48, 0xe3, 0xa4, 0xd1, 0xd8, 0xa2, + 0xa2, 0xea, 0x81, 0xc9, 0xee, 0x78, 0x3d, 0xd8, 0x9e, 0x5d, 0x66, 0xc6, 0x29, 0xbe, 0xa0, 0x4a, + 0x7c, 0x81, 0xf2, 0x6d, 0xb8, 0x73, 0xc9, 0xb1, 0xc7, 0x1e, 0x90, 0x45, 0xcc, 0x91, 0x6f, 0x90, + 0x13, 0x9a, 0xd9, 0xb1, 0x77, 0xed, 0x38, 0xa9, 0x0b, 0xb7, 0xdd, 0xf7, 0x7e, 0xbf, 0xdf, 0x7b, + 0xf3, 0xde, 0x9b, 0x37, 0x60, 0x3b, 0xa0, 0xb2, 0xdd, 0x3f, 0x76, 0xbc, 0xb0, 0xe7, 0x86, 0x11, + 0x61, 0xa2, 0x4d, 0x5b, 0xd2, 0xc5, 0x11, 0x75, 0x79, 0xd8, 0x97, 0xc4, 0x3d, 0xd9, 0x76, 0x03, + 0xc2, 0x08, 0xc7, 0x92, 0xf8, 0x4e, 0xc4, 0x43, 0x19, 0xc2, 0xdb, 0x09, 0xc5, 0x99, 0x50, 0x1c, + 0x1c, 0x51, 0x47, 0x53, 0x9c, 0x93, 0xed, 0xf5, 0x8f, 0x53, 0xaa, 0x41, 0x18, 0x84, 0xae, 0x66, + 0x1e, 0xf7, 0x5b, 0xfa, 0x4f, 0xff, 0xe8, 0xaf, 0x58, 0x71, 0xdd, 0xee, 0xdc, 0x17, 0x0e, 0x0d, + 0x75, 0x58, 0x2f, 0xe4, 0xf3, 0xa2, 0xae, 0xdf, 0x4b, 0x30, 0x3d, 0xec, 0xb5, 0x29, 0x23, 0x7c, + 0xe0, 0x46, 0x9d, 0x40, 0x19, 0x84, 0xdb, 0x23, 0x12, 0xcf, 0x63, 0x7d, 0x7e, 0x19, 0x8b, 0xf7, + 0x99, 0xa4, 0x3d, 0xe2, 0x0a, 0xaf, 0x4d, 0x7a, 0xf8, 0x02, 0xef, 0xd3, 0xcb, 0x78, 0x7d, 0x49, + 0xbb, 0x2e, 0x65, 0x52, 0x48, 0x3e, 0x4b, 0xb2, 0x7f, 0xcb, 0x80, 0x3c, 0x52, 0x25, 0x80, 0x3f, + 0x80, 0x15, 0x95, 0x91, 0x8f, 0x25, 0x2e, 0x5b, 0x9b, 0xd6, 0x56, 0x69, 0xe7, 0x13, 0x27, 0x56, + 0x74, 0xd2, 0x8a, 0x4e, 0xd4, 0x09, 0x94, 0x41, 0x38, 0x0a, 0xed, 0x9c, 0x6c, 0x3b, 0x8f, 0x8f, + 0x7f, 0x24, 0x9e, 0x3c, 0x20, 0x12, 0xd7, 0xe0, 0xe9, 0xb0, 0xba, 0x34, 0x1a, 0x56, 0x41, 0x62, + 0x43, 0x13, 0x55, 0x78, 0x08, 0x72, 0x22, 0x22, 0x5e, 0x39, 0xa3, 0xd5, 0xef, 0x3a, 0x6f, 0xec, + 0x89, 0xa3, 0x33, 0x6b, 0x44, 0xc4, 0xab, 0x5d, 0x33, 0xca, 0x39, 0xf5, 0x87, 0xb4, 0x0e, 0xfc, + 0x0e, 0x14, 0x84, 0xc4, 0xb2, 0x2f, 0xca, 0x59, 0xad, 0xe8, 0x2c, 0xac, 0xa8, 0x59, 0xb5, 0x55, + 0xa3, 0x59, 0x88, 0xff, 0x91, 0x51, 0xb3, 0x7f, 0xcd, 0x82, 0x6b, 0x1a, 0xb7, 0xc7, 0x02, 0x4e, + 0x84, 0x80, 0x9b, 0x20, 0xd7, 0x0e, 0x85, 0xd4, 0x65, 0x29, 0x26, 0xa9, 0x7c, 0x1b, 0x0a, 0x89, + 0xb4, 0x07, 0xee, 0x00, 0xa0, 0x43, 0xf0, 0x43, 0xdc, 0x23, 0xfa, 0x80, 0xc5, 0xa4, 0x18, 0x68, + 0xe2, 0x41, 0x29, 0x14, 0xec, 0x02, 0xe0, 0x85, 0xcc, 0xa7, 0x92, 0x86, 0x4c, 0x1d, 0x21, 0xbb, + 0x55, 0xda, 0xb9, 0xbf, 0xe8, 0x11, 0x4c, 0x6a, 0xbb, 0x63, 0x81, 0x24, 0xda, 0xc4, 0x24, 0x50, + 0x4a, 0x1f, 0x36, 0xc1, 0xea, 0x73, 0xda, 0xf5, 0x3d, 0xcc, 0xfd, 0xa3, 0xb0, 0x4b, 0xbd, 0x41, + 0x39, 0xa7, 0xb3, 0xbc, 0x6b, 0x78, 0xab, 0x4f, 0xa6, 0xbc, 0xe7, 0xc3, 0x2a, 0x9c, 0xb6, 0x34, + 0x07, 0x11, 0x41, 0x33, 0x1a, 0xf0, 0x7b, 0x70, 0x33, 0x3e, 0xd1, 0x2e, 0x66, 0x21, 0xa3, 0x1e, + 0xee, 0xaa, 0xa2, 0x30, 0x55, 0x84, 0xbc, 0x96, 0xaf, 0x1a, 0xf9, 0x9b, 0x68, 0x3e, 0x0c, 0x5d, + 0xc6, 0xb7, 0xff, 0xc9, 0x80, 0x1b, 0x73, 0x8f, 0x0a, 0xbf, 0x02, 0x39, 0x39, 0x88, 0x88, 0x69, + 0xc7, 0x9d, 0x71, 0x3b, 0x54, 0x82, 0xe7, 0xc3, 0xea, 0xad, 0xb9, 0x24, 0x9d, 0xbd, 0xa6, 0xc1, + 0xfa, 0x64, 0x6c, 0xe2, 0x3e, 0xdd, 0x9b, 0x1e, 0x83, 0xf3, 0x61, 0x75, 0xce, 0xdd, 0x76, 0x26, + 0x4a, 0xd3, 0xc3, 0x02, 0x3f, 0x04, 0x05, 0x4e, 0xb0, 0x08, 0x99, 0x1e, 0xc2, 0x62, 0x32, 0x54, + 0x48, 0x5b, 0x91, 0xf1, 0xc2, 0x3b, 0x60, 0xb9, 0x47, 0x84, 0xc0, 0x01, 0x31, 0x85, 0x7f, 0xc7, + 0x00, 0x97, 0x0f, 0x62, 0x33, 0x1a, 0xfb, 0x21, 0x07, 0xb0, 0x8b, 0x85, 0x6c, 0x72, 0xcc, 0x44, + 0x9c, 0x3c, 0x35, 0xf5, 0x2c, 0xed, 0x7c, 0xb4, 0xd8, 0x9d, 0x54, 0x8c, 0xda, 0x07, 0xa3, 0x61, + 0x15, 0xd6, 0x2f, 0x28, 0xa1, 0x39, 0xea, 0xf6, 0xef, 0x16, 0x28, 0xea, 0xc2, 0xd5, 0xa9, 0x90, + 0xf0, 0xd9, 0x85, 0x5d, 0xe0, 0x2c, 0x16, 0x57, 0xb1, 0xf5, 0x26, 0x78, 0xd7, 0x9c, 0x6e, 0x65, + 0x6c, 0x49, 0xed, 0x81, 0x03, 0x90, 0xa7, 0x92, 0xf4, 0x54, 0xfd, 0xd5, 0xcc, 0x6f, 0x2d, 0x3a, + 0xf3, 0xb5, 0xeb, 0x46, 0x34, 0xbf, 0xa7, 0xe8, 0x28, 0x56, 0xb1, 0x7f, 0x32, 0x99, 0x1f, 0x85, + 0x5c, 0x42, 0x1f, 0x00, 0x89, 0x79, 0x40, 0xa4, 0xfa, 0x7b, 0xe3, 0x1e, 0x53, 0x9b, 0xd1, 0x89, + 0x37, 0xa3, 0xb3, 0xc7, 0xe4, 0x63, 0xde, 0x90, 0x9c, 0xb2, 0x20, 0xb9, 0x4c, 0xcd, 0x89, 0x16, + 0x4a, 0xe9, 0xda, 0x7f, 0xe4, 0x4c, 0x4c, 0xb5, 0x8d, 0x16, 0x58, 0x0f, 0x2e, 0x28, 0x8a, 0xfe, + 0xb1, 0x1f, 0xf6, 0x30, 0x65, 0xe5, 0x15, 0x0d, 0x5b, 0x33, 0xb0, 0x62, 0x63, 0xec, 0x40, 0x09, + 0x46, 0x49, 0x46, 0x58, 0xb6, 0xcd, 0x84, 0x4e, 0x24, 0x8f, 0xb0, 0x6c, 0x23, 0xed, 0x81, 0x0d, + 0x90, 0x91, 0xa1, 0x59, 0x7c, 0x5f, 0x2c, 0x5a, 0xc1, 0xf8, 0x38, 0x88, 0xb4, 0x08, 0x27, 0xcc, + 0x23, 0x35, 0x60, 0x84, 0x33, 0xcd, 0x10, 0x65, 0x64, 0x08, 0x5f, 0x58, 0x60, 0x0d, 0x77, 0x25, + 0xe1, 0x0c, 0x4b, 0x52, 0xc3, 0x5e, 0x87, 0x30, 0x5f, 0x94, 0x73, 0xba, 0x4d, 0xff, 0x39, 0xc8, + 0x2d, 0x13, 0x64, 0xed, 0xc1, 0xac, 0x32, 0xba, 0x18, 0x0c, 0x3e, 0x02, 0xb9, 0x48, 0xb5, 0x2e, + 0xff, 0x76, 0x8f, 0x84, 0x6a, 0x4b, 0x6d, 0x45, 0xd7, 0x48, 0x35, 0x4b, 0x6b, 0xc0, 0x6f, 0x40, + 0x56, 0x76, 0x45, 0xb9, 0xb0, 0xb0, 0x54, 0xb3, 0xde, 0xd8, 0x0d, 0x59, 0x8b, 0x06, 0xb5, 0xe5, + 0xd1, 0xb0, 0x9a, 0x6d, 0xd6, 0x1b, 0x48, 0x29, 0xcc, 0x59, 0x9e, 0xcb, 0xff, 0x7f, 0x79, 0xda, + 0x14, 0x94, 0x52, 0xcf, 0x11, 0x7c, 0x0a, 0x96, 0x69, 0xbc, 0xb5, 0xca, 0x96, 0xae, 0xb8, 0xfb, + 0x96, 0x8f, 0x41, 0xb2, 0x52, 0x8c, 0x01, 0x8d, 0x05, 0xed, 0x5f, 0xc0, 0xfb, 0xf3, 0x7a, 0xa3, + 0xe6, 0xac, 0x43, 0x99, 0x3f, 0x3b, 0xba, 0xfb, 0x94, 0xf9, 0x48, 0x7b, 0x14, 0x82, 0x25, 0x6f, + 0xda, 0x04, 0xa1, 0x5f, 0x33, 0xed, 0x81, 0x36, 0x28, 0x3c, 0x27, 0x34, 0x68, 0x4b, 0x3d, 0x8d, + 0xf9, 0x1a, 0x50, 0xdb, 0xef, 0x89, 0xb6, 0x20, 0xe3, 0xb1, 0x43, 0x73, 0x54, 0xde, 0x68, 0x63, + 0xee, 0xeb, 0xfb, 0xa0, 0x3e, 0xf4, 0x6b, 0x69, 0xcd, 0xdc, 0x87, 0xb1, 0x03, 0x25, 0x18, 0x45, + 0xf0, 0x99, 0x68, 0xf4, 0x5b, 0x2d, 0xfa, 0xb3, 0x49, 0x65, 0x42, 0x78, 0x78, 0xd8, 0x88, 0x1d, + 0x28, 0xc1, 0xd8, 0x7f, 0x66, 0x41, 0x71, 0xd2, 0x4d, 0xb8, 0x0f, 0x4a, 0x92, 0xf0, 0x1e, 0x65, + 0x58, 0x2d, 0xbc, 0x99, 0x87, 0xa3, 0xd4, 0x4c, 0x5c, 0xaa, 0x73, 0xcd, 0x7a, 0x23, 0x65, 0xd1, + 0x9d, 0x4b, 0xb3, 0xe1, 0x67, 0xa0, 0xe4, 0x11, 0x2e, 0x69, 0x8b, 0x7a, 0x58, 0x8e, 0x0b, 0xf3, + 0xde, 0x58, 0x6c, 0x37, 0x71, 0xa1, 0x34, 0x0e, 0x6e, 0x80, 0x6c, 0x87, 0x0c, 0xcc, 0x2b, 0x51, + 0x32, 0xf0, 0xec, 0x3e, 0x19, 0x20, 0x65, 0x87, 0x5f, 0x82, 0xeb, 0x1e, 0x4e, 0x91, 0xcd, 0x2b, + 0x71, 0xc3, 0x00, 0xaf, 0xef, 0x3e, 0x48, 0x2b, 0x4f, 0x63, 0xe1, 0x33, 0x50, 0xf6, 0x89, 0x90, + 0x26, 0xc3, 0x29, 0xa8, 0x79, 0x87, 0x37, 0x8d, 0x4e, 0xf9, 0xe1, 0x25, 0x38, 0x74, 0xa9, 0x02, + 0x7c, 0x69, 0x81, 0x0d, 0xca, 0x04, 0xf1, 0xfa, 0x9c, 0x7c, 0xed, 0x07, 0x24, 0x55, 0x1d, 0x73, + 0x1b, 0x0a, 0x3a, 0xc6, 0x23, 0x13, 0x63, 0x63, 0xef, 0x2a, 0xf0, 0xf9, 0xb0, 0x7a, 0xfb, 0x4a, + 0x80, 0xae, 0xf8, 0xd5, 0x01, 0x6b, 0x5b, 0xa7, 0x67, 0x95, 0xa5, 0x57, 0x67, 0x95, 0xa5, 0xd7, + 0x67, 0x95, 0xa5, 0x17, 0xa3, 0x8a, 0x75, 0x3a, 0xaa, 0x58, 0xaf, 0x46, 0x15, 0xeb, 0xf5, 0xa8, + 0x62, 0xfd, 0x35, 0xaa, 0x58, 0x2f, 0xff, 0xae, 0x2c, 0x3d, 0xcd, 0x9c, 0x6c, 0xff, 0x1b, 0x00, + 0x00, 0xff, 0xff, 0x26, 0x8b, 0x83, 0xf6, 0x2d, 0x0c, 0x00, 0x00, +} + +func (m *Route) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Route) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Route) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Status.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouteIngress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteIngress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteIngress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.RouterCanonicalHostname) + copy(dAtA[i:], m.RouterCanonicalHostname) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RouterCanonicalHostname))) + i-- + dAtA[i] = 0x2a + i -= len(m.WildcardPolicy) + copy(dAtA[i:], m.WildcardPolicy) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.WildcardPolicy))) + i-- + dAtA[i] = 0x22 + if len(m.Conditions) > 0 { + for iNdEx := len(m.Conditions) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Conditions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + i -= len(m.RouterName) + copy(dAtA[i:], m.RouterName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RouterName))) + i-- + dAtA[i] = 0x12 + i -= len(m.Host) + copy(dAtA[i:], m.Host) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Host))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouteIngressCondition) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteIngressCondition) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteIngressCondition) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.LastTransitionTime != nil { + { + size, err := m.LastTransitionTime.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + i -= len(m.Message) + copy(dAtA[i:], m.Message) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) + i-- + dAtA[i] = 0x22 + i -= len(m.Reason) + copy(dAtA[i:], m.Reason) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) + i-- + dAtA[i] = 0x1a + i -= len(m.Status) + copy(dAtA[i:], m.Status) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Status))) + i-- + dAtA[i] = 0x12 + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouteList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Items) > 0 { + for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RoutePort) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutePort) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RoutePort) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TargetPort.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouteSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteSpec) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Subdomain) + copy(dAtA[i:], m.Subdomain) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subdomain))) + i-- + dAtA[i] = 0x42 + i -= len(m.WildcardPolicy) + copy(dAtA[i:], m.WildcardPolicy) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.WildcardPolicy))) + i-- + dAtA[i] = 0x3a + if m.TLS != nil { + { + size, err := m.TLS.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.Port != nil { + { + size, err := m.Port.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.AlternateBackends) > 0 { + for iNdEx := len(m.AlternateBackends) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AlternateBackends[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + { + size, err := m.To.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x12 + i -= len(m.Host) + copy(dAtA[i:], m.Host) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Host))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouteStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Ingress) > 0 { + for iNdEx := len(m.Ingress) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Ingress[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RouteTargetReference) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouteTargetReference) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouteTargetReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Weight != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.Weight)) + i-- + dAtA[i] = 0x18 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + i -= len(m.Kind) + copy(dAtA[i:], m.Kind) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Kind))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *RouterShard) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RouterShard) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RouterShard) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.DNSSuffix) + copy(dAtA[i:], m.DNSSuffix) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.DNSSuffix))) + i-- + dAtA[i] = 0x12 + i -= len(m.ShardName) + copy(dAtA[i:], m.ShardName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ShardName))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *TLSConfig) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TLSConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TLSConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.InsecureEdgeTerminationPolicy) + copy(dAtA[i:], m.InsecureEdgeTerminationPolicy) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.InsecureEdgeTerminationPolicy))) + i-- + dAtA[i] = 0x32 + i -= len(m.DestinationCACertificate) + copy(dAtA[i:], m.DestinationCACertificate) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.DestinationCACertificate))) + i-- + dAtA[i] = 0x2a + i -= len(m.CACertificate) + copy(dAtA[i:], m.CACertificate) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.CACertificate))) + i-- + dAtA[i] = 0x22 + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x1a + i -= len(m.Certificate) + copy(dAtA[i:], m.Certificate) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Certificate))) + i-- + dAtA[i] = 0x12 + i -= len(m.Termination) + copy(dAtA[i:], m.Termination) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Termination))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { + offset -= sovGenerated(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Route) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Spec.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Status.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *RouteIngress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Host) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.RouterName) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Conditions) > 0 { + for _, e := range m.Conditions { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + l = len(m.WildcardPolicy) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.RouterCanonicalHostname) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *RouteIngressCondition) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Type) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Status) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Reason) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Message) + n += 1 + l + sovGenerated(uint64(l)) + if m.LastTransitionTime != nil { + l = m.LastTransitionTime.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *RouteList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *RoutePort) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.TargetPort.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *RouteSpec) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Host) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Path) + n += 1 + l + sovGenerated(uint64(l)) + l = m.To.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.AlternateBackends) > 0 { + for _, e := range m.AlternateBackends { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if m.Port != nil { + l = m.Port.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.TLS != nil { + l = m.TLS.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.WildcardPolicy) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Subdomain) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *RouteStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Ingress) > 0 { + for _, e := range m.Ingress { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *RouteTargetReference) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Kind) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if m.Weight != nil { + n += 1 + sovGenerated(uint64(*m.Weight)) + } + return n +} + +func (m *RouterShard) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ShardName) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.DNSSuffix) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *TLSConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Termination) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Certificate) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Key) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.CACertificate) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.DestinationCACertificate) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.InsecureEdgeTerminationPolicy) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func sovGenerated(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenerated(x uint64) (n int) { + return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Route) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Route{`, + `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "RouteSpec", "RouteSpec", 1), `&`, ``, 1) + `,`, + `Status:` + strings.Replace(strings.Replace(this.Status.String(), "RouteStatus", "RouteStatus", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *RouteIngress) String() string { + if this == nil { + return "nil" + } + repeatedStringForConditions := "[]RouteIngressCondition{" + for _, f := range this.Conditions { + repeatedStringForConditions += strings.Replace(strings.Replace(f.String(), "RouteIngressCondition", "RouteIngressCondition", 1), `&`, ``, 1) + "," + } + repeatedStringForConditions += "}" + s := strings.Join([]string{`&RouteIngress{`, + `Host:` + fmt.Sprintf("%v", this.Host) + `,`, + `RouterName:` + fmt.Sprintf("%v", this.RouterName) + `,`, + `Conditions:` + repeatedStringForConditions + `,`, + `WildcardPolicy:` + fmt.Sprintf("%v", this.WildcardPolicy) + `,`, + `RouterCanonicalHostname:` + fmt.Sprintf("%v", this.RouterCanonicalHostname) + `,`, + `}`, + }, "") + return s +} +func (this *RouteIngressCondition) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RouteIngressCondition{`, + `Type:` + fmt.Sprintf("%v", this.Type) + `,`, + `Status:` + fmt.Sprintf("%v", this.Status) + `,`, + `Reason:` + fmt.Sprintf("%v", this.Reason) + `,`, + `Message:` + fmt.Sprintf("%v", this.Message) + `,`, + `LastTransitionTime:` + strings.Replace(fmt.Sprintf("%v", this.LastTransitionTime), "Time", "v1.Time", 1) + `,`, + `}`, + }, "") + return s +} +func (this *RouteList) String() string { + if this == nil { + return "nil" + } + repeatedStringForItems := "[]Route{" + for _, f := range this.Items { + repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Route", "Route", 1), `&`, ``, 1) + "," + } + repeatedStringForItems += "}" + s := strings.Join([]string{`&RouteList{`, + `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + repeatedStringForItems + `,`, + `}`, + }, "") + return s +} +func (this *RoutePort) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RoutePort{`, + `TargetPort:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.TargetPort), "IntOrString", "intstr.IntOrString", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *RouteSpec) String() string { + if this == nil { + return "nil" + } + repeatedStringForAlternateBackends := "[]RouteTargetReference{" + for _, f := range this.AlternateBackends { + repeatedStringForAlternateBackends += strings.Replace(strings.Replace(f.String(), "RouteTargetReference", "RouteTargetReference", 1), `&`, ``, 1) + "," + } + repeatedStringForAlternateBackends += "}" + s := strings.Join([]string{`&RouteSpec{`, + `Host:` + fmt.Sprintf("%v", this.Host) + `,`, + `Path:` + fmt.Sprintf("%v", this.Path) + `,`, + `To:` + strings.Replace(strings.Replace(this.To.String(), "RouteTargetReference", "RouteTargetReference", 1), `&`, ``, 1) + `,`, + `AlternateBackends:` + repeatedStringForAlternateBackends + `,`, + `Port:` + strings.Replace(this.Port.String(), "RoutePort", "RoutePort", 1) + `,`, + `TLS:` + strings.Replace(this.TLS.String(), "TLSConfig", "TLSConfig", 1) + `,`, + `WildcardPolicy:` + fmt.Sprintf("%v", this.WildcardPolicy) + `,`, + `Subdomain:` + fmt.Sprintf("%v", this.Subdomain) + `,`, + `}`, + }, "") + return s +} +func (this *RouteStatus) String() string { + if this == nil { + return "nil" + } + repeatedStringForIngress := "[]RouteIngress{" + for _, f := range this.Ingress { + repeatedStringForIngress += strings.Replace(strings.Replace(f.String(), "RouteIngress", "RouteIngress", 1), `&`, ``, 1) + "," + } + repeatedStringForIngress += "}" + s := strings.Join([]string{`&RouteStatus{`, + `Ingress:` + repeatedStringForIngress + `,`, + `}`, + }, "") + return s +} +func (this *RouteTargetReference) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RouteTargetReference{`, + `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Weight:` + valueToStringGenerated(this.Weight) + `,`, + `}`, + }, "") + return s +} +func (this *RouterShard) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RouterShard{`, + `ShardName:` + fmt.Sprintf("%v", this.ShardName) + `,`, + `DNSSuffix:` + fmt.Sprintf("%v", this.DNSSuffix) + `,`, + `}`, + }, "") + return s +} +func (this *TLSConfig) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TLSConfig{`, + `Termination:` + fmt.Sprintf("%v", this.Termination) + `,`, + `Certificate:` + fmt.Sprintf("%v", this.Certificate) + `,`, + `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `CACertificate:` + fmt.Sprintf("%v", this.CACertificate) + `,`, + `DestinationCACertificate:` + fmt.Sprintf("%v", this.DestinationCACertificate) + `,`, + `InsecureEdgeTerminationPolicy:` + fmt.Sprintf("%v", this.InsecureEdgeTerminationPolicy) + `,`, + `}`, + }, "") + return s +} +func valueToStringGenerated(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Route) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Route: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Route: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteIngress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteIngress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteIngress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Host", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Host = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RouterName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RouterName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Conditions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Conditions = append(m.Conditions, RouteIngressCondition{}) + if err := m.Conditions[len(m.Conditions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WildcardPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WildcardPolicy = WildcardPolicyType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RouterCanonicalHostname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RouterCanonicalHostname = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteIngressCondition) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteIngressCondition: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteIngressCondition: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = RouteIngressConditionType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Status = k8s_io_api_core_v1.ConditionStatus(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reason", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reason = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Message = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastTransitionTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LastTransitionTime == nil { + m.LastTransitionTime = &v1.Time{} + } + if err := m.LastTransitionTime.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, Route{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RoutePort) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RoutePort: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RoutePort: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetPort", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TargetPort.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Host", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Host = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.To.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AlternateBackends", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AlternateBackends = append(m.AlternateBackends, RouteTargetReference{}) + if err := m.AlternateBackends[len(m.AlternateBackends)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Port == nil { + m.Port = &RoutePort{} + } + if err := m.Port.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TLS", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TLS == nil { + m.TLS = &TLSConfig{} + } + if err := m.TLS.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WildcardPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WildcardPolicy = WildcardPolicyType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subdomain", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subdomain = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ingress", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ingress = append(m.Ingress, RouteIngress{}) + if err := m.Ingress[len(m.Ingress)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteTargetReference) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouteTargetReference: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteTargetReference: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Weight", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Weight = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouterShard) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RouterShard: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouterShard: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ShardName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ShardName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DNSSuffix", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DNSSuffix = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TLSConfig) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TLSConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TLSConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Termination", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Termination = TLSTerminationType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Certificate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Certificate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CACertificate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CACertificate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DestinationCACertificate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DestinationCACertificate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InsecureEdgeTerminationPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InsecureEdgeTerminationPolicy = InsecureEdgeTerminationPolicyType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenerated(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenerated + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenerated + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenerated + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/openshift/api/route/v1/generated.proto b/vendor/github.com/openshift/api/route/v1/generated.proto new file mode 100644 index 00000000000..c4bc446e34f --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/generated.proto @@ -0,0 +1,241 @@ + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package github.com.openshift.api.route.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// A route allows developers to expose services through an HTTP(S) aware load balancing and proxy +// layer via a public DNS entry. The route may further specify TLS options and a certificate, or +// specify a public CNAME that the router should also accept for HTTP and HTTPS traffic. An +// administrator typically configures their router to be visible outside the cluster firewall, and +// may also add additional security, caching, or traffic controls on the service content. Routers +// usually talk directly to the service endpoints. +// +// Once a route is created, the `host` field may not be changed. Generally, routers use the oldest +// route with a given host when resolving conflicts. +// +// Routers are subject to additional customization and may support additional controls via the +// annotations field. +// +// Because administrators may configure multiple routers, the route status field is used to +// return information to clients about the names and states of the route under each router. +// If a client chooses a duplicate name, for instance, the route status conditions are used +// to indicate the route cannot be chosen. +// +// To enable HTTP/2 ALPN on a route it requires a custom +// (non-wildcard) certificate. This prevents connection coalescing by +// clients, notably web browsers. We do not support HTTP/2 ALPN on +// routes that use the default certificate because of the risk of +// connection re-use/coalescing. Routes that do not have their own +// custom certificate will not be HTTP/2 ALPN-enabled on either the +// frontend or the backend. +message Route { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec is the desired state of the route + optional RouteSpec spec = 2; + + // status is the current state of the route + // +optional + optional RouteStatus status = 3; +} + +// RouteIngress holds information about the places where a route is exposed. +message RouteIngress { + // Host is the host string under which the route is exposed; this value is required + optional string host = 1; + + // Name is a name chosen by the router to identify itself; this value is required + optional string routerName = 2; + + // Conditions is the state of the route, may be empty. + repeated RouteIngressCondition conditions = 3; + + // Wildcard policy is the wildcard policy that was allowed where this route is exposed. + optional string wildcardPolicy = 4; + + // CanonicalHostname is the external host name for the router that can be used as a CNAME + // for the host requested for this route. This value is optional and may not be set in all cases. + optional string routerCanonicalHostname = 5; +} + +// RouteIngressCondition contains details for the current condition of this route on a particular +// router. +message RouteIngressCondition { + // Type is the type of the condition. + // Currently only Ready. + optional string type = 1; + + // Status is the status of the condition. + // Can be True, False, Unknown. + optional string status = 2; + + // (brief) reason for the condition's last transition, and is usually a machine and human + // readable constant + optional string reason = 3; + + // Human readable message indicating details about last transition. + optional string message = 4; + + // RFC 3339 date and time when this condition last transitioned + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 5; +} + +// RouteList is a collection of Routes. +message RouteList { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is a list of routes + repeated Route items = 2; +} + +// RoutePort defines a port mapping from a router to an endpoint in the service endpoints. +message RoutePort { + // The target port on pods selected by the service this route points to. + // If this is a string, it will be looked up as a named port in the target + // endpoints port list. Required + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString targetPort = 1; +} + +// RouteSpec describes the hostname or path the route exposes, any security information, +// and one to four backends (services) the route points to. Requests are distributed +// among the backends depending on the weights assigned to each backend. When using +// roundrobin scheduling the portion of requests that go to each backend is the backend +// weight divided by the sum of all of the backend weights. When the backend has more than +// one endpoint the requests that end up on the backend are roundrobin distributed among +// the endpoints. Weights are between 0 and 256 with default 100. Weight 0 causes no requests +// to the backend. If all weights are zero the route will be considered to have no backends +// and return a standard 503 response. +// +// The `tls` field is optional and allows specific certificates or behavior for the +// route. Routers typically configure a default certificate on a wildcard domain to +// terminate routes without explicit certificates, but custom hostnames usually must +// choose passthrough (send traffic directly to the backend via the TLS Server-Name- +// Indication field) or provide a certificate. +message RouteSpec { + // host is an alias/DNS that points to the service. Optional. + // If not specified a route name will typically be automatically + // chosen. + // Must follow DNS952 subdomain conventions. + // +optional + optional string host = 1; + + // subdomain is a DNS subdomain that is requested within the ingress controller's + // domain (as a subdomain). If host is set this field is ignored. An ingress + // controller may choose to ignore this suggested name, in which case the controller + // will report the assigned name in the status.ingress array or refuse to admit the + // route. If this value is set and the server does not support this field host will + // be populated automatically. Otherwise host is left empty. The field may have + // multiple parts separated by a dot, but not all ingress controllers may honor + // the request. This field may not be changed after creation except by a user with + // the update routes/custom-host permission. + // + // Example: subdomain `frontend` automatically receives the router subdomain + // `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + // + // +optional + optional string subdomain = 8; + + // path that the router watches for, to route traffic for to the service. Optional + optional string path = 2; + + // to is an object the route should use as the primary backend. Only the Service kind + // is allowed, and it will be defaulted to Service. If the weight field (0-256 default 100) + // is set to zero, no traffic will be sent to this backend. + optional RouteTargetReference to = 3; + + // alternateBackends allows up to 3 additional backends to be assigned to the route. + // Only the Service kind is allowed, and it will be defaulted to Service. + // Use the weight field in RouteTargetReference object to specify relative preference. + repeated RouteTargetReference alternateBackends = 4; + + // If specified, the port to be used by the router. Most routers will use all + // endpoints exposed by the service by default - set this value to instruct routers + // which port to use. + optional RoutePort port = 5; + + // The tls field provides the ability to configure certificates and termination for the route. + optional TLSConfig tls = 6; + + // Wildcard policy if any for the route. + // Currently only 'Subdomain' or 'None' is allowed. + optional string wildcardPolicy = 7; +} + +// RouteStatus provides relevant info about the status of a route, including which routers +// acknowledge it. +message RouteStatus { + // ingress describes the places where the route may be exposed. The list of + // ingress points may contain duplicate Host or RouterName values. Routes + // are considered live once they are `Ready` + repeated RouteIngress ingress = 1; +} + +// RouteTargetReference specifies the target that resolve into endpoints. Only the 'Service' +// kind is allowed. Use 'weight' field to emphasize one over others. +message RouteTargetReference { + // The kind of target that the route is referring to. Currently, only 'Service' is allowed + optional string kind = 1; + + // name of the service/target that is being referred to. e.g. name of the service + optional string name = 2; + + // weight as an integer between 0 and 256, default 100, that specifies the target's relative weight + // against other target reference objects. 0 suppresses requests to this backend. + // +optional + optional int32 weight = 3; +} + +// RouterShard has information of a routing shard and is used to +// generate host names and routing table entries when a routing shard is +// allocated for a specific route. +// Caveat: This is WIP and will likely undergo modifications when sharding +// support is added. +message RouterShard { + // shardName uniquely identifies a router shard in the "set" of + // routers used for routing traffic to the services. + optional string shardName = 1; + + // dnsSuffix for the shard ala: shard-1.v3.openshift.com + optional string dnsSuffix = 2; +} + +// TLSConfig defines config used to secure a route and provide termination +message TLSConfig { + // termination indicates termination type. + optional string termination = 1; + + // certificate provides certificate contents + optional string certificate = 2; + + // key provides key file contents + optional string key = 3; + + // caCertificate provides the cert authority certificate contents + optional string caCertificate = 4; + + // destinationCACertificate provides the contents of the ca certificate of the final destination. When using reencrypt + // termination this file should be provided in order to have routers use it for health checks on the secure connection. + // If this field is not specified, the router may provide its own destination CA and perform hostname validation using + // the short service name (service.namespace.svc), which allows infrastructure generated certificates to automatically + // verify. + optional string destinationCACertificate = 5; + + // insecureEdgeTerminationPolicy indicates the desired behavior for insecure connections to a route. While + // each router may make its own decisions on which ports to expose, this is normally port 80. + // + // * Allow - traffic is sent to the server on the insecure port (default) + // * Disable - no traffic is allowed on the insecure port. + // * Redirect - clients are redirected to the secure port. + optional string insecureEdgeTerminationPolicy = 6; +} + diff --git a/vendor/github.com/openshift/api/route/v1/legacy.go b/vendor/github.com/openshift/api/route/v1/legacy.go new file mode 100644 index 00000000000..498f5dd0f06 --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/legacy.go @@ -0,0 +1,22 @@ +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + legacyGroupVersion = schema.GroupVersion{Group: "", Version: "v1"} + legacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, corev1.AddToScheme) + DeprecatedInstallWithoutGroup = legacySchemeBuilder.AddToScheme +) + +func addLegacyKnownTypes(scheme *runtime.Scheme) error { + types := []runtime.Object{ + &Route{}, + &RouteList{}, + } + scheme.AddKnownTypes(legacyGroupVersion, types...) + return nil +} diff --git a/vendor/github.com/openshift/api/route/v1/register.go b/vendor/github.com/openshift/api/route/v1/register.go new file mode 100644 index 00000000000..6f99ef5c96a --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/register.go @@ -0,0 +1,39 @@ +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + GroupName = "route.openshift.io" + GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, corev1.AddToScheme) + // Install is a function which adds this version to a scheme + Install = schemeBuilder.AddToScheme + + // SchemeGroupVersion generated code relies on this name + // Deprecated + SchemeGroupVersion = GroupVersion + // AddToScheme exists solely to keep the old generators creating valid code + // DEPRECATED + AddToScheme = schemeBuilder.AddToScheme +) + +// Resource generated code relies on this being here, but it logically belongs to the group +// DEPRECATED +func Resource(resource string) schema.GroupResource { + return schema.GroupResource{Group: GroupName, Resource: resource} +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(GroupVersion, + &Route{}, + &RouteList{}, + ) + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/vendor/github.com/openshift/api/route/v1/types.go b/vendor/github.com/openshift/api/route/v1/types.go new file mode 100644 index 00000000000..9e59c697827 --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/types.go @@ -0,0 +1,280 @@ +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// A route allows developers to expose services through an HTTP(S) aware load balancing and proxy +// layer via a public DNS entry. The route may further specify TLS options and a certificate, or +// specify a public CNAME that the router should also accept for HTTP and HTTPS traffic. An +// administrator typically configures their router to be visible outside the cluster firewall, and +// may also add additional security, caching, or traffic controls on the service content. Routers +// usually talk directly to the service endpoints. +// +// Once a route is created, the `host` field may not be changed. Generally, routers use the oldest +// route with a given host when resolving conflicts. +// +// Routers are subject to additional customization and may support additional controls via the +// annotations field. +// +// Because administrators may configure multiple routers, the route status field is used to +// return information to clients about the names and states of the route under each router. +// If a client chooses a duplicate name, for instance, the route status conditions are used +// to indicate the route cannot be chosen. +// +// To enable HTTP/2 ALPN on a route it requires a custom +// (non-wildcard) certificate. This prevents connection coalescing by +// clients, notably web browsers. We do not support HTTP/2 ALPN on +// routes that use the default certificate because of the risk of +// connection re-use/coalescing. Routes that do not have their own +// custom certificate will not be HTTP/2 ALPN-enabled on either the +// frontend or the backend. +type Route struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // spec is the desired state of the route + Spec RouteSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` + // status is the current state of the route + // +optional + Status RouteStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RouteList is a collection of Routes. +type RouteList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // items is a list of routes + Items []Route `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// RouteSpec describes the hostname or path the route exposes, any security information, +// and one to four backends (services) the route points to. Requests are distributed +// among the backends depending on the weights assigned to each backend. When using +// roundrobin scheduling the portion of requests that go to each backend is the backend +// weight divided by the sum of all of the backend weights. When the backend has more than +// one endpoint the requests that end up on the backend are roundrobin distributed among +// the endpoints. Weights are between 0 and 256 with default 100. Weight 0 causes no requests +// to the backend. If all weights are zero the route will be considered to have no backends +// and return a standard 503 response. +// +// The `tls` field is optional and allows specific certificates or behavior for the +// route. Routers typically configure a default certificate on a wildcard domain to +// terminate routes without explicit certificates, but custom hostnames usually must +// choose passthrough (send traffic directly to the backend via the TLS Server-Name- +// Indication field) or provide a certificate. +type RouteSpec struct { + // host is an alias/DNS that points to the service. Optional. + // If not specified a route name will typically be automatically + // chosen. + // Must follow DNS952 subdomain conventions. + // +optional + Host string `json:"host,omitempty" protobuf:"bytes,1,opt,name=host"` + // subdomain is a DNS subdomain that is requested within the ingress controller's + // domain (as a subdomain). If host is set this field is ignored. An ingress + // controller may choose to ignore this suggested name, in which case the controller + // will report the assigned name in the status.ingress array or refuse to admit the + // route. If this value is set and the server does not support this field host will + // be populated automatically. Otherwise host is left empty. The field may have + // multiple parts separated by a dot, but not all ingress controllers may honor + // the request. This field may not be changed after creation except by a user with + // the update routes/custom-host permission. + // + // Example: subdomain `frontend` automatically receives the router subdomain + // `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + // + // +optional + Subdomain string `json:"subdomain,omitempty" protobuf:"bytes,8,opt,name=subdomain"` + + // path that the router watches for, to route traffic for to the service. Optional + Path string `json:"path,omitempty" protobuf:"bytes,2,opt,name=path"` + + // to is an object the route should use as the primary backend. Only the Service kind + // is allowed, and it will be defaulted to Service. If the weight field (0-256 default 100) + // is set to zero, no traffic will be sent to this backend. + To RouteTargetReference `json:"to" protobuf:"bytes,3,opt,name=to"` + + // alternateBackends allows up to 3 additional backends to be assigned to the route. + // Only the Service kind is allowed, and it will be defaulted to Service. + // Use the weight field in RouteTargetReference object to specify relative preference. + AlternateBackends []RouteTargetReference `json:"alternateBackends,omitempty" protobuf:"bytes,4,rep,name=alternateBackends"` + + // If specified, the port to be used by the router. Most routers will use all + // endpoints exposed by the service by default - set this value to instruct routers + // which port to use. + Port *RoutePort `json:"port,omitempty" protobuf:"bytes,5,opt,name=port"` + + // The tls field provides the ability to configure certificates and termination for the route. + TLS *TLSConfig `json:"tls,omitempty" protobuf:"bytes,6,opt,name=tls"` + + // Wildcard policy if any for the route. + // Currently only 'Subdomain' or 'None' is allowed. + WildcardPolicy WildcardPolicyType `json:"wildcardPolicy,omitempty" protobuf:"bytes,7,opt,name=wildcardPolicy"` +} + +// RouteTargetReference specifies the target that resolve into endpoints. Only the 'Service' +// kind is allowed. Use 'weight' field to emphasize one over others. +type RouteTargetReference struct { + // The kind of target that the route is referring to. Currently, only 'Service' is allowed + Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"` + + // name of the service/target that is being referred to. e.g. name of the service + Name string `json:"name" protobuf:"bytes,2,opt,name=name"` + + // weight as an integer between 0 and 256, default 100, that specifies the target's relative weight + // against other target reference objects. 0 suppresses requests to this backend. + // +optional + Weight *int32 `json:"weight" protobuf:"varint,3,opt,name=weight"` +} + +// RoutePort defines a port mapping from a router to an endpoint in the service endpoints. +type RoutePort struct { + // The target port on pods selected by the service this route points to. + // If this is a string, it will be looked up as a named port in the target + // endpoints port list. Required + TargetPort intstr.IntOrString `json:"targetPort" protobuf:"bytes,1,opt,name=targetPort"` +} + +// RouteStatus provides relevant info about the status of a route, including which routers +// acknowledge it. +type RouteStatus struct { + // ingress describes the places where the route may be exposed. The list of + // ingress points may contain duplicate Host or RouterName values. Routes + // are considered live once they are `Ready` + Ingress []RouteIngress `json:"ingress,omitempty" protobuf:"bytes,1,rep,name=ingress"` +} + +// RouteIngress holds information about the places where a route is exposed. +type RouteIngress struct { + // Host is the host string under which the route is exposed; this value is required + Host string `json:"host,omitempty" protobuf:"bytes,1,opt,name=host"` + // Name is a name chosen by the router to identify itself; this value is required + RouterName string `json:"routerName,omitempty" protobuf:"bytes,2,opt,name=routerName"` + // Conditions is the state of the route, may be empty. + Conditions []RouteIngressCondition `json:"conditions,omitempty" protobuf:"bytes,3,rep,name=conditions"` + // Wildcard policy is the wildcard policy that was allowed where this route is exposed. + WildcardPolicy WildcardPolicyType `json:"wildcardPolicy,omitempty" protobuf:"bytes,4,opt,name=wildcardPolicy"` + // CanonicalHostname is the external host name for the router that can be used as a CNAME + // for the host requested for this route. This value is optional and may not be set in all cases. + RouterCanonicalHostname string `json:"routerCanonicalHostname,omitempty" protobuf:"bytes,5,opt,name=routerCanonicalHostname"` +} + +// RouteIngressConditionType is a valid value for RouteCondition +type RouteIngressConditionType string + +// These are valid conditions of pod. +const ( + // RouteAdmitted means the route is able to service requests for the provided Host + RouteAdmitted RouteIngressConditionType = "Admitted" + // TODO: add other route condition types +) + +// RouteIngressCondition contains details for the current condition of this route on a particular +// router. +type RouteIngressCondition struct { + // Type is the type of the condition. + // Currently only Ready. + Type RouteIngressConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=RouteIngressConditionType"` + // Status is the status of the condition. + // Can be True, False, Unknown. + Status corev1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"` + // (brief) reason for the condition's last transition, and is usually a machine and human + // readable constant + Reason string `json:"reason,omitempty" protobuf:"bytes,3,opt,name=reason"` + // Human readable message indicating details about last transition. + Message string `json:"message,omitempty" protobuf:"bytes,4,opt,name=message"` + // RFC 3339 date and time when this condition last transitioned + LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,5,opt,name=lastTransitionTime"` +} + +// RouterShard has information of a routing shard and is used to +// generate host names and routing table entries when a routing shard is +// allocated for a specific route. +// Caveat: This is WIP and will likely undergo modifications when sharding +// support is added. +type RouterShard struct { + // shardName uniquely identifies a router shard in the "set" of + // routers used for routing traffic to the services. + ShardName string `json:"shardName" protobuf:"bytes,1,opt,name=shardName"` + + // dnsSuffix for the shard ala: shard-1.v3.openshift.com + DNSSuffix string `json:"dnsSuffix" protobuf:"bytes,2,opt,name=dnsSuffix"` +} + +// TLSConfig defines config used to secure a route and provide termination +type TLSConfig struct { + // termination indicates termination type. + Termination TLSTerminationType `json:"termination" protobuf:"bytes,1,opt,name=termination,casttype=TLSTerminationType"` + + // certificate provides certificate contents + Certificate string `json:"certificate,omitempty" protobuf:"bytes,2,opt,name=certificate"` + + // key provides key file contents + Key string `json:"key,omitempty" protobuf:"bytes,3,opt,name=key"` + + // caCertificate provides the cert authority certificate contents + CACertificate string `json:"caCertificate,omitempty" protobuf:"bytes,4,opt,name=caCertificate"` + + // destinationCACertificate provides the contents of the ca certificate of the final destination. When using reencrypt + // termination this file should be provided in order to have routers use it for health checks on the secure connection. + // If this field is not specified, the router may provide its own destination CA and perform hostname validation using + // the short service name (service.namespace.svc), which allows infrastructure generated certificates to automatically + // verify. + DestinationCACertificate string `json:"destinationCACertificate,omitempty" protobuf:"bytes,5,opt,name=destinationCACertificate"` + + // insecureEdgeTerminationPolicy indicates the desired behavior for insecure connections to a route. While + // each router may make its own decisions on which ports to expose, this is normally port 80. + // + // * Allow - traffic is sent to the server on the insecure port (default) + // * Disable - no traffic is allowed on the insecure port. + // * Redirect - clients are redirected to the secure port. + InsecureEdgeTerminationPolicy InsecureEdgeTerminationPolicyType `json:"insecureEdgeTerminationPolicy,omitempty" protobuf:"bytes,6,opt,name=insecureEdgeTerminationPolicy,casttype=InsecureEdgeTerminationPolicyType"` +} + +// TLSTerminationType dictates where the secure communication will stop +// TODO: Reconsider this type in v2 +type TLSTerminationType string + +// InsecureEdgeTerminationPolicyType dictates the behavior of insecure +// connections to an edge-terminated route. +type InsecureEdgeTerminationPolicyType string + +const ( + // TLSTerminationEdge terminate encryption at the edge router. + TLSTerminationEdge TLSTerminationType = "edge" + // TLSTerminationPassthrough terminate encryption at the destination, the destination is responsible for decrypting traffic + TLSTerminationPassthrough TLSTerminationType = "passthrough" + // TLSTerminationReencrypt terminate encryption at the edge router and re-encrypt it with a new certificate supplied by the destination + TLSTerminationReencrypt TLSTerminationType = "reencrypt" + + // InsecureEdgeTerminationPolicyNone disables insecure connections for an edge-terminated route. + InsecureEdgeTerminationPolicyNone InsecureEdgeTerminationPolicyType = "None" + // InsecureEdgeTerminationPolicyAllow allows insecure connections for an edge-terminated route. + InsecureEdgeTerminationPolicyAllow InsecureEdgeTerminationPolicyType = "Allow" + // InsecureEdgeTerminationPolicyRedirect redirects insecure connections for an edge-terminated route. + // As an example, for routers that support HTTP and HTTPS, the + // insecure HTTP connections will be redirected to use HTTPS. + InsecureEdgeTerminationPolicyRedirect InsecureEdgeTerminationPolicyType = "Redirect" +) + +// WildcardPolicyType indicates the type of wildcard support needed by routes. +type WildcardPolicyType string + +const ( + // WildcardPolicyNone indicates no wildcard support is needed. + WildcardPolicyNone WildcardPolicyType = "None" + + // WildcardPolicySubdomain indicates the host needs wildcard support for the subdomain. + // Example: For host = "www.acme.test", indicates that the router + // should support requests for *.acme.test + // Note that this will not match acme.test only *.acme.test + WildcardPolicySubdomain WildcardPolicyType = "Subdomain" +) diff --git a/vendor/github.com/openshift/api/route/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/route/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..a9576c414ca --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/zz_generated.deepcopy.go @@ -0,0 +1,240 @@ +// +build !ignore_autogenerated + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Route) DeepCopyInto(out *Route) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. +func (in *Route) DeepCopy() *Route { + if in == nil { + return nil + } + out := new(Route) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Route) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteIngress) DeepCopyInto(out *RouteIngress) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]RouteIngressCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteIngress. +func (in *RouteIngress) DeepCopy() *RouteIngress { + if in == nil { + return nil + } + out := new(RouteIngress) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteIngressCondition) DeepCopyInto(out *RouteIngressCondition) { + *out = *in + if in.LastTransitionTime != nil { + in, out := &in.LastTransitionTime, &out.LastTransitionTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteIngressCondition. +func (in *RouteIngressCondition) DeepCopy() *RouteIngressCondition { + if in == nil { + return nil + } + out := new(RouteIngressCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteList) DeepCopyInto(out *RouteList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Route, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteList. +func (in *RouteList) DeepCopy() *RouteList { + if in == nil { + return nil + } + out := new(RouteList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouteList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RoutePort) DeepCopyInto(out *RoutePort) { + *out = *in + out.TargetPort = in.TargetPort + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoutePort. +func (in *RoutePort) DeepCopy() *RoutePort { + if in == nil { + return nil + } + out := new(RoutePort) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteSpec) DeepCopyInto(out *RouteSpec) { + *out = *in + in.To.DeepCopyInto(&out.To) + if in.AlternateBackends != nil { + in, out := &in.AlternateBackends, &out.AlternateBackends + *out = make([]RouteTargetReference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(RoutePort) + **out = **in + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(TLSConfig) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteSpec. +func (in *RouteSpec) DeepCopy() *RouteSpec { + if in == nil { + return nil + } + out := new(RouteSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteStatus) DeepCopyInto(out *RouteStatus) { + *out = *in + if in.Ingress != nil { + in, out := &in.Ingress, &out.Ingress + *out = make([]RouteIngress, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteStatus. +func (in *RouteStatus) DeepCopy() *RouteStatus { + if in == nil { + return nil + } + out := new(RouteStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteTargetReference) DeepCopyInto(out *RouteTargetReference) { + *out = *in + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteTargetReference. +func (in *RouteTargetReference) DeepCopy() *RouteTargetReference { + if in == nil { + return nil + } + out := new(RouteTargetReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouterShard) DeepCopyInto(out *RouterShard) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterShard. +func (in *RouterShard) DeepCopy() *RouterShard { + if in == nil { + return nil + } + out := new(RouterShard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. +func (in *TLSConfig) DeepCopy() *TLSConfig { + if in == nil { + return nil + } + out := new(TLSConfig) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/openshift/api/route/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/route/v1/zz_generated.swagger_doc_generated.go new file mode 100644 index 00000000000..9974795f627 --- /dev/null +++ b/vendor/github.com/openshift/api/route/v1/zz_generated.swagger_doc_generated.go @@ -0,0 +1,128 @@ +package v1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE +var map_Route = map[string]string{ + "": "A route allows developers to expose services through an HTTP(S) aware load balancing and proxy layer via a public DNS entry. The route may further specify TLS options and a certificate, or specify a public CNAME that the router should also accept for HTTP and HTTPS traffic. An administrator typically configures their router to be visible outside the cluster firewall, and may also add additional security, caching, or traffic controls on the service content. Routers usually talk directly to the service endpoints.\n\nOnce a route is created, the `host` field may not be changed. Generally, routers use the oldest route with a given host when resolving conflicts.\n\nRouters are subject to additional customization and may support additional controls via the annotations field.\n\nBecause administrators may configure multiple routers, the route status field is used to return information to clients about the names and states of the route under each router. If a client chooses a duplicate name, for instance, the route status conditions are used to indicate the route cannot be chosen.\n\nTo enable HTTP/2 ALPN on a route it requires a custom (non-wildcard) certificate. This prevents connection coalescing by clients, notably web browsers. We do not support HTTP/2 ALPN on routes that use the default certificate because of the risk of connection re-use/coalescing. Routes that do not have their own custom certificate will not be HTTP/2 ALPN-enabled on either the frontend or the backend.", + "spec": "spec is the desired state of the route", + "status": "status is the current state of the route", +} + +func (Route) SwaggerDoc() map[string]string { + return map_Route +} + +var map_RouteIngress = map[string]string{ + "": "RouteIngress holds information about the places where a route is exposed.", + "host": "Host is the host string under which the route is exposed; this value is required", + "routerName": "Name is a name chosen by the router to identify itself; this value is required", + "conditions": "Conditions is the state of the route, may be empty.", + "wildcardPolicy": "Wildcard policy is the wildcard policy that was allowed where this route is exposed.", + "routerCanonicalHostname": "CanonicalHostname is the external host name for the router that can be used as a CNAME for the host requested for this route. This value is optional and may not be set in all cases.", +} + +func (RouteIngress) SwaggerDoc() map[string]string { + return map_RouteIngress +} + +var map_RouteIngressCondition = map[string]string{ + "": "RouteIngressCondition contains details for the current condition of this route on a particular router.", + "type": "Type is the type of the condition. Currently only Ready.", + "status": "Status is the status of the condition. Can be True, False, Unknown.", + "reason": "(brief) reason for the condition's last transition, and is usually a machine and human readable constant", + "message": "Human readable message indicating details about last transition.", + "lastTransitionTime": "RFC 3339 date and time when this condition last transitioned", +} + +func (RouteIngressCondition) SwaggerDoc() map[string]string { + return map_RouteIngressCondition +} + +var map_RouteList = map[string]string{ + "": "RouteList is a collection of Routes.", + "items": "items is a list of routes", +} + +func (RouteList) SwaggerDoc() map[string]string { + return map_RouteList +} + +var map_RoutePort = map[string]string{ + "": "RoutePort defines a port mapping from a router to an endpoint in the service endpoints.", + "targetPort": "The target port on pods selected by the service this route points to. If this is a string, it will be looked up as a named port in the target endpoints port list. Required", +} + +func (RoutePort) SwaggerDoc() map[string]string { + return map_RoutePort +} + +var map_RouteSpec = map[string]string{ + "": "RouteSpec describes the hostname or path the route exposes, any security information, and one to four backends (services) the route points to. Requests are distributed among the backends depending on the weights assigned to each backend. When using roundrobin scheduling the portion of requests that go to each backend is the backend weight divided by the sum of all of the backend weights. When the backend has more than one endpoint the requests that end up on the backend are roundrobin distributed among the endpoints. Weights are between 0 and 256 with default 100. Weight 0 causes no requests to the backend. If all weights are zero the route will be considered to have no backends and return a standard 503 response.\n\nThe `tls` field is optional and allows specific certificates or behavior for the route. Routers typically configure a default certificate on a wildcard domain to terminate routes without explicit certificates, but custom hostnames usually must choose passthrough (send traffic directly to the backend via the TLS Server-Name- Indication field) or provide a certificate.", + "host": "host is an alias/DNS that points to the service. Optional. If not specified a route name will typically be automatically chosen. Must follow DNS952 subdomain conventions.", + "subdomain": "subdomain is a DNS subdomain that is requested within the ingress controller's domain (as a subdomain). If host is set this field is ignored. An ingress controller may choose to ignore this suggested name, in which case the controller will report the assigned name in the status.ingress array or refuse to admit the route. If this value is set and the server does not support this field host will be populated automatically. Otherwise host is left empty. The field may have multiple parts separated by a dot, but not all ingress controllers may honor the request. This field may not be changed after creation except by a user with the update routes/custom-host permission.\n\nExample: subdomain `frontend` automatically receives the router subdomain `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`.", + "path": "path that the router watches for, to route traffic for to the service. Optional", + "to": "to is an object the route should use as the primary backend. Only the Service kind is allowed, and it will be defaulted to Service. If the weight field (0-256 default 100) is set to zero, no traffic will be sent to this backend.", + "alternateBackends": "alternateBackends allows up to 3 additional backends to be assigned to the route. Only the Service kind is allowed, and it will be defaulted to Service. Use the weight field in RouteTargetReference object to specify relative preference.", + "port": "If specified, the port to be used by the router. Most routers will use all endpoints exposed by the service by default - set this value to instruct routers which port to use.", + "tls": "The tls field provides the ability to configure certificates and termination for the route.", + "wildcardPolicy": "Wildcard policy if any for the route. Currently only 'Subdomain' or 'None' is allowed.", +} + +func (RouteSpec) SwaggerDoc() map[string]string { + return map_RouteSpec +} + +var map_RouteStatus = map[string]string{ + "": "RouteStatus provides relevant info about the status of a route, including which routers acknowledge it.", + "ingress": "ingress describes the places where the route may be exposed. The list of ingress points may contain duplicate Host or RouterName values. Routes are considered live once they are `Ready`", +} + +func (RouteStatus) SwaggerDoc() map[string]string { + return map_RouteStatus +} + +var map_RouteTargetReference = map[string]string{ + "": "RouteTargetReference specifies the target that resolve into endpoints. Only the 'Service' kind is allowed. Use 'weight' field to emphasize one over others.", + "kind": "The kind of target that the route is referring to. Currently, only 'Service' is allowed", + "name": "name of the service/target that is being referred to. e.g. name of the service", + "weight": "weight as an integer between 0 and 256, default 100, that specifies the target's relative weight against other target reference objects. 0 suppresses requests to this backend.", +} + +func (RouteTargetReference) SwaggerDoc() map[string]string { + return map_RouteTargetReference +} + +var map_RouterShard = map[string]string{ + "": "RouterShard has information of a routing shard and is used to generate host names and routing table entries when a routing shard is allocated for a specific route. Caveat: This is WIP and will likely undergo modifications when sharding\n support is added.", + "shardName": "shardName uniquely identifies a router shard in the \"set\" of routers used for routing traffic to the services.", + "dnsSuffix": "dnsSuffix for the shard ala: shard-1.v3.openshift.com", +} + +func (RouterShard) SwaggerDoc() map[string]string { + return map_RouterShard +} + +var map_TLSConfig = map[string]string{ + "": "TLSConfig defines config used to secure a route and provide termination", + "termination": "termination indicates termination type.", + "certificate": "certificate provides certificate contents", + "key": "key provides key file contents", + "caCertificate": "caCertificate provides the cert authority certificate contents", + "destinationCACertificate": "destinationCACertificate provides the contents of the ca certificate of the final destination. When using reencrypt termination this file should be provided in order to have routers use it for health checks on the secure connection. If this field is not specified, the router may provide its own destination CA and perform hostname validation using the short service name (service.namespace.svc), which allows infrastructure generated certificates to automatically verify.", + "insecureEdgeTerminationPolicy": "insecureEdgeTerminationPolicy indicates the desired behavior for insecure connections to a route. While each router may make its own decisions on which ports to expose, this is normally port 80.\n\n* Allow - traffic is sent to the server on the insecure port (default) * Disable - no traffic is allowed on the insecure port. * Redirect - clients are redirected to the secure port.", +} + +func (TLSConfig) SwaggerDoc() map[string]string { + return map_TLSConfig +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/vendor/github.com/openshift/client-go/LICENSE b/vendor/github.com/openshift/client-go/LICENSE new file mode 100644 index 00000000000..c4ea8b6f9d8 --- /dev/null +++ b/vendor/github.com/openshift/client-go/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2014 Red Hat, Inc. + + 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. diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go new file mode 100644 index 00000000000..14db57a58f8 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go @@ -0,0 +1,4 @@ +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go new file mode 100644 index 00000000000..0604e5613d7 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go @@ -0,0 +1,40 @@ +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + routev1 "github.com/openshift/api/route/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + routev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go new file mode 100644 index 00000000000..225e6b2be34 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go @@ -0,0 +1,4 @@ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go new file mode 100644 index 00000000000..4f2173b6fc5 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go @@ -0,0 +1,5 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type RouteExpansion interface{} diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go new file mode 100644 index 00000000000..adbe7e565cb --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go @@ -0,0 +1,179 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + "time" + + v1 "github.com/openshift/api/route/v1" + scheme "github.com/openshift/client-go/route/clientset/versioned/scheme" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// RoutesGetter has a method to return a RouteInterface. +// A group's client should implement this interface. +type RoutesGetter interface { + Routes(namespace string) RouteInterface +} + +// RouteInterface has methods to work with Route resources. +type RouteInterface interface { + Create(ctx context.Context, route *v1.Route, opts metav1.CreateOptions) (*v1.Route, error) + Update(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (*v1.Route, error) + UpdateStatus(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (*v1.Route, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Route, error) + List(ctx context.Context, opts metav1.ListOptions) (*v1.RouteList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Route, err error) + RouteExpansion +} + +// routes implements RouteInterface +type routes struct { + client rest.Interface + ns string +} + +// newRoutes returns a Routes +func newRoutes(c *RouteV1Client, namespace string) *routes { + return &routes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the route, and returns the corresponding route object, and an error if there is any. +func (c *routes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Route, err error) { + result = &v1.Route{} + err = c.client.Get(). + Namespace(c.ns). + Resource("routes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Routes that match those selectors. +func (c *routes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.RouteList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.RouteList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("routes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested routes. +func (c *routes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("routes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a route and creates it. Returns the server's representation of the route, and an error, if there is any. +func (c *routes) Create(ctx context.Context, route *v1.Route, opts metav1.CreateOptions) (result *v1.Route, err error) { + result = &v1.Route{} + err = c.client.Post(). + Namespace(c.ns). + Resource("routes"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(route). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a route and updates it. Returns the server's representation of the route, and an error, if there is any. +func (c *routes) Update(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (result *v1.Route, err error) { + result = &v1.Route{} + err = c.client.Put(). + Namespace(c.ns). + Resource("routes"). + Name(route.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(route). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *routes) UpdateStatus(ctx context.Context, route *v1.Route, opts metav1.UpdateOptions) (result *v1.Route, err error) { + result = &v1.Route{} + err = c.client.Put(). + Namespace(c.ns). + Resource("routes"). + Name(route.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(route). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the route and deletes it. Returns an error if one occurs. +func (c *routes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("routes"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *routes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("routes"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched route. +func (c *routes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Route, err error) { + result = &v1.Route{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("routes"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go new file mode 100644 index 00000000000..351945deab7 --- /dev/null +++ b/vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go @@ -0,0 +1,73 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openshift/api/route/v1" + "github.com/openshift/client-go/route/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type RouteV1Interface interface { + RESTClient() rest.Interface + RoutesGetter +} + +// RouteV1Client is used to interact with features provided by the route.openshift.io group. +type RouteV1Client struct { + restClient rest.Interface +} + +func (c *RouteV1Client) Routes(namespace string) RouteInterface { + return newRoutes(c, namespace) +} + +// NewForConfig creates a new RouteV1Client for the given config. +func NewForConfig(c *rest.Config) (*RouteV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &RouteV1Client{client}, nil +} + +// NewForConfigOrDie creates a new RouteV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *RouteV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new RouteV1Client for the given RESTClient. +func New(c rest.Interface) *RouteV1Client { + return &RouteV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *RouteV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 20b7567301c..f9bb94337f5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1024,9 +1024,14 @@ github.com/opencontainers/go-digest ## explicit; go 1.11 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/openshift/api v0.0.0-20200713203337-b2494ecb17dd -## explicit; go 1.13 +# github.com/openshift/api v0.0.0-20200929171550-c99a4deebbe5 +## explicit; go 1.15 github.com/openshift/api/apps/v1 +github.com/openshift/api/route/v1 +# github.com/openshift/client-go v0.0.0-20200929181438-91d71ef2122c +## explicit; go 1.13 +github.com/openshift/client-go/route/clientset/versioned/scheme +github.com/openshift/client-go/route/clientset/versioned/typed/route/v1 # github.com/pelletier/go-toml v1.9.4 ## explicit; go 1.12 github.com/pelletier/go-toml