diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..bd7fd6bbc739 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.idea +*.sw* +.DS_Store +bin/* +.vscode +*.kubeconfig +*.config +_output +vendor +public.zip +docs/public +docs/node_modules +docs/public.zip diff --git a/ATTRIBUTION.txt b/ATTRIBUTION.txt new file mode 100644 index 000000000000..ddd7d510ce9c --- /dev/null +++ b/ATTRIBUTION.txt @@ -0,0 +1,4212 @@ + +** cloud.google.com/go; version v0.57.0 -- +https://github.com/googleapis/google-cloud-go + +** cloud.google.com/go/storage; version v1.6.0 -- +https://github.com/googleapis/google-cloud-go + +** github.com/aws/aws-sdk-go; version v1.38.40 -- +https://github.com/aws/aws-sdk-go + +** github.com/aws/eks-distro-build-tooling/release/api/v1alpha1; version v0.0.0-20210810165539-7d41d9b36b74 -- +https://github.com/aws/eks-distro-build-tooling/release + +** github.com/Azure/go-autorest/autorest; version v0.11.12 -- +https://github.com/Azure/go-autorest/autorest + +** github.com/Azure/go-autorest/autorest/adal; version v0.9.5 -- +https://github.com/Azure/go-autorest/autorest/adal + +** github.com/Azure/go-autorest/autorest/date; version v0.3.0 -- +https://github.com/Azure/go-autorest/autorest/date + +** github.com/Azure/go-autorest/logger; version v0.2.0 -- +https://github.com/Azure/go-autorest/logger + +** github.com/Azure/go-autorest/tracing; version v0.6.0 -- +https://github.com/Azure/go-autorest/tracing + +** github.com/caddyserver/caddy/caddyfile; version v1.0.3 -- +https://github.com/caddyserver/caddy + +** github.com/containerd/containerd; version v1.5.1 -- +https://github.com/containerd/containerd + +** github.com/containers/image/v5; version v5.10.4 -- +https://github.com/containers/image/v5 + +** github.com/containers/libtrust; version v0.0.0-20190913040956-14b96171aa3b -- +https://github.com/containers/libtrust + +** github.com/containers/ocicrypt/spec; version v1.1.1 -- +https://github.com/containers/ocicrypt + +** github.com/containers/storage; version v1.24.8 -- +https://github.com/containers/storage + +** github.com/coredns/corefile-migration/migration; version v1.0.11 -- +https://github.com/coredns/corefile-migration + +** github.com/docker/distribution; version v2.7.1+incompatible -- +https://github.com/distribution/distribution + +** github.com/docker/docker; version v20.10.6+incompatible -- +https://github.com/moby/moby + +** github.com/docker/go-connections; version v0.4.0 -- +https://github.com/docker/go-connections + +** github.com/docker/go-metrics; version v0.0.1 -- +https://github.com/docker/go-metrics + +** github.com/docker/go-units; version v0.4.0 -- +https://github.com/docker/go-units + +** github.com/go-git/go-billy/v5; version v5.3.1 -- +https://github.com/go-git/go-billy/v5 + +** github.com/go-git/go-git/v5; version v5.4.2 -- +https://github.com/go-git/go-git/v5 + +** github.com/go-logr/logr; version v0.4.0 -- +https://github.com/go-logr/logr + +** github.com/go-logr/zapr; version v0.4.0 -- +https://github.com/go-logr/zapr + +** github.com/go-openapi/jsonpointer; version v0.19.3 -- +https://github.com/go-openapi/jsonpointer + +** github.com/go-openapi/jsonreference; version v0.19.3 -- +https://github.com/go-openapi/jsonreference + +** github.com/go-openapi/spec; version v0.19.5 -- +https://github.com/go-openapi/spec + +** github.com/go-openapi/swag; version v0.19.5 -- +https://github.com/go-openapi/swag + +** github.com/golang/groupcache/lru; version v0.0.0-20210331224755-41bb18bfe9da -- +https://github.com/golang/groupcache + +** github.com/google/btree; version v1.0.0 -- +https://github.com/google/btree + +** github.com/google/gofuzz; version v1.2.0 -- +https://github.com/google/gofuzz + +** github.com/google/shlex; version v0.0.0-20191202100458-e7afc7fbc510 -- +https://github.com/google/shlex + +** github.com/googleapis/gnostic; version v0.5.4 -- +https://github.com/google/gnostic + +** github.com/jmespath/go-jmespath; version v0.4.0 -- +https://github.com/jmespath/go-jmespath + +** github.com/matttproud/golang_protobuf_extensions/pbutil; version v1.0.2-0.20181231171920-c182affec369 -- +https://github.com/matttproud/golang_protobuf_extensions + +** github.com/mistifyio/go-zfs; version v2.1.2-0.20190413222219-f784269be439+incompatible -- +https://github.com/mistifyio/go-zfs + +** github.com/moby/spdystream; version v0.2.0 -- +https://github.com/moby/spdystream + +** github.com/moby/sys/mountinfo; version v0.4.1 -- +https://github.com/moby/sys/mountinfo + +** github.com/modern-go/concurrent; version v0.0.0-20180306012644-bacd9c7ef1dd -- +https://github.com/modern-go/concurrent + +** github.com/modern-go/reflect2; version v1.0.1 -- +https://github.com/modern-go/reflect2 + +** github.com/mrajashree/etcdadm-bootstrap-provider/api/v1alpha3; version v0.1.1-0.20210807004059-42797f8a87fd -- +https://github.com/mrajashree/etcdadm-bootstrap-provider + +** github.com/mrajashree/etcdadm-controller/api/v1alpha3; version v0.1.1-0.20210807012710-3e2035176ab8 -- +https://github.com/mrajashree/etcdadm-controller + +** github.com/opencontainers/go-digest; version v1.0.0 -- +https://github.com/opencontainers/go-digest + +** github.com/opencontainers/image-spec/specs-go; version v1.0.2-0.20190823105129-775207bd45b6 -- +https://github.com/opencontainers/image-spec + +** github.com/opencontainers/runc/libcontainer; version v1.0.0-rc93 -- +https://github.com/opencontainers/runc + +** github.com/opencontainers/runtime-spec/specs-go; version v1.0.3-0.20200929063507-e6143ca7d51d -- +https://github.com/opencontainers/runtime-spec + +** github.com/opencontainers/selinux; version v1.8.0 -- +https://github.com/opencontainers/selinux + +** github.com/pquerna/ffjson; version v0.0.0-20190813045741-dac163c6c0a9 -- +https://github.com/pquerna/ffjson + +** github.com/prometheus/client_golang/prometheus; version v1.9.0 -- +https://github.com/prometheus/client_golang + +** github.com/prometheus/client_model/go; version v0.2.0 -- +https://github.com/prometheus/client_model + +** github.com/prometheus/common; version v0.15.0 -- +https://github.com/prometheus/common + +** github.com/prometheus/procfs; version v0.6.0 -- +https://github.com/prometheus/procfs + +** github.com/replicatedhq/troubleshoot; version v0.10.24 -- +https://github.com/replicatedhq/troubleshoot + +** github.com/spf13/afero; version v1.2.2 -- +https://github.com/spf13/afero + +** github.com/spf13/cobra; version v1.1.3 -- +https://github.com/spf13/cobra + +** github.com/xanzy/ssh-agent; version v0.3.0 -- +https://github.com/xanzy/ssh-agent + +** go.opencensus.io; version v0.22.3 -- +https://github.com/census-instrumentation/opencensus-go + +** gomodules.xyz/jsonpatch/v2; version v2.1.0 -- +https://github.com/gomodules/jsonpatch + +** google.golang.org/genproto/googleapis; version v0.0.0-20201110150050-8816d57aaa9a -- +https://github.com/googleapis/go-genproto + +** google.golang.org/grpc; version v1.38.0 -- +https://github.com/grpc/grpc-go + +** gopkg.in/ini.v1; version v1.51.0 -- +https://gopkg.in/ini.v1 + +** gopkg.in/yaml.v2; version v2.4.0 -- +https://gopkg.in/yaml.v2 + +** k8s.io/api; version v0.21.2 -- +https://github.com/kubernetes/api + +** k8s.io/apiextensions-apiserver/pkg; version v0.21.0 -- +https://github.com/kubernetes/apiextensions-apiserver + +** k8s.io/apimachinery; version v0.21.2 -- +https://github.com/kubernetes/apimachinery + +** k8s.io/cli-runtime/pkg; version v0.21.0 -- +https://github.com/kubernetes/cli-runtime + +** k8s.io/client-go; version v0.21.2 -- +https://github.com/kubernetes/client-go + +** k8s.io/cluster-bootstrap/token; version v0.21.0 -- +https://github.com/kubernetes/cluster-bootstrap + +** k8s.io/component-base/config; version v0.21.0 -- +https://github.com/kubernetes/component-base + +** k8s.io/klog/v2; version v2.8.0 -- +https://github.com/kubernetes/klog + +** k8s.io/kube-openapi/pkg/util/proto; version v0.0.0-20210305001622-591a79e4bda7 -- +https://github.com/kubernetes/kube-openapi + +** k8s.io/utils; version v0.0.0-20210305010621-2afb4311ab10 -- +https://github.com/kubernetes/utils + +** sigs.k8s.io/cluster-api; version v0.3.11-0.20210430210359-402a4524f006 -- +https://github.com/kubernetes-sigs/cluster-api + +** sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha3; version v0.7.8 -- +https://github.com/kubernetes-sigs/cluster-api-provider-vsphere + +** sigs.k8s.io/controller-runtime; version v0.9.0-beta.0 -- +https://github.com/kubernetes-sigs/controller-runtime + +** sigs.k8s.io/kustomize/api; version v0.8.5 -- +https://github.com/kubernetes-sigs/kustomize + +** sigs.k8s.io/kustomize/kyaml; version v0.10.15 -- +https://github.com/kubernetes-sigs/kustomize + +** sigs.k8s.io/structured-merge-diff/v4; version v4.1.0 -- +https://github.com/kubernetes-sigs/structured-merge-diff + + + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + +* For github.com/containerd/containerd see also this required NOTICE: +Docker +Copyright 2012-2015 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. + + +* For github.com/containers/storage see also this required NOTICE: +Docker +Copyright 2012-2016 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +This product contains software (https://github.com/kr/pty) developed +by Keith Rarick, licensed under the MIT License. + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. + + +* For github.com/docker/docker see also this required NOTICE: +Docker +Copyright 2012-2017 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +This product contains software (https://github.com/creack/pty) developed +by Keith Rarick, licensed under the MIT License. + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. + + +* For github.com/docker/go-metrics see also this required NOTICE: +Docker +Copyright 2012-2015 Docker, Inc. + +This product includes software developed at Docker, Inc. (https://www.docker.com). + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + +See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. + + +* For github.com/matttproud/golang_protobuf_extensions/pbutil see also this required NOTICE: +Copyright 2012 Matt T. Proud (matt.proud@gmail.com) + + +* For github.com/moby/spdystream see also this required NOTICE: +SpdyStream +Copyright 2014-2021 Docker Inc. + +This product includes software developed at +Docker Inc. (https://www.docker.com/). + + +* For github.com/opencontainers/runc/libcontainer see also this required NOTICE: +runc + +Copyright 2012-2015 Docker, Inc. + +This product includes software developed at Docker, Inc. (http://www.docker.com). + +The following is courtesy of our legal counsel: + + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see http://www.bis.doc.gov + +See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. + + +* For github.com/pquerna/ffjson see also this required NOTICE: +ffjson +Copyright (c) 2014, Paul Querna + +This product includes software developed by +Paul Querna (http://paul.querna.org/). + +Portions of this software were developed as +part of Go, Copyright (c) 2012 The Go Authors. + +* For github.com/prometheus/client_golang/prometheus see also this required NOTICE: +Prometheus instrumentation library for Go applications +Copyright 2012-2015 The Prometheus Authors + +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +The following components are included in this product: + +perks - a fork of https://github.com/bmizerany/perks +https://github.com/beorn7/perks +Copyright 2013-2015 Blake Mizerany, Björn Rabenstein +See https://github.com/beorn7/perks/blob/master/README.md for license details. + +Go support for Protocol Buffers - Google's data interchange format +http://github.com/golang/protobuf/ +Copyright 2010 The Go Authors +See source code for license details. + +Support for streaming Protocol Buffer messages for the Go language (golang). +https://github.com/matttproud/golang_protobuf_extensions +Copyright 2013 Matt T. Proud +Licensed under the Apache License, Version 2.0 + + +* For github.com/prometheus/client_model/go see also this required NOTICE: +Data model artifacts for Prometheus. +Copyright 2012-2015 The Prometheus Authors + +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +* For github.com/prometheus/common see also this required NOTICE: +Common libraries shared by Prometheus Go components. +Copyright 2015 The Prometheus Authors + +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +* For github.com/prometheus/procfs see also this required NOTICE: +procfs provides functions to retrieve system, kernel and process +metrics from the pseudo-filesystem proc. + +Copyright 2014-2015 The Prometheus Authors + +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +* For gopkg.in/yaml.v2 see also this required NOTICE: +Copyright 2011-2016 Canonical Ltd. + +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. + +------ + +** github.com/emirpasic/gods; version v1.12.0 -- +https://github.com/emirpasic/gods + +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + +AVL Tree: + +Copyright (c) 2017 Benjamin Scher Purcell + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +------ + +** github.com/go-redis/redis/v7; version v7.2.0 -- +https://github.com/go-redis/redis/v7 + +Copyright (c) 2013 The github.com/go-redis/redis Authors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/godbus/dbus; version v4.1.0+incompatible -- +https://github.com/godbus/dbus + +Copyright (c) 2013, Georg Reinke (), Google +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/magiconair/properties; version v1.8.1 -- +https://github.com/magiconair/properties + +goproperties - properties file decoder for Go + +Copyright (c) 2013-2018 - Frank Schroeder + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/pkg/errors; version v0.9.1 -- +https://github.com/pkg/errors + +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/syndtr/gocapability/capability; version v0.0.0-20200815063812-42c35b437635 -- +https://github.com/syndtr/gocapability + +Copyright 2013 Suryandaru Triandana +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** gopkg.in/warnings.v0; version v0.1.2 -- +https://gopkg.in/warnings.v0 + +Copyright (c) 2016 Péter Surányi. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/aws/aws-sdk-go/internal/sync/singleflight; version v1.38.40 -- +https://github.com/aws/aws-sdk-go + +** github.com/liggitt/tabwriter; version v0.0.0-20181228230101-89fcab3d43de -- +https://github.com/liggitt/tabwriter + +** github.com/ProtonMail/go-crypto; version v0.0.0-20210428141323-04723f9f07d7 -- +https://github.com/ProtonMail/go-crypto + +** golang.org/go; version go1.16.7 -- +https://github.com/golang/go + +** golang.org/x/crypto; version v0.0.0-20210513164829-c07d793c2f9a -- +https://go.googlesource.com/crypto + +** golang.org/x/net; version v0.0.0-20210428140749-89ef3d95e781 -- +https://go.googlesource.com/net + +** golang.org/x/oauth2; version v0.0.0-20200107190931-bf48bf16ab8d -- +https://go.googlesource.com/oauth2 + +** golang.org/x/sys; version v0.0.0-20210510120138-977fb7262007 -- +https://go.googlesource.com/sys + +** golang.org/x/term; version v0.0.0-20210220032956-6a3ed077a48d -- +https://go.googlesource.com/term + +** golang.org/x/text; version v0.3.6 -- +https://go.googlesource.com/text + +** golang.org/x/time/rate; version v0.0.0-20210220033141-f8bda1e9f3ba -- +https://go.googlesource.com/time + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/evanphx/json-patch; version v4.9.0+incompatible -- +https://github.com/evanphx/json-patch + +Copyright (c) 2014, Evan Phoenix +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the Evan Phoenix nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/fsnotify/fsnotify; version v1.4.9 -- +https://github.com/fsnotify/fsnotify + +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2012-2019 fsnotify Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/go-git/gcfg; version v1.5.0 -- +https://github.com/go-git/gcfg + +** gopkg.in/gcfg.v1; version v1.2.3 -- +https://gopkg.in/gcfg.v1 + +** gopkg.in/inf.v0; version v0.9.1 -- +https://gopkg.in/inf.v0 + +Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go +Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/gogo/protobuf; version v1.3.2 -- +https://github.com/gogo/protobuf + +Copyright (c) 2013, The GoGo Authors. All rights reserved. + +Protocol Buffers for Go with Gadgets + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------ + +** github.com/golang/protobuf; version v1.5.2 -- +https://github.com/golang/protobuf + +Copyright 2010 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------ + +** github.com/google/go-cmp/cmp; version v0.5.5 -- +https://github.com/google/go-cmp + +Copyright (c) 2017 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/google/go-github/v35/github; version v35.2.0 -- +https://github.com/google/go-github/v35 + +Copyright (c) 2013 The go-github AUTHORS. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/google/go-querystring/query; version v1.0.0 -- +https://github.com/google/go-querystring + +Copyright (c) 2013 Google. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/google/uuid; version v1.2.0 -- +https://github.com/google/uuid + +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/googleapis/gax-go/v2; version v2.0.5 -- +https://github.com/googleapis/gax-go/v2 + +Copyright 2016, Google Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/gorilla/mux; version v1.8.0 -- +https://github.com/gorilla/mux + +Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/imdario/mergo; version v0.3.12 -- +https://github.com/imdario/mergo + +Copyright (c) 2013 Dario Castañé. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/klauspost/compress; version v1.11.13 -- +https://github.com/klauspost/compress + +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2019 Klaus Post. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/klauspost/compress/snappy; version v1.11.13 -- +https://github.com/klauspost/compress + +Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/nguyer/promptui; version v0.8.1-0.20210517132806-70ccd4709797 -- +https://github.com/nguyer/promptui + +BSD 3-Clause License + +Copyright (c) 2017, Arigato Machine Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/pmezard/go-difflib/difflib; version v1.0.0 -- +https://github.com/pmezard/go-difflib + +Copyright (c) 2013, Patrick Mezard +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg; version v0.15.0 -- +https://github.com/prometheus/common + +Copyright (c) 2011, Open Knowledge Foundation Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + Neither the name of the Open Knowledge Foundation Ltd. nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------ + +** github.com/PuerkitoBio/purell; version v1.1.1 -- +https://github.com/PuerkitoBio/purell + +Copyright (c) 2012, Martin Angers +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/PuerkitoBio/urlesc; version v0.0.0-20170810143723-de5bf2ad4578 -- +https://github.com/PuerkitoBio/urlesc + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/shirou/gopsutil; version v3.21.1+incompatible -- +https://github.com/shirou/gopsutil + +gopsutil is distributed under BSD license reproduced below. + +Copyright (c) 2014, WAKAYAMA Shirou +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the gopsutil authors nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------- +internal/common/binary.go in the gopsutil is copied and modifid from golang/encoding/binary.go. + + + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------ + +** github.com/spf13/pflag; version v1.0.5 -- +https://github.com/spf13/pflag + +Copyright (c) 2012 Alex Ogier. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/ulikunitz/xz; version v0.5.9 -- +https://github.com/ulikunitz/xz + +Copyright (c) 2014-2020 Ulrich Kunitz +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* My name, Ulrich Kunitz, may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/vbatts/tar-split; version v0.11.1 -- +https://github.com/vbatts/tar-split + +Copyright (c) 2015 Vincent Batts, Raleigh, NC, USA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/willf/bitset; version v1.1.11 -- +https://github.com/bits-and-blooms/bitset + +Copyright (c) 2014 Will Fitzgerald. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** go.starlark.net; version v0.0.0-20200306205701-8dd3e2ee1dd5 -- +https://github.com/google/starlark-go + +Copyright (c) 2017 The Bazel Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** google.golang.org/api; version v0.22.0 -- +https://github.com/googleapis/google-api-go-client + +Copyright (c) 2011 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** google.golang.org/api/internal/third_party/uritemplates; version v0.22.0 -- +https://github.com/googleapis/google-api-go-client + +Copyright (c) 2013 Joshua Tacoma. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** google.golang.org/protobuf; version v1.26.0 -- +https://go.googlesource.com/protobuf + +Copyright (c) 2018 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------ + +** github.com/davecgh/go-spew/spew; version v1.1.1 -- +https://github.com/davecgh/go-spew + +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +------ + +** github.com/beorn7/perks/quantile; version v1.0.1 -- +https://github.com/beorn7/perks +Copyright (C) 2013 Blake Mizerany + +** github.com/blang/semver; version v3.5.1+incompatible -- +https://github.com/blang/semver +Copyright (c) 2014 Benedikt Lang + +** github.com/BurntSushi/toml; version v0.3.1 -- +https://github.com/BurntSushi/toml +Copyright (c) 2013 TOML authors + +** github.com/cespare/xxhash/v2; version v2.1.1 -- +https://github.com/cespare/xxhash/v2 +Copyright (c) 2016 Caleb Spare + +** github.com/chzyer/readline; version v0.0.0-20180603132655-2972be24d48e -- +https://github.com/chzyer/readline +Copyright (c) 2015 Chzyer + +** github.com/docker/docker-credential-helpers; version v0.6.3 -- +https://github.com/docker/docker-credential-helpers +Copyright (c) 2016 David Calavera + +** github.com/form3tech-oss/jwt-go; version v3.2.2+incompatible -- +https://github.com/form3tech-oss/jwt-go +Copyright (c) 2012 Dave Grijalva + +** github.com/go-errors/errors; version v1.0.1 -- +https://github.com/go-errors/errors +Copyright (c) 2015 Conrad Irwin + +** github.com/gobuffalo/flect; version v0.2.2 -- +https://github.com/gobuffalo/flect +Copyright (c) 2019 Mark Bates + +** github.com/gobwas/glob; version v0.2.3 -- +https://github.com/gobwas/glob +Copyright (c) 2016 Sergey Kamardin + +** github.com/jbenet/go-context/io; version v0.0.0-20150711004518-d14ea06fba99 -- +https://github.com/jbenet/go-context +Copyright (c) 2014 Juan Batiz-Benet + +** github.com/json-iterator/go; version v1.1.10 -- +https://github.com/json-iterator/go +Copyright (c) 2016 json-iterator + +** github.com/klauspost/compress/zstd/internal/xxhash; version v1.11.13 -- +https://github.com/klauspost/compress +Copyright (c) 2016 Caleb Spare + +** github.com/klauspost/pgzip; version v1.2.5 -- +https://github.com/klauspost/pgzip +Copyright (c) 2014 Klaus Post + +** github.com/mailru/easyjson; version v0.7.0 -- +https://github.com/mailru/easyjson +Copyright (c) 2016 Mail.Ru Group + +** github.com/mattn/go-isatty; version v0.0.12 -- +https://github.com/mattn/go-isatty +Copyright (c) Yasuhiro MATSUMOTO + +** github.com/mitchellh/go-homedir; version v1.1.0 -- +https://github.com/mitchellh/go-homedir +Copyright (c) 2013 Mitchell Hashimoto + +** github.com/mitchellh/go-testing-interface; version v1.0.0 -- +https://github.com/mitchellh/go-testing-interface +Copyright (c) 2016 Mitchell Hashimoto + +** github.com/mitchellh/mapstructure; version v1.1.2 -- +https://github.com/mitchellh/mapstructure +Copyright (c) 2013 Mitchell Hashimoto + +** github.com/monochromegane/go-gitignore; version v0.0.0-20200626010858-205db1a8cc00 -- +https://github.com/monochromegane/go-gitignore +Copyright (c) [2015] [go-gitignore] + +** github.com/onsi/gomega; version v1.14.0 -- +https://github.com/onsi/gomega +Copyright (c) 2013-2014 Onsi Fakhouri + +** github.com/pelletier/go-toml; version v1.8.1 -- +https://github.com/pelletier/go-toml +Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton + +** github.com/peterbourgon/diskv; version v2.0.1+incompatible -- +https://github.com/peterbourgon/diskv +Copyright (c) 2011-2012 Peter Bourgon + +** github.com/segmentio/ksuid; version v1.0.3 -- +https://github.com/segmentio/ksuid +Copyright (c) 2017 Segment.io + +** github.com/sergi/go-diff/diffmatchpatch; version v1.2.0 -- +https://github.com/sergi/go-diff +Copyright (c) 2012-2016 The go-diff Authors. All rights reserved. + +** github.com/sirupsen/logrus; version v1.7.0 -- +https://github.com/sirupsen/logrus +Copyright (c) 2014 Simon Eskildsen + +** github.com/spf13/cast; version v1.3.0 -- +https://github.com/spf13/cast +Copyright (c) 2014 Steve Francia + +** github.com/spf13/jwalterweatherman; version v1.0.0 -- +https://github.com/spf13/jwalterweatherman +Copyright (c) 2014 Steve Francia + +** github.com/spf13/viper; version v1.7.1 -- +https://github.com/spf13/viper +Copyright (c) 2014 Steve Francia + +** github.com/stretchr/testify/assert; version v1.7.0 -- +https://github.com/stretchr/testify +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +** github.com/subosito/gotenv; version v1.2.0 -- +https://github.com/subosito/gotenv +Copyright (c) 2013 Alif Rachmawadi + +** github.com/tchap/go-patricia/patricia; version v2.3.0+incompatible -- +https://github.com/tchap/go-patricia +Copyright (c) 2014 The AUTHORS + +** go.uber.org/atomic; version v1.7.0 -- +https://github.com/uber-go/atomic +Copyright (c) 2016 Uber Technologies, Inc. + +** go.uber.org/multierr; version v1.6.0 -- +https://github.com/uber-go/multierr +Copyright (c) 2017 Uber Technologies, Inc. + +** go.uber.org/zap; version v1.16.1-0.20210329175301-c23abee72d19 -- +https://github.com/uber-go/zap +Copyright (c) 2016-2017 Uber Technologies, Inc. + +** sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util; version v0.10.15 -- +https://github.com/kubernetes-sigs/kustomize +Copyright (c) 2018 QRI, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------ + +** github.com/bgentry/go-netrc/netrc; version v0.0.0-20140422174119-9fd32a8b3d3d -- +https://github.com/bgentry/go-netrc + +Original version Copyright © 2010 Fazlul Shahriar . Newer +portions Copyright © 2014 Blake Gentry . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +------ + +** github.com/ghodss/yaml; version v1.0.0 -- +https://github.com/ghodss/yaml +Copyright (c) 2014 Sam Ghods +Copyright (c) 2012 The Go Authors. All rights reserved. + +** sigs.k8s.io/yaml; version v1.2.0 -- +https://github.com/kubernetes-sigs/yaml +Copyright (c) 2014 Sam Ghods +Copyright (c) 2012 The Go Authors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. +* Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------ + +** github.com/gregjones/httpcache; version v0.0.0-20180305231024-9cad4c3443a7 -- +https://github.com/gregjones/httpcache + +Copyright © 2012 Greg Jones (greg.jones@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------ + +** github.com/kevinburke/ssh_config; version v0.0.0-20201106050909-4977a11b4351 -- +https://github.com/kevinburke/ssh_config +Copyright (c) 2017 Kevin Burke. +Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +=================== + +The lexer and parser borrow heavily from github.com/pelletier/go-toml. The +license for that project is copied below. + + + + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------ + +** github.com/lib/pq; version v1.3.0 -- +https://github.com/lib/pq +Copyright (c) 2011-2013, 'pq' Contributors +Copyright (C) 2011 Blake Mizerany + +Portions + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------ + +** github.com/xlab/treeprint; version v0.0.0-20181112141820-a009c3971eca -- +https://github.com/xlab/treeprint + +Copyright © 2016 Maxim Kupriianov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +------ + +** gopkg.in/yaml.v3; version v3.0.0-20200615113413-eeeca48fe776 -- +https://gopkg.in/yaml.v3 +Copyright (c) 2006-2010 Kirill Simonov +Copyright (c) 2006-2011 Kirill Simonov +Copyright (c) 2011-2019 Canonical Ltd + +This project is covered by two different licenses: MIT and Apache. + +#### MIT License #### + +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original MIT license, with the additional +copyright staring in 2011 when the project was ported over: + +apic.go emitterc.go parserc.go readerc.go scannerc.go +writerc.go yamlh.go yamlprivateh.go + + + + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +### Apache License ### + +All the remaining project files are covered by the Apache license: + + + +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. + +* For gopkg.in/yaml.v3 see also this required NOTICE: +Copyright 2011-2016 Canonical Ltd. + +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. + +------ + +** github.com/go-sql-driver/mysql; version v1.5.0 -- +https://github.com/go-sql-driver/mysql + + * Package github.com/go-sql-driver/mysql's source code may be found at: + https://github.com/go-sql-driver/mysql/tree/v1.5.0 + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +------ + +** github.com/hashicorp/errwrap; version v1.0.0 -- +https://github.com/hashicorp/errwrap + + * Package github.com/hashicorp/errwrap's source code may be found at: + https://github.com/hashicorp/errwrap/tree/v1.0.0 + +** github.com/hashicorp/go-getter; version v1.3.1-0.20190627223108-da0323b9545e -- +https://github.com/hashicorp/go-getter + + * Package github.com/hashicorp/go-getter's source code may be found at: + https://github.com/hashicorp/go-getter/tree/v1.3.1-0.20190627223108-da0323b9545e + +** github.com/hashicorp/go-version; version v1.2.0 -- +https://github.com/hashicorp/go-version + + * Package github.com/hashicorp/go-version's source code may be found at: + https://github.com/hashicorp/go-version/tree/v1.2.0 + +** github.com/hashicorp/hcl; version v1.0.0 -- +https://github.com/hashicorp/hcl + + * Package github.com/hashicorp/hcl's source code may be found at: + https://github.com/hashicorp/hcl/tree/v1.0.0 + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + + +------ + +** github.com/hashicorp/go-cleanhttp; version v0.5.1 -- +https://github.com/hashicorp/go-cleanhttp + + * Package github.com/hashicorp/go-cleanhttp's source code may be found at: + https://github.com/hashicorp/go-cleanhttp/tree/v0.5.1 + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + + +------ + +** github.com/hashicorp/go-multierror; version v1.1.1 -- +https://github.com/hashicorp/go-multierror + + * Package github.com/hashicorp/go-multierror's source code may be found at: + https://github.com/hashicorp/go-multierror/tree/v1.1.1 + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + +------ + +** github.com/hashicorp/go-safetemp; version v1.0.0 -- +https://github.com/hashicorp/go-safetemp + + * Package github.com/hashicorp/go-safetemp's source code may be found at: + https://github.com/hashicorp/go-safetemp/tree/v1.0.0 + +** github.com/hashicorp/golang-lru; version v0.5.4 -- +https://github.com/hashicorp/golang-lru + + * Package github.com/hashicorp/golang-lru's source code may be found at: + https://github.com/hashicorp/golang-lru/tree/v0.5.4 + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + +------ diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 000000000000..63e15a589a3b --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,26 @@ +## Development + +### Generate/Update Mocks + +#### Prerequisites + +1. We need mockgen installed, `go get github.com/golang/mock/mockgen` +2. Verify the binary was installed, `$GOPATH/bin/mockgen` + +#### Generate/Update + +To generate or update Mocks for an interface in a package, use the following +command: + +```bash +make mocks +``` + +If you are mocking a new interface for testing, be sure to update the Makefile +target `mocks` to include the new interface. + +```Makefile +.PHONY: mocks +mocks: + mockgen -destination=pkg//mocks/.go -package=mocks "github.com/aws/eks-anywhere/" +``` diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..7e3bfc619a24 --- /dev/null +++ b/Makefile @@ -0,0 +1,298 @@ +export INTEGRATION_TEST_UBUNTU_AMI_ID?=integration_test_ami +export INTEGRATION_TEST_STORAGE_BUCKET?=integration_test_storage_bucket +export INTEGRATION_TEST_INSTANCE_PROFILE?=integration_test_instance_profile +export INTEGRATION_TEST_MAX_INSTANCE_AGE?=86400 +export INTEGRATION_TEST_SUBNET_ID?=integration_test_subnet_id +export INTEGRATION_TEST_INSTANCE_TAG?=integration_test_instance_tag +export JOB_ID?=${PROW_JOB_ID} +GO_TEST ?= go test +GIT_VERSION?=$(shell git describe --tag) + +RELEASE_MANIFEST_URL?=https://dev-release-prod-pdx.s3.us-west-2.amazonaws.com/eks-a-release.yaml +DEV_GIT_VERSION:=v0.0.0-dev + +BIN_DIR := bin +TOOLS_BIN_DIR := hack/tools/bin + +KUSTOMIZE := $(TOOLS_BIN_DIR)/kustomize +KUSTOMIZE_VERSION := 4.2.0 + +KUBEBUILDER := $(TOOLS_BIN_DIR)/kubebuilder +KUBEBUILDER_VERSION := v3.1.0 + +CONTROLLER_GEN_BIN := contoller-gen +CONTROLLER_GEN := $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN) + +# This removes the compile dependency on C libraries from github.com/containers/storage which is imported by github.com/replicatedhq/troubleshoot +BUILD_TAGS := exclude_graphdriver_btrfs exclude_graphdriver_devicemapper + +GO_ARCH:=$(shell go env GOARCH) +GO_OS:=$(shell go env GOOS) + +DOCKER_E2E_TEST := TestDockerKubernetes121SimpleFlow + +.PHONY: build +build: eks-a eks-a-tool lint unit-test ## Generate binaries, run go lint and unit tests + +.PHONY: release +release: eks-a-release unit-test ## Generate release binary and run unit tests + +.PHONY: eks-a-binary +eks-a-binary: ALL_LINKER_FLAGS := $(LINKER_FLAGS) -X github.com/aws/eks-anywhere/pkg/version.gitVersion=$(GIT_VERSION) -X github.com/aws/eks-anywhere/pkg/cluster.releasesManifestURL=$(RELEASE_MANIFEST_URL) +eks-a-binary: LINKER_FLAGS_ARG := -ldflags "$(ALL_LINKER_FLAGS)" +eks-a-binary: BUILD_TAGS_ARG := -tags "$(BUILD_TAGS)" +eks-a-binary: OUTPUT_FILE ?= bin/eks-a +eks-a-binary: + GOOS=$(GO_OS) GOARCH=$(GO_ARCH) go build $(BUILD_TAGS_ARG) $(LINKER_FLAGS_ARG) -o $(OUTPUT_FILE) github.com/aws/eks-anywhere/cmd/eks-a + +.PHONY: eks-a-embed-config +eks-a-embed-config: ## Build a dev release version of eks-a with embed cluster spec config + $(MAKE) eks-a-binary GIT_VERSION=$(DEV_GIT_VERSION) RELEASE_MANIFEST_URL=embed:///config/releases.yaml BUILD_TAGS='$(BUILD_TAGS) spec_embed_config' + +.PHONY: eks-a +eks-a: ## Build a dev release version of eks-a + $(MAKE) eks-a-binary GIT_VERSION=$(DEV_GIT_VERSION) + +.PHONY: eks-a-release +eks-a-release: ## Generate a release binary + $(MAKE) eks-a-binary GO_OS=linux GO_ARCH=amd64 LINKER_FLAGS='-s -w -X github.com/aws/eks-anywhere/pkg/eksctl.enabled=true' + +.PHONY: eks-a-cross-platform +eks-a-cross-platform: ## Generate binaries for Linux and MacOS + $(MAKE) eks-a-binary GIT_VERSION=$(DEV_GIT_VERSION) GO_OS=darwin GO_ARCH=amd64 OUTPUT_FILE=bin/darwin/eks-a + $(MAKE) eks-a-binary GIT_VERSION=$(DEV_GIT_VERSION) GO_OS=linux GO_ARCH=amd64 OUTPUT_FILE=bin/linux/eks-a + +.PHONY: eks-a-release-cross-platform +eks-a-release-cross-platform: ## Generate binaries for Linux and MacOS + $(MAKE) eks-a-binary GO_OS=darwin GO_ARCH=amd64 OUTPUT_FILE=bin/darwin/eks-a LINKER_FLAGS='-s -w -X github.com/aws/eks-anywhere/pkg/eksctl.enabled=true' + $(MAKE) eks-a-binary GO_OS=linux GO_ARCH=amd64 OUTPUT_FILE=bin/linux/eks-a LINKER_FLAGS='-s -w -X github.com/aws/eks-anywhere/pkg/eksctl.enabled=true' + +$(TOOLS_BIN_DIR): + mkdir -p $(TOOLS_BIN_DIR) + +$(KUSTOMIZE): $(TOOLS_BIN_DIR) + cd $(TOOLS_BIN_DIR) && curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | sh -s $(KUSTOMIZE_VERSION) + +$(KUBEBUILDER): $(TOOLS_BIN_DIR) + cd $(TOOLS_BIN_DIR) && curl -L -o kubebuilder https://go.kubebuilder.io/dl/$(KUBEBUILDER_VERSION)/$(GO_OS)/$(GO_ARCH) + chmod +x $(KUBEBUILDER) + +$(CONTROLLER_GEN): $(TOOLS_BIN_DIR) + cd $(TOOLS_BIN_DIR); go build -tags=tools -o $(CONTROLLER_GEN_BIN) sigs.k8s.io/controller-tools/cmd/controller-gen + +.PHONY: lint +lint: bin/golangci-lint ## Run golangci-lint + bin/golangci-lint run + +bin/golangci-lint: ## Download golangci-lint + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.39.0 + +.PHONY: build-cross-platform +build-cross-platform: eks-a-cross-platform + +.PHONY: eks-a-tool +eks-a-tool: ## Build eks-a-tool + go build -o bin/eks-a-tool github.com/aws/eks-anywhere/cmd/eks-a-tool + +.PHONY: eks-a-cluster-controller +eks-a-cluster-controller: ## Build eks-a-cluster-controller + go build -ldflags "-s -w -buildid='' -extldflags -static" -o bin/manager ./controllers + +# This target will copy LICENSE file from root to the release submodule +# when fetching licenses for cluster-controller +.PHONY: copy-license-cluster-controller +copy-license-cluster-controller: SHELL := /bin/bash +copy-license-cluster-controller: + source scripts/attribution_helpers.sh && build::fix_licenses + +# Build target invoked by build-tooling repo script +.PHONY: build-cluster-controller +build-cluster-controller: eks-a-cluster-controller copy-license-cluster-controller + +.PHONY: generate-attribution +generate-attribution: GOLANG_VERSION ?= "1.16" +generate-attribution: + scripts/make_attribution.sh $(GOLANG_VERSION) + +.PHONY: update-attribution-files +update-attribution-files: generate-attribution + scripts/create_pr.sh + +.PHONY: clean +clean: ## Clean up resources created by make targets + rm -rf ./bin/* + rm -rf ./pkg/executables/cluster-name/ + rm -rf ./pkg/providers/vsphere/test/ + find . -depth -name 'folderWriter*' -exec rm -rf {} \; + rm -rf ./controllers/bin/* + rm -rf vendor + rm -rf GIT_TAG + rm -rf _output + make -C docs clean + +# +# Generate zz_generated.deepcopy.go +# +generate: $(CONTROLLER_GEN) ## Generate zz_generated.deepcopy.go + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: test +test: unit-test capd-test ## Run unit and capd tests + +.PHONY: unit-test +unit-test: ## Run unit tests + $(GO_TEST) ./... -cover -tags "$(BUILD_TAGS)" + +.PHONY: capd-test +capd-test: e2e ## Run default e2e capd test locally + ./bin/e2e.test -test.v -test.run $(DOCKER_E2E_TEST) + +.PHONY: docker-e2e-test +docker-e2e-test: e2e ## Run docker integration test in new ec2 instance + scripts/e2e_test_docker.sh $(DOCKER_E2E_TEST) + +.PHONY: e2e-cleanup +e2e-cleanup: e2e ## Clean up resources generated by e2e tests + scripts/e2e_cleanup.sh + +.PHONY: vsphere-e2e-test +vsphere-e2e-test: build-cross-platform ## Run vsphere integration tests + go run cmd/integration_test/main.go e2e vsphere \ + -a ${INTEGRATION_TEST_UBUNTU_AMI_ID} \ + -s ${INTEGRATION_TEST_STORAGE_BUCKET} \ + -j ${JOB_ID} \ + -i ${INTEGRATION_TEST_INSTANCE_PROFILE} \ + -n ${INTEGRATION_TEST_SUBNET_ID} \ + -d false + +.PHONY: build-e2e-test-binaries +build-e2e-test-binaries: build build-cross-platform ## Build e2e binaries + go build -o bin/eks-a-e2e github.com/aws/eks-anywhere/cmd/integration_test + +.PHONY: capd-test-all +capd-test-all: capd-test-118 capd-test capd-test-120 + +.PHONY: capd-test-% +capd-test-%: e2e ## Run CAPD tests + ./bin/e2e.test -test.v -test.run TestDockerKubernetes$*SimpleFlow + +.PHONY: mocks +mocks: ## Generate mocks + go get github.com/golang/mock/mockgen@v1.5.0 + ${GOPATH}/bin/mockgen -destination=pkg/providers/mocks/providers.go -package=mocks "github.com/aws/eks-anywhere/pkg/providers" Provider,DatacenterConfig,MachineConfig + ${GOPATH}/bin/mockgen -destination=pkg/executables/mocks/executables.go -package=mocks "github.com/aws/eks-anywhere/pkg/executables" Executable + ${GOPATH}/bin/mockgen -destination=pkg/providers/aws/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/providers/aws" ProviderClient,ProviderKubectlClient + ${GOPATH}/bin/mockgen -destination=pkg/providers/docker/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/providers/docker" ProviderClient,ProviderKubectlClient + ${GOPATH}/bin/mockgen -destination=pkg/providers/vsphere/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/providers/vsphere" ProviderGovcClient,ProviderKubectlClient + ${GOPATH}/bin/mockgen -destination=pkg/filewriter/mocks/filewriter.go -package=mocks "github.com/aws/eks-anywhere/pkg/filewriter" FileWriter + ${GOPATH}/bin/mockgen -destination=pkg/clustermanager/mocks/client_and_networking.go -package=mocks "github.com/aws/eks-anywhere/pkg/clustermanager" ClusterClient,Networking + ${GOPATH}/bin/mockgen -destination=pkg/addonmanager/addonclients/mocks/fluxaddonclient.go -package=mocks "github.com/aws/eks-anywhere/pkg/addonmanager/addonclients" Flux + ${GOPATH}/bin/mockgen -destination=pkg/task/mocks/task.go -package=mocks "github.com/aws/eks-anywhere/pkg/task" Task + ${GOPATH}/bin/mockgen -destination=pkg/bootstrapper/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/bootstrapper" ClusterClient + ${GOPATH}/bin/mockgen -destination=pkg/cluster/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/cluster" ClusterClient + ${GOPATH}/bin/mockgen -destination=pkg/workflows/interfaces/mocks/clients.go -package=mocks "github.com/aws/eks-anywhere/pkg/workflows/interfaces" Bootstrapper,ClusterManager,AddonManager,Validator + ${GOPATH}/bin/mockgen -destination=pkg/git/providers/github/mocks/github.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/providers/github" GitProviderClient,GithubProviderClient + ${GOPATH}/bin/mockgen -destination=pkg/git/mocks/git.go -package=mocks "github.com/aws/eks-anywhere/pkg/git" Provider + ${GOPATH}/bin/mockgen -destination=pkg/git/gogithub/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/gogithub" Client + ${GOPATH}/bin/mockgen -destination=pkg/git/gogit/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/gogit" GoGitClient + ${GOPATH}/bin/mockgen -destination=pkg/validations/mocks/docker.go -package=mocks "github.com/aws/eks-anywhere/pkg/validations" DockerExecutable + ${GOPATH}/bin/mockgen -destination=controllers/controllers/resource/mocks/resource.go -package=mocks "github.com/aws/eks-anywhere/controllers/controllers/resource" ResourceFetcher,ResourceUpdater + ${GOPATH}/bin/mockgen -destination=pkg/providers/vsphere/internal/templates/mocks/govc.go -package=mocks -source "pkg/providers/vsphere/internal/templates/factory.go" GovcClient + ${GOPATH}/bin/mockgen -destination=pkg/providers/vsphere/internal/tags/mocks/govc.go -package=mocks -source "pkg/providers/vsphere/internal/tags/factory.go" GovcClient + ${GOPATH}/bin/mockgen -destination=pkg/validations/upgradevalidations/mocks/upgradevalidations.go -package=mocks -source "pkg/validations/upgradevalidations/upgradevalidations.go" ValidationsKubectlClient + +.PHONY: verify-mocks +verify-mocks: mocks ## Verify if mocks need to be updated + $(eval DIFF=$(shell git diff --raw -- '*.go' | wc -c)) + if [[ $(DIFF) != 0 ]]; then \ + echo "Detected out of date mocks"; \ + exit 1;\ + fi + +.PHONY: e2e +e2e: e2e-tests-binary integration-test-binary ## Run integration tests + if [ "$(CODEBUILD_CI)" = "true" ]; then \ + make eks-a-cross-platform; \ + else \ + make eks-a; \ + fi + +.PHONY: e2e-tests-binary +e2e-tests-binary: + go test ./test/e2e -c -o bin/e2e.test -tags e2e -ldflags "-X github.com/aws/eks-anywhere/pkg/version.gitVersion=$(DEV_GIT_VERSION)" + +.PHONY: integration-test-binary +integration-test-binary: + go build -o bin/test github.com/aws/eks-anywhere/cmd/integration_test + +.PHONY: help +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[%\/0-9A-Za-z_-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: generate-manifests +generate-manifests: ## Generate manifests e.g. CRD, RBAC etc. + $(MAKE) generate-core-manifests + +.PHONY: generate-core-manifests +generate-core-manifests: $(CONTROLLER_GEN) ## Generate manifests for the core provider e.g. CRD, RBAC etc. + $(CONTROLLER_GEN) \ + paths=./pkg/api/... \ + paths=./controllers/... \ + crd:crdVersions=v1 \ + rbac:roleName=manager-role \ + output:crd:dir=./config/crd/bases \ + output:webhook:dir=./config/webhook \ + webhook + +GOLANG_VERSION := 1.16.2 +REGISTRY ?= public.ecr.aws/a2k4d8v8 +IMAGE_NAME ?= eksa-cluster-controller +CONTROLLER_IMG ?= $(REGISTRY)/$(IMAGE_NAME) + +TAG ?= dev +ARCH ?= amd64 + +CONTROLLER_IMG_TAGGED ?= $(CONTROLLER_IMG)-$(ARCH):$(TAG) + +LDFLAGS := $(shell hack/version.sh) + +.PHONY: docker-build +docker-build: + $(MAKE) ARCH=$(ARCH) docker-build-core + +.PHONY: docker-build-core +docker-build-core: docker-pull-prerequisites ## Build the docker image for controller-manager + DOCKER_BUILDKIT=1 docker build --build-arg ARCH=$(ARCH) --build-arg ldflags="$(LDFLAGS)" . -t CONTROLLER_IMG_TAGGED -f build/Dockerfile + +.PHONY: docker-push +docker-push: ## Push the docker image + docker push CONTROLLER_IMG_TAGGED + +.PHONY: docker-pull-prerequisites +docker-pull-prerequisites: + docker pull docker.io/docker/dockerfile:1.1-experimental + docker pull docker.io/library/golang:$(GOLANG_VERSION) + docker pull gcr.io/distroless/static:latest + +## TODO update release folder +RELEASE_DIR := config/manifest + +$(RELEASE_DIR): + mkdir -p $(RELEASE_DIR)/ + +.PHONY: release-manifests +release-manifests: $(KUSTOMIZE) generate-manifests $(RELEASE_DIR) ## Builds the manifests to publish with a release + # Build core-components. + $(KUSTOMIZE) build config/prod > $(RELEASE_DIR)/eksa-components.yaml + +.PHONY: e2e-cleanup-postsubmit # Temporary target to make postsubmit cleanup job work. +e2e-cleanup-postsubmit: + go run cmd/integration_test/main.go e2e cleanup \ + -s ${INTEGRATION_TEST_STORAGE_BUCKET} \ + -a ${INTEGRATION_TEST_MAX_INSTANCE_AGE} \ + -t ${INTEGRATION_TEST_INSTANCE_TAG} \ + -d false + +.PHONY: run-controller # Run eksa controller from local repo with tilt +run-controller: + tilt up --file controllers/Tiltfile diff --git a/PROJECT b/PROJECT new file mode 100644 index 000000000000..8cc753bdc60f --- /dev/null +++ b/PROJECT @@ -0,0 +1,71 @@ +domain: eks.amazonaws.com +layout: +- go.kubebuilder.io/v3 +projectName: eksa +repo: github.com/aws/eks-anywhere +resources: +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: Cluster + version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: AWSDatacenterConfig + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: DockerDatacenterConfig + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: VSphereDatacenterConfig + version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: VSphereMachineConfig + version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: GitOpsConfig + version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + domain: eks.amazonaws.com + group: anywhere + kind: OIDCConfig + version: v1alpha1 + webhooks: + validation: true + webhookVersion: v1 +version: "3" diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 000000000000..729b808172d9 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,48 @@ +# syntax=docker/dockerfile:1.1-experimental + +# Build the manager binary +FROM golang:1.16.2 as builder +WORKDIR /workspace + +# Run this with docker build --build_arg $(go env GOPROXY) to override the goproxy +ARG goproxy=direct +ENV GOPROXY=$goproxy + +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum + +COPY release/go.mod release/go.mod +COPY release/go.sum release/go.sum + +# Cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +# Copy the sources +COPY ./ ./ + +# Cache the go build into the the Go’s compiler cache folder so we take benefits of compiler caching across docker build calls +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg/mod \ + go build -o main ./controllers + +# Build +ARG package=./controllers +ARG ARCH +ARG ldflags + +# Do not force rebuild of up-to-date packages (do not use -a) and use the compiler cache folder +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg/mod \ + CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} \ + go build -ldflags "${ldflags} -extldflags '-static'" \ + -o manager ${package} + +# Production image +FROM gcr.io/distroless/static:latest +WORKDIR / +COPY --from=builder /workspace/manager . +USER nobody +ENTRYPOINT ["/manager"] diff --git a/cmd/.DS_Store b/cmd/.DS_Store new file mode 100644 index 000000000000..50f3d8964ef1 Binary files /dev/null and b/cmd/.DS_Store differ diff --git a/cmd/eks-a-tool/cmd/conformance.go b/cmd/eks-a-tool/cmd/conformance.go new file mode 100644 index 000000000000..a4e8a55f3446 --- /dev/null +++ b/cmd/eks-a-tool/cmd/conformance.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var conformanceCmd = &cobra.Command{ + Use: "conformance", + Short: "Conformance tests", + Long: "Use eks-a-tool conformance to run conformance tests", +} + +func init() { + rootCmd.AddCommand(conformanceCmd) +} diff --git a/cmd/eks-a-tool/cmd/conformancedownload.go b/cmd/eks-a-tool/cmd/conformancedownload.go new file mode 100644 index 000000000000..8b89a63c524d --- /dev/null +++ b/cmd/eks-a-tool/cmd/conformancedownload.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/internal/pkg/conformance" +) + +var conformanceDownloadCmd = &cobra.Command{ + Use: "download", + Short: "Conformance download command", + Long: "This command downloads the conformance test suite", + RunE: func(cmd *cobra.Command, args []string) error { + err := conformance.Download() + if err != nil { + log.Fatalf("Error downloading conformance: %v", err) + } + return nil + }, +} + +func init() { + conformanceCmd.AddCommand(conformanceDownloadCmd) + err := viper.BindPFlags(conformanceDownloadCmd.Flags()) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } +} diff --git a/cmd/eks-a-tool/cmd/conformancetest.go b/cmd/eks-a-tool/cmd/conformancetest.go new file mode 100644 index 000000000000..9ec27832ae9b --- /dev/null +++ b/cmd/eks-a-tool/cmd/conformancetest.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/internal/pkg/conformance" +) + +var conformanceTestCmd = &cobra.Command{ + Use: "test ", + Short: "Conformance test command", + Long: "This command run the conformance tests", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + log.Fatalf("Error running sonobuoy: cluster context not provided") + } + results, err := conformance.RunTests(cmd.Context(), args[0]) + if err != nil { + log.Fatalf("Error running sonobuoy: %v", err) + } + log.Printf("Conformance Test results:\n %v", results) + return nil + }, +} + +func init() { + conformanceCmd.AddCommand(conformanceTestCmd) + err := viper.BindPFlags(conformanceTestCmd.Flags()) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } +} diff --git a/cmd/eks-a-tool/cmd/root.go b/cmd/eks-a-tool/cmd/root.go new file mode 100644 index 000000000000..b93c9ad102fd --- /dev/null +++ b/cmd/eks-a-tool/cmd/root.go @@ -0,0 +1,43 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/logger" +) + +var rootCmd = &cobra.Command{ + Use: "eks-a-tool", + Short: "Amazon EKS Anywhere Tool", + Long: `Use eks-a-tool to validate your cluster`, + PersistentPreRun: rootPersistentPreRun, +} + +func init() { + rootCmd.PersistentFlags().IntP("verbosity", "v", 0, "Set the log level verbosity") + if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { + log.Fatalf("failed to bind flags for root: %v", err) + } +} + +func rootPersistentPreRun(cmd *cobra.Command, args []string) { + if err := initLogger(); err != nil { + log.Fatal(err) + } +} + +func initLogger() error { + if err := logger.InitZap(viper.GetInt("verbosity")); err != nil { + return fmt.Errorf("failed init zap logger in root command: %v", err) + } + + return nil +} + +func Execute() error { + return rootCmd.Execute() +} diff --git a/cmd/eks-a-tool/cmd/uniqueip.go b/cmd/eks-a-tool/cmd/uniqueip.go new file mode 100644 index 000000000000..5c3e4c81be98 --- /dev/null +++ b/cmd/eks-a-tool/cmd/uniqueip.go @@ -0,0 +1,52 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/networkutils" +) + +var uniqueIpCmd = &cobra.Command{ + Use: "unique-ip", + Short: "Unique IP", + Long: "Generate a random unique IP to be used for control plane endpoint ip", + PreRun: preRunUniqueIp, + RunE: func(cmd *cobra.Command, args []string) error { + uniqueIp, err := generateUniqueIP(cmd.Context()) + if err != nil { + log.Fatalf("Error generating unique ip: %v", err) + } + fmt.Println(uniqueIp) + return nil + }, +} + +func init() { + rootCmd.AddCommand(uniqueIpCmd) + uniqueIpCmd.Flags().StringP("cidr", "c", "", "CIDR range for the unique IP") + err := uniqueIpCmd.MarkFlagRequired("cidr") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func preRunUniqueIp(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +func generateUniqueIP(ctx context.Context) (string, error) { + cidr := viper.GetString("cidr") + ipgen := networkutils.NewIPGenerator(&networkutils.DefaultNetClient{}) + return ipgen.GenerateUniqueIP(cidr) +} diff --git a/cmd/eks-a-tool/cmd/validatecluster.go b/cmd/eks-a-tool/cmd/validatecluster.go new file mode 100644 index 000000000000..065ff1694aa7 --- /dev/null +++ b/cmd/eks-a-tool/cmd/validatecluster.go @@ -0,0 +1,61 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/validations" +) + +var validateClusterCmd = &cobra.Command{ + Use: "validate-cluster ", + Short: "Validate eks-a cluster command", + Long: "Use eks-a-tool validate eks-anywhere cluster", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) < 2 { + log.Fatalf("Some args are missing. See usage for required arguments") + } + clusterName, err := validations.ValidateClusterNameArg(args) + if err != nil { + log.Fatalf("Error validating the cluster: %v", err) + } + kubeconfig := args[1] + if !validations.FileExists(kubeconfig) { + log.Fatalf("Error validating the cluster: kubeconfig file %s not found", kubeconfig) + } + err = validateCluster(cmd.Context(), clusterName, kubeconfig) + if err != nil { + log.Fatalf("Error validating the cluster: %v", err) + } + return nil + }, +} + +func init() { + rootCmd.AddCommand(validateClusterCmd) +} + +func validateCluster(ctx context.Context, clusterName string, kubeconfig string) error { + executableBuilder, err := executables.NewExecutableBuilder(ctx, executables.DefaultEksaImage()) + if err != nil { + return fmt.Errorf("unable to initialize executables: %v", err) + } + kubectl := executableBuilder.BuildKubectlExecutable() + err = kubectl.ValidateNodes(ctx, kubeconfig) + if err != nil { + return err + } + err = kubectl.ValidateControlPlaneNodes(ctx, clusterName, kubeconfig) + if err != nil { + return err + } + err = kubectl.ValidateWorkerNodes(ctx, clusterName, kubeconfig) + if err != nil { + return err + } + return kubectl.ValidatePods(ctx, kubeconfig) +} diff --git a/cmd/eks-a-tool/cmd/versions.go b/cmd/eks-a-tool/cmd/versions.go new file mode 100644 index 000000000000..4a7eaab563a3 --- /dev/null +++ b/cmd/eks-a-tool/cmd/versions.go @@ -0,0 +1,36 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + + "github.com/aws/eks-anywhere/pkg/executables" +) + +var versionsCmd = &cobra.Command{ + Use: "versions", + Short: "Get cluster versions", + Long: "Get the versions of images in cluster", + RunE: func(cmd *cobra.Command, args []string) error { + err := versions(cmd.Context()) + if err != nil { + log.Fatalf("Error getting image versions: %v", err) + } + return nil + }, +} + +func init() { + rootCmd.AddCommand(versionsCmd) +} + +func versions(ctx context.Context) error { + executableBuilder, err := executables.NewExecutableBuilder(ctx, executables.DefaultEksaImage()) + if err != nil { + return fmt.Errorf("unable to initialize executables: %v", err) + } + return executableBuilder.BuildKubectlExecutable().ListCluster(ctx) +} diff --git a/cmd/eks-a-tool/cmd/vsphere.go b/cmd/eks-a-tool/cmd/vsphere.go new file mode 100644 index 000000000000..f4739df8442b --- /dev/null +++ b/cmd/eks-a-tool/cmd/vsphere.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var vsphereCmd = &cobra.Command{ + Use: "vsphere", + Short: "VSphere commands", + Long: "Use eks-a-tool vsphere to run vsphere utilities", +} + +func init() { + rootCmd.AddCommand(vsphereCmd) +} diff --git a/cmd/eks-a-tool/cmd/vsphereautofill.go b/cmd/eks-a-tool/cmd/vsphereautofill.go new file mode 100644 index 000000000000..ecc194441391 --- /dev/null +++ b/cmd/eks-a-tool/cmd/vsphereautofill.go @@ -0,0 +1,146 @@ +package cmd + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "sigs.k8s.io/yaml" + + "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/validations" +) + +var autofillCmd = &cobra.Command{ + Use: "autofill", + Short: "Autofill provider config", + Long: "Fills provider config with values set in environment variables", + PreRun: preRunAutofill, + RunE: func(cmd *cobra.Command, args []string) error { + err := autofill(cmd.Context()) + if err != nil { + log.Fatalf("Error filling the provider config: %v", err) + } + return nil + }, +} + +func init() { + vsphereCmd.AddCommand(autofillCmd) + autofillCmd.Flags().StringP("filename", "f", "", "Cluster config yaml filepath") + err := autofillCmd.MarkFlagRequired("filename") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func preRunAutofill(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +func autofill(ctx context.Context) error { + clusterConfigFileName := viper.GetString("filename") + clusterConfigFileExist := validations.FileExists(clusterConfigFileName) + if !clusterConfigFileExist { + return fmt.Errorf("the cluster config file %s does not exist", clusterConfigFileName) + } + clusterConfig, err := v1alpha1.GetAndValidateClusterConfig(clusterConfigFileName) + if err != nil { + return fmt.Errorf("unable to get cluster config from file: %v", err) + } + datacenterConfig, err := v1alpha1.GetVSphereDatacenterConfig(clusterConfigFileName) + if err != nil { + return fmt.Errorf("unable to get datacenter config from file: %v", err) + } + machineConfig, err := v1alpha1.GetVSphereMachineConfigs(clusterConfigFileName) + if err != nil { + return fmt.Errorf("unable to get machine config from file: %v", err) + } + controlPlaneMachineConfig := machineConfig[clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name] + workerMachineConfig := machineConfig[clusterConfig.Spec.WorkerNodeGroupConfigurations[0].MachineGroupRef.Name] + var updatedFields []string + updateField := func(envName string, field *string) { + if value, set := os.LookupEnv(envName); set && len(value) > 0 { + *field = value + updatedFields = append(updatedFields, envName) + } + } + + updateFieldInt := func(envName string, field *int) { + if value, set := os.LookupEnv(envName); set && len(value) > 0 { + val, _ := strconv.Atoi(value) + *field = val + updatedFields = append(updatedFields, envName) + } + } + tlsInsecure := strconv.FormatBool(datacenterConfig.Spec.Insecure) + updateField("CONTROL_PLANE_ENDPOINT_IP", &clusterConfig.Spec.ControlPlaneConfiguration.Endpoint.Host) + updateField("DATACENTER", &datacenterConfig.Spec.Datacenter) + updateField("NETWORK", &datacenterConfig.Spec.Network) + updateField("SERVER", &datacenterConfig.Spec.Server) + updateField("INSECURE", &tlsInsecure) + updateField("THUMBPRINT", &datacenterConfig.Spec.Thumbprint) + + updateFieldInt("CONTROL_PLANE_COUNT", &clusterConfig.Spec.ControlPlaneConfiguration.Count) + updateFieldInt("WORKER_NODE_COUNT", &clusterConfig.Spec.WorkerNodeGroupConfigurations[0].Count) + + updateField("SSH_AUTHORIZED_KEY", &controlPlaneMachineConfig.Spec.Users[0].SshAuthorizedKeys[0]) + updateField("SSH_USERNAME", &controlPlaneMachineConfig.Spec.Users[0].Name) + updateField("TEMPLATE", &controlPlaneMachineConfig.Spec.Template) + updateField("DATASTORE", &controlPlaneMachineConfig.Spec.Datastore) + updateField("FOLDER", &controlPlaneMachineConfig.Spec.Folder) + updateField("RESOURCE_POOL", &controlPlaneMachineConfig.Spec.ResourcePool) + updateField("STORAGE_POLICY_NAME", &controlPlaneMachineConfig.Spec.StoragePolicyName) + + updateField("SSH_AUTHORIZED_KEY", &workerMachineConfig.Spec.Users[0].SshAuthorizedKeys[0]) + updateField("SSH_USERNAME", &workerMachineConfig.Spec.Users[0].Name) + updateField("TEMPLATE", &workerMachineConfig.Spec.Template) + updateField("DATASTORE", &workerMachineConfig.Spec.Datastore) + updateField("FOLDER", &workerMachineConfig.Spec.Folder) + updateField("RESOURCE_POOL", &workerMachineConfig.Spec.ResourcePool) + updateField("STORAGE_POLICY_NAME", &workerMachineConfig.Spec.StoragePolicyName) + + clusterOutput, err := yaml.Marshal(clusterConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + datacenterOutput, err := yaml.Marshal(datacenterConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + controlPlaneMachineOutput, err := yaml.Marshal(controlPlaneMachineConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + workerMachineOutput, err := yaml.Marshal(workerMachineConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + result := strings.ReplaceAll(string(datacenterOutput), " aws: {}\n", "") + result = strings.ReplaceAll(result, " vsphere: {}\n", "") + result = string(clusterOutput) + "\n---\n" + result + "\n---\n" + string(controlPlaneMachineOutput) + "\n---\n" + string(workerMachineOutput) + + writer, err := filewriter.NewWriter(filepath.Dir(clusterConfig.Name)) + if err != nil { + return err + } + _, err = writer.Write(filepath.Base(clusterConfig.Name), []byte(result)) + if err != nil { + return fmt.Errorf("error writing to file %s: %v", clusterConfig.Name, err) + } + fmt.Printf("The following fields were updated: %v\n", updatedFields) + return nil +} diff --git a/cmd/eks-a-tool/cmd/vsphererm.go b/cmd/eks-a-tool/cmd/vsphererm.go new file mode 100644 index 000000000000..fac00de28c9b --- /dev/null +++ b/cmd/eks-a-tool/cmd/vsphererm.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var vsphereRmCmd = &cobra.Command{ + Use: "rm", + Short: "VSphere rm commands", + Long: "Use eks-a-tool vsphere rm to run vsphere rm utilities", +} + +func init() { + vsphereCmd.AddCommand(vsphereRmCmd) +} diff --git a/cmd/eks-a-tool/cmd/vspherermvms.go b/cmd/eks-a-tool/cmd/vspherermvms.go new file mode 100644 index 000000000000..e4317ebb846a --- /dev/null +++ b/cmd/eks-a-tool/cmd/vspherermvms.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/validations" +) + +var vsphereRmVmsCmd = &cobra.Command{ + Use: "vms ", + Short: "VSphere rmvms command", + Long: "This command removes vms associated with a cluster name", + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var clusterName string + + clusterName, err = validations.ValidateClusterNameArg(args) + if err != nil { + return err + } + + err = vsphereRmVms(cmd.Context(), clusterName, viper.GetBool("dry-run")) + if err != nil { + log.Fatalf("Error removing vms: %v", err) + } + return nil + }, +} + +func init() { + var err error + + vsphereRmCmd.AddCommand(vsphereRmVmsCmd) + vsphereRmVmsCmd.Flags().Bool("dry-run", false, "Dry run flag") + err = viper.BindPFlags(vsphereRmVmsCmd.Flags()) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } +} + +func vsphereRmVms(ctx context.Context, clusterName string, dryRun bool) error { + executableBuilder, err := executables.NewExecutableBuilder(ctx, executables.DefaultEksaImage()) + if err != nil { + return fmt.Errorf("unable to initialize executables: %v", err) + } + tmpWriter, _ := filewriter.NewWriter("rmvms") + return executableBuilder.BuildGovcExecutable(tmpWriter).CleanupVms(ctx, clusterName, dryRun) +} diff --git a/cmd/eks-a-tool/main.go b/cmd/eks-a-tool/main.go new file mode 100644 index 000000000000..871e3b0ed1ec --- /dev/null +++ b/cmd/eks-a-tool/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "os" + + "github.com/aws/eks-anywhere/cmd/eks-a-tool/cmd" +) + +func main() { + if cmd.Execute() == nil { + os.Exit(0) + } + os.Exit(-1) +} diff --git a/cmd/eks-a/cmd/constants.go b/cmd/eks-a/cmd/constants.go new file mode 100644 index 000000000000..9920dd70060a --- /dev/null +++ b/cmd/eks-a/cmd/constants.go @@ -0,0 +1,5 @@ +package cmd + +const ( + kubeconfigPattern = "%s-eks-a-cluster.kubeconfig" +) diff --git a/cmd/eks-a/cmd/create.go b/cmd/eks-a/cmd/create.go new file mode 100644 index 000000000000..963db92ea7cb --- /dev/null +++ b/cmd/eks-a/cmd/create.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create resources", + Long: "Use eks-a create to create resources, such as clusters", +} + +func init() { + rootCmd.AddCommand(createCmd) +} diff --git a/cmd/eks-a/cmd/createcluster.go b/cmd/eks-a/cmd/createcluster.go new file mode 100644 index 000000000000..482aa80bd807 --- /dev/null +++ b/cmd/eks-a/cmd/createcluster.go @@ -0,0 +1,170 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/addonmanager/addonclients" + "github.com/aws/eks-anywhere/pkg/bootstrapper" + fluxclient "github.com/aws/eks-anywhere/pkg/clients/flux" + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/clustermanager" + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/networking" + "github.com/aws/eks-anywhere/pkg/providers/factory" + "github.com/aws/eks-anywhere/pkg/validations" + "github.com/aws/eks-anywhere/pkg/version" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type createClusterOptions struct { + fileName string + forceClean bool + skipIpCheck bool +} + +var cc = &createClusterOptions{} + +var createClusterCmd = &cobra.Command{ + Use: "cluster", + Short: "Create workload cluster", + Long: "This command is used to create workload clusters", + PreRunE: preRunCreateCluster, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := cc.validate(cmd.Context()); err != nil { + return err + } + if err := cc.createCluster(cmd.Context()); err != nil { + return fmt.Errorf("failed to create cluster: %v", err) + } + return nil + }, +} + +func init() { + createCmd.AddCommand(createClusterCmd) + createClusterCmd.Flags().StringVarP(&cc.fileName, "filename", "f", "", "Filename that contains EKS-A cluster configuration") + createClusterCmd.Flags().BoolVar(&cc.forceClean, "force-cleanup", false, "Force deletion of previously created bootstrap cluster") + createClusterCmd.Flags().BoolVar(&cc.skipIpCheck, "skip-ip-check", false, "Skip check for whether cluster control plane ip is in use") + err := createClusterCmd.MarkFlagRequired("filename") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func preRunCreateCluster(cmd *cobra.Command, args []string) error { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) + return nil +} + +type clusterManagerClient struct { + *executables.Clusterctl + *executables.Kubectl +} + +type bootstrapperClient struct { + *executables.Kind + *executables.Kubectl +} + +func (cc *createClusterOptions) validate(ctx context.Context) error { + clusterConfig, err := commonValidation(ctx, cc.fileName) + if err != nil { + return err + } + if validations.KubeConfigExists(clusterConfig.Name, clusterConfig.Name, "", kubeconfigPattern) { + return fmt.Errorf("old cluster config file exists under %s, please use a different clusterName to proceed", clusterConfig.Name) + } + return nil +} + +func (cc *createClusterOptions) createCluster(ctx context.Context) error { + clusterSpec, err := cluster.NewSpec(cc.fileName, version.Get()) + if err != nil { + return fmt.Errorf("unable to get cluster config from file: %v", err) + } + if clusterSpec.HasOverrideClusterSpecFile() { + logger.Info("Warning: Override Cluster Spec file is configured. All other values in EKS-A spec will be ignored.") + } + + writer, err := filewriter.NewWriter(clusterSpec.Name) + if err != nil { + return fmt.Errorf("unable to write: %v", err) + } + eksaToolsImage := clusterSpec.VersionsBundle.Eksa.CliTools + image := eksaToolsImage.VersionedImage() + executableBuilder, err := executables.NewExecutableBuilder(ctx, image) + if err != nil { + return fmt.Errorf("unable to initialize executables: %v", err) + } + clusterawsadm := executableBuilder.BuildClusterAwsAdmExecutable() + kind := executableBuilder.BuildKindExecutable(writer) + clusterctl := executableBuilder.BuildClusterCtlExecutable(writer) + kubectl := executableBuilder.BuildKubectlExecutable() + govc := executableBuilder.BuildGovcExecutable(writer) + docker := executables.BuildDockerExecutable() + flux := executableBuilder.BuildFluxExecutable() + + providerFactory := &factory.ProviderFactory{ + AwsClient: clusterawsadm, + DockerClient: docker, + DockerKubectlClient: kubectl, + VSphereGovcClient: govc, + VSphereKubectlClient: kubectl, + Writer: writer, + SkipIpCheck: cc.skipIpCheck, + } + provider, err := providerFactory.BuildProvider(cc.fileName, clusterSpec.Cluster) + if err != nil { + return err + } + + bootstrapper := bootstrapper.New(&bootstrapperClient{kind, kubectl}) + + clusterManager := clustermanager.New( + &clusterManagerClient{ + clusterctl, + kubectl, + }, + networking.NewCilium(), + writer, + ) + + gitOpts, err := addonclients.NewGitOptions(ctx, clusterSpec.Cluster, clusterSpec.GitOpsConfig, writer) + if err != nil { + return err + } + addonClient := addonclients.NewFluxAddonClient( + &fluxclient.FluxKubectl{ + Flux: flux, + Kubectl: kubectl, + }, + gitOpts, + ) + + createCluster := workflows.NewCreate( + bootstrapper, + provider, + clusterManager, + addonClient, + writer, + ) + err = createCluster.Run(ctx, clusterSpec, cc.forceClean) + if err == nil { + writer.CleanUpTemp() + } + return err +} diff --git a/cmd/eks-a/cmd/delete.go b/cmd/eks-a/cmd/delete.go new file mode 100644 index 000000000000..ea0e1366238f --- /dev/null +++ b/cmd/eks-a/cmd/delete.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete", + Short: "Delete resources", + Long: "Use eks-a delete to delete clusters", +} + +func init() { + rootCmd.AddCommand(deleteCmd) +} diff --git a/cmd/eks-a/cmd/deletecluster.go b/cmd/eks-a/cmd/deletecluster.go new file mode 100644 index 000000000000..609f053e19c6 --- /dev/null +++ b/cmd/eks-a/cmd/deletecluster.go @@ -0,0 +1,171 @@ +package cmd + +import ( + "context" + "fmt" + "log" + "path/filepath" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/addonmanager/addonclients" + "github.com/aws/eks-anywhere/pkg/bootstrapper" + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/clustermanager" + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/networking" + "github.com/aws/eks-anywhere/pkg/providers/factory" + "github.com/aws/eks-anywhere/pkg/types" + "github.com/aws/eks-anywhere/pkg/validations" + "github.com/aws/eks-anywhere/pkg/version" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type deleteClusterOptions struct { + fileName string + wConfig string + forceCleanup bool +} + +func (dc *deleteClusterOptions) kubeConfig(clusterName string) string { + if dc.wConfig == "" { + return filepath.Join(clusterName, fmt.Sprintf(kubeconfigPattern, clusterName)) + } + return dc.wConfig +} + +var dc = &deleteClusterOptions{} + +var deleteClusterCmd = &cobra.Command{ + Use: "cluster (|-f )", + Short: "Workload cluster", + Long: "This command is used to delete workload clusters created by eks-a", + PreRunE: preRunDeleteCluster, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := dc.validate(cmd.Context(), args); err != nil { + return err + } + if err := dc.deleteCluster(cmd.Context()); err != nil { + return fmt.Errorf("failed to delete cluster: %v", err) + } + return nil + }, +} + +func preRunDeleteCluster(cmd *cobra.Command, args []string) error { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) + return nil +} + +func init() { + deleteCmd.AddCommand(deleteClusterCmd) + deleteClusterCmd.Flags().StringVarP(&dc.fileName, "filename", "f", "", "Filename that contains EKS-A cluster configuration, required if is not provided") + deleteClusterCmd.Flags().StringVarP(&dc.wConfig, "w-config", "w", "", "Kubeconfig file to use when deleting a workload cluster") + deleteClusterCmd.Flags().BoolVar(&dc.forceCleanup, "force-cleanup", false, "Force deletion of previously created bootstrap cluster") +} + +func (dc *deleteClusterOptions) validate(ctx context.Context, args []string) error { + if dc.fileName == "" { + clusterName, err := validations.ValidateClusterNameArg(args) + if err != nil { + return fmt.Errorf("please provide either a valid or -f ") + } + filename := fmt.Sprintf("%s/%s-eks-a-cluster.yaml", clusterName, clusterName) + if !validations.FileExists(filename) { + return fmt.Errorf("clusterconfig file %s for cluster: %s not found, please provide the clusterconfig path manually using -f ", filename, clusterName) + } + dc.fileName = filename + } + clusterConfig, err := commonValidation(ctx, dc.fileName) + if err != nil { + return err + } + if !validations.KubeConfigExists(clusterConfig.Name, clusterConfig.Name, dc.wConfig, kubeconfigPattern) { + return fmt.Errorf("KubeConfig doesn't exists for cluster %s", clusterConfig.Name) + } + return nil +} + +func (dc *deleteClusterOptions) deleteCluster(ctx context.Context) error { + clusterSpec, err := cluster.NewSpec(dc.fileName, version.Get()) + if err != nil { + return fmt.Errorf("unable to get cluster config from file: %v", err) + } + + writer, err := filewriter.NewWriter(clusterSpec.Name) + if err != nil { + return fmt.Errorf("unable to write: %v", err) + } + + eksaToolsImage := clusterSpec.VersionsBundle.Eksa.CliTools + image := eksaToolsImage.VersionedImage() + executableBuilder, err := executables.NewExecutableBuilder(ctx, image) + if err != nil { + return fmt.Errorf("unable initialize executables: %v", err) + } + + clusterawsadm := executableBuilder.BuildClusterAwsAdmExecutable() + kind := executableBuilder.BuildKindExecutable(writer) + clusterctl := executableBuilder.BuildClusterCtlExecutable(writer) + kubectl := executableBuilder.BuildKubectlExecutable() + govc := executableBuilder.BuildGovcExecutable(writer) + docker := executables.BuildDockerExecutable() + + providerFactory := &factory.ProviderFactory{ + AwsClient: clusterawsadm, + DockerClient: docker, + DockerKubectlClient: kubectl, + VSphereGovcClient: govc, + VSphereKubectlClient: kubectl, + Writer: writer, + } + provider, err := providerFactory.BuildProvider(dc.fileName, clusterSpec.Cluster) + if err != nil { + return err + } + + bootstrapper := bootstrapper.New(&bootstrapperClient{kind, kubectl}) + + clusterManager := clustermanager.New( + &clusterManagerClient{ + clusterctl, + kubectl, + }, + networking.NewCilium(), + writer, + ) + + gitOpts, err := addonclients.NewGitOptions(ctx, clusterSpec.Cluster, clusterSpec.GitOpsConfig, writer) + if err != nil { + return fmt.Errorf("failed to set up git options: %v", err) + } + + addonClient := addonclients.NewFluxAddonClient(nil, gitOpts) + + deleteCluster := workflows.NewDelete( + bootstrapper, + provider, + clusterManager, + addonClient, + ) + + // Initialize Workload cluster type + workloadCluster := &types.Cluster{ + Name: clusterSpec.Name, + KubeconfigFile: dc.kubeConfig(clusterSpec.Name), + } + err = deleteCluster.Run(ctx, workloadCluster, clusterSpec, viper.GetBool("force-cleanup")) + if err == nil { + writer.CleanUp() + } + return err +} diff --git a/cmd/eks-a/cmd/generate.go b/cmd/eks-a/cmd/generate.go new file mode 100644 index 000000000000..40006de34221 --- /dev/null +++ b/cmd/eks-a/cmd/generate.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var generateCmd = &cobra.Command{ + Use: "generate", + Short: "Generate resources", + Long: "Use eks-a generate to generate resources, such as clusterconfig yaml", +} + +func init() { + rootCmd.AddCommand(generateCmd) +} diff --git a/cmd/eks-a/cmd/generatebundleconfig.go b/cmd/eks-a/cmd/generatebundleconfig.go new file mode 100644 index 000000000000..1b5de7e3011f --- /dev/null +++ b/cmd/eks-a/cmd/generatebundleconfig.go @@ -0,0 +1,26 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + support "github.com/aws/eks-anywhere/pkg/support" +) + +var generateBundleConfigCmd = &cobra.Command{ + Use: "support-bundle-config", + Short: "Generate support bundle config", + Long: "This command is used to generate a default support bundle config yaml", + RunE: func(cmd *cobra.Command, args []string) error { + err := support.GenerateBundleConfig() + if err != nil { + return fmt.Errorf("failed to generate bunlde config: %v", err) + } + return nil + }, +} + +func init() { + generateCmd.AddCommand(generateBundleConfigCmd) +} diff --git a/cmd/eks-a/cmd/generateclusterconfig.go b/cmd/eks-a/cmd/generateclusterconfig.go new file mode 100644 index 000000000000..563ea54fe228 --- /dev/null +++ b/cmd/eks-a/cmd/generateclusterconfig.go @@ -0,0 +1,110 @@ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "sigs.k8s.io/yaml" + + "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/providers/docker" + "github.com/aws/eks-anywhere/pkg/providers/vsphere" + "github.com/aws/eks-anywhere/pkg/templater" + "github.com/aws/eks-anywhere/pkg/validations" +) + +var generateClusterConfigCmd = &cobra.Command{ + Use: "clusterconfig (max 80 chars)", + Short: "Generate cluster config", + Long: "This command is used to generate a cluster config yaml for the create cluster command", + PreRun: preRunGenerateClusterConfig, + RunE: func(cmd *cobra.Command, args []string) error { + clusterName, err := validations.ValidateClusterNameArg(args) + if err != nil { + return err + } + err = generateClusterConfig(clusterName) + if err != nil { + return fmt.Errorf("failed to generate eks-a cluster config: %v", err) // need to have better error handling here in own func + } + return nil + }, +} + +func preRunGenerateClusterConfig(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +func init() { + generateCmd.AddCommand(generateClusterConfigCmd) + generateClusterConfigCmd.Flags().StringP("provider", "p", "", "Provider to use") + err := generateClusterConfigCmd.MarkFlagRequired("provider") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func generateClusterConfig(clusterName string) error { + var resources [][]byte + var datacenterYaml []byte + var machineGroupYaml [][]byte + var clusterConfigOpts []v1alpha1.ClusterGenerateOpt + switch strings.ToLower(viper.GetString("provider")) { + case docker.ProviderName: + datacenterConfig := v1alpha1.NewDockerDatacenterConfigGenerate(clusterName) + clusterConfigOpts = append(clusterConfigOpts, v1alpha1.WithDatacenterRef(datacenterConfig)) + dcyaml, err := yaml.Marshal(datacenterConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + datacenterYaml = dcyaml + case vsphere.ProviderName: + clusterConfigOpts = append(clusterConfigOpts, v1alpha1.WithClusterEndpoint()) + datacenterConfig := v1alpha1.NewVSphereDatacenterConfigGenerate(clusterName) + clusterConfigOpts = append(clusterConfigOpts, v1alpha1.WithDatacenterRef(datacenterConfig)) + dcyaml, err := yaml.Marshal(datacenterConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + datacenterYaml = dcyaml + // need to default control plane config name to something different from the cluster name based on assumption + // in controller code + cpMachineConfig := v1alpha1.NewVSphereMachineConfigGenerate(clusterName + "-cp") + workerMachineConfig := v1alpha1.NewVSphereMachineConfigGenerate(clusterName) + clusterConfigOpts = append(clusterConfigOpts, + v1alpha1.WithCPMachineGroupRef(cpMachineConfig), + v1alpha1.WithWorkerMachineGroupRef(workerMachineConfig)) + cpMcYaml, err := yaml.Marshal(cpMachineConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + workerMcYaml, err := yaml.Marshal(workerMachineConfig) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + machineGroupYaml = append(machineGroupYaml, cpMcYaml, workerMcYaml) + default: + return fmt.Errorf("not a valid provider") + } + config := v1alpha1.NewClusterGenerate(clusterName, clusterConfigOpts...) + + clusterYaml, err := yaml.Marshal(config) + if err != nil { + return fmt.Errorf("error outputting yaml: %v", err) + } + resources = append(resources, clusterYaml, datacenterYaml) + if len(machineGroupYaml) > 0 { + resources = append(resources, machineGroupYaml...) + } + fmt.Println(string(templater.AppendYamlResources(resources...))) + return nil +} diff --git a/cmd/eks-a/cmd/root.go b/cmd/eks-a/cmd/root.go new file mode 100644 index 000000000000..0a4bf5ff9775 --- /dev/null +++ b/cmd/eks-a/cmd/root.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/logger" +) + +var rootCmd = &cobra.Command{ + Use: "eks-a", + Short: "Amazon EKS Anywhere", + Long: `Use eks-a to build your own self-managing cluster on your hardware with the best of Amazon EKS`, + PersistentPreRun: rootPersistentPreRun, +} + +func init() { + rootCmd.PersistentFlags().IntP("verbosity", "v", 0, "Set the log level verbosity") + if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { + log.Fatalf("failed to bind flags for root: %v", err) + } +} + +func rootPersistentPreRun(cmd *cobra.Command, args []string) { + if err := initLogger(); err != nil { + log.Fatal(err) + } +} + +func initLogger() error { + if err := logger.InitZap(viper.GetInt("verbosity")); err != nil { + return fmt.Errorf("failed init zap logger in root command: %v", err) + } + + return nil +} + +func Execute() error { + return rootCmd.ExecuteContext(context.Background()) +} diff --git a/cmd/eks-a/cmd/supportbundle.go b/cmd/eks-a/cmd/supportbundle.go new file mode 100644 index 000000000000..9d3c0494f099 --- /dev/null +++ b/cmd/eks-a/cmd/supportbundle.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/logger" + support "github.com/aws/eks-anywhere/pkg/support" + "github.com/aws/eks-anywhere/pkg/validations" + "github.com/aws/eks-anywhere/pkg/version" +) + +type createSupportBundleOptions struct { + fileName string + wConfig string + since string + sinceTime string + bundleConfig string +} + +func (csbo *createSupportBundleOptions) kubeConfig(clusterName string) string { + if csbo.wConfig == "" { + return filepath.Join(clusterName, fmt.Sprintf(kubeconfigPattern, clusterName)) + } + return csbo.wConfig +} + +var csbo = &createSupportBundleOptions{} + +var supportbundleCmd = &cobra.Command{ + Use: "support-bundle -f my-cluster.yaml", + Short: "Generate a support bundle", + Long: "This command is used to create a support bundle to troubleshoot a cluster", + PreRunE: preRunSupportBundle, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := csbo.validate(cmd.Context()); err != nil { + return err + } + if err := csbo.createBundle(csbo.since, csbo.sinceTime, csbo.bundleConfig); err != nil { + return fmt.Errorf("failed to create support bundle: %v", err) + } + return nil + }, +} + +func init() { + generateCmd.AddCommand(supportbundleCmd) + supportbundleCmd.Flags().StringVarP(&csbo.sinceTime, "since-time", "", "", "Collect pod logs after a specific datetime(RFC3339) like 2021-06-28T15:04:05Z") + supportbundleCmd.Flags().StringVarP(&csbo.since, "since", "", "", "Collect pod logs in the latest duration like 5s, 2m, or 3h.") + supportbundleCmd.Flags().StringVarP(&csbo.bundleConfig, "bundle-config", "", "", "Bundle Config file to use when generating support bundle") + supportbundleCmd.Flags().StringVarP(&csbo.fileName, "filename", "f", "", "Filename that contains EKS-A cluster configuration") + supportbundleCmd.Flags().StringVarP(&csbo.wConfig, "w-config", "w", "", "Kubeconfig file to use when creating support bundle for a workload cluster") + err := supportbundleCmd.MarkFlagRequired("filename") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func (csbo *createSupportBundleOptions) validate(ctx context.Context) error { + clusterConfig, err := commonValidation(ctx, csbo.fileName) + if err != nil { + return err + } + if !validations.KubeConfigExists(clusterConfig.Name, clusterConfig.Name, csbo.wConfig, kubeconfigPattern) { + return fmt.Errorf("KubeConfig doesn't exists for cluster %s", clusterConfig.Name) + } + return nil +} + +func preRunSupportBundle(cmd *cobra.Command, args []string) error { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) + return nil +} + +func (csbo *createSupportBundleOptions) createBundle(since, sinceTime, bundleConfig string) error { + clusterSpec, err := cluster.NewSpec(csbo.fileName, version.Get()) + if err != nil { + return fmt.Errorf("unable to get cluster config from file: %v", err) + } + os.Setenv("KUBECONFIG", csbo.kubeConfig(clusterSpec.Name)) + supportBundle, err := support.ParseBundleFromDoc(bundleConfig) + if err != nil { + return fmt.Errorf("failed to parse collector: %v", err) + } + + var sinceTimeValue *time.Time + sinceTimeValue, err = support.ParseTimeOptions(since, sinceTime) + if err != nil { + return fmt.Errorf("failed parse since time: %v", err) + } + + archivePath, err := support.CollectBundleFromSpec(sinceTimeValue, &supportBundle.Spec) + if err != nil { + return fmt.Errorf("run collectors: %v", err) + } + + logger.Info("\r \033[36mAnalyzing support bundle\033[m") + err = support.AnalyzeBundle(&supportBundle.Spec, archivePath) + if err != nil { + return fmt.Errorf("there is an error when analyzing: %v", err) + } + + logger.Info("a support bundle has been created in the current directory:", "path", archivePath) + return nil +} diff --git a/cmd/eks-a/cmd/upgrade.go b/cmd/eks-a/cmd/upgrade.go new file mode 100644 index 000000000000..81e494c655a0 --- /dev/null +++ b/cmd/eks-a/cmd/upgrade.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var upgradeCmd = &cobra.Command{ + Use: "upgrade", + Short: "Upgrade resources", + Long: "Use eks-a upgrade to upgrade resources, such as clusters", +} + +func init() { + rootCmd.AddCommand(upgradeCmd) +} diff --git a/cmd/eks-a/cmd/upgradecluster.go b/cmd/eks-a/cmd/upgradecluster.go new file mode 100644 index 000000000000..f97cd5a36266 --- /dev/null +++ b/cmd/eks-a/cmd/upgradecluster.go @@ -0,0 +1,187 @@ +package cmd + +import ( + "context" + "fmt" + "log" + "path/filepath" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/addonmanager/addonclients" + "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/bootstrapper" + fluxclient "github.com/aws/eks-anywhere/pkg/clients/flux" + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/clustermanager" + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/networking" + "github.com/aws/eks-anywhere/pkg/providers/factory" + "github.com/aws/eks-anywhere/pkg/types" + "github.com/aws/eks-anywhere/pkg/validations" + "github.com/aws/eks-anywhere/pkg/validations/upgradevalidations" + "github.com/aws/eks-anywhere/pkg/version" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type upgradeClusterOptions struct { + fileName string + wConfig string + forceClean bool +} + +func (uc *upgradeClusterOptions) kubeConfig(clusterName string) string { + if uc.wConfig == "" { + return filepath.Join(clusterName, fmt.Sprintf(kubeconfigPattern, clusterName)) + } + return uc.wConfig +} + +var uc = &upgradeClusterOptions{} + +var upgradeClusterCmd = &cobra.Command{ + Use: "cluster", + Short: "Upgrade workload cluster", + Long: "This command is used to upgrade workload clusters", + PreRunE: preRunUpgradeCluster, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := uc.upgradeCluster(cmd.Context()); err != nil { + return fmt.Errorf("failed to upgrade cluster: %v", err) + } + return nil + }, +} + +func preRunUpgradeCluster(cmd *cobra.Command, args []string) error { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) + return nil +} + +func init() { + upgradeCmd.AddCommand(upgradeClusterCmd) + upgradeClusterCmd.Flags().StringVarP(&uc.fileName, "filename", "f", "", "Filename that contains EKS-A cluster configuration") + upgradeClusterCmd.Flags().StringVarP(&uc.wConfig, "w-config", "w", "", "Kubeconfig file to use when upgrading a workload cluster") + upgradeClusterCmd.Flags().BoolVar(&uc.forceClean, "force-cleanup", false, "Force deletion of previously created bootstrap cluster") + err := upgradeClusterCmd.MarkFlagRequired("filename") + if err != nil { + log.Fatalf("Error marking flag as required: %v", err) + } +} + +func (uc *upgradeClusterOptions) upgradeCluster(ctx context.Context) error { + if _, err := uc.commonValidations(ctx); err != nil { + return fmt.Errorf("common validations failed due to: %v", err) + } + clusterSpec, err := cluster.NewSpec(uc.fileName, version.Get()) + if err != nil { + return fmt.Errorf("unable to get cluster config from file: %v", err) + } + if clusterSpec.HasOverrideClusterSpecFile() { + logger.Info("Warning: Override Cluster Spec file is configured. All other values in EKS-A spec will be ignored.") + } + + writer, err := filewriter.NewWriter(clusterSpec.Name) + if err != nil { + return fmt.Errorf("unable to write: %v", err) + } + + eksaToolsImage := clusterSpec.VersionsBundle.Eksa.CliTools + image := eksaToolsImage.VersionedImage() + executableBuilder, err := executables.NewExecutableBuilder(ctx, image) + if err != nil { + return fmt.Errorf("unable to initialize executables: %v", err) + } + + clusterawsadm := executableBuilder.BuildClusterAwsAdmExecutable() + kind := executableBuilder.BuildKindExecutable(writer) + clusterctl := executableBuilder.BuildClusterCtlExecutable(writer) + kubectl := executableBuilder.BuildKubectlExecutable() + govc := executableBuilder.BuildGovcExecutable(writer) + docker := executables.BuildDockerExecutable() + flux := executableBuilder.BuildFluxExecutable() + + providerFactory := &factory.ProviderFactory{ + AwsClient: clusterawsadm, + DockerClient: docker, + DockerKubectlClient: kubectl, + VSphereGovcClient: govc, + VSphereKubectlClient: kubectl, + Writer: writer, + } + provider, err := providerFactory.BuildProvider(uc.fileName, clusterSpec.Cluster) + if err != nil { + return err + } + + bootstrapper := bootstrapper.New(&bootstrapperClient{kind, kubectl}) + + clusterManager := clustermanager.New( + &clusterManagerClient{ + clusterctl, + kubectl, + }, + networking.NewCilium(), + writer, + ) + + gitOpts, err := addonclients.NewGitOptions(ctx, clusterSpec.Cluster, clusterSpec.GitOpsConfig, writer) + if err != nil { + return fmt.Errorf("failed to set up git options: %v", err) + } + + addonClient := addonclients.NewFluxAddonClient( + &fluxclient.FluxKubectl{ + Flux: flux, + Kubectl: kubectl, + }, + gitOpts, + ) + + upgradeCluster := workflows.NewUpgrade( + bootstrapper, + provider, + clusterManager, + addonClient, + writer, + ) + + workloadCluster := &types.Cluster{ + Name: clusterSpec.Name, + KubeconfigFile: uc.kubeConfig(clusterSpec.Name), + } + + validationOpts := &upgradevalidations.UpgradeValidationOpts{ + Kubectl: kubectl, + Spec: clusterSpec, + WorkloadCluster: workloadCluster, + Provider: provider, + } + upgradeValidations := upgradevalidations.New(validationOpts) + + err = upgradeCluster.Run(ctx, clusterSpec, workloadCluster, upgradeValidations, uc.forceClean) + if err == nil { + writer.CleanUpTemp() + } + return err +} + +func (uc *upgradeClusterOptions) commonValidations(ctx context.Context) (cluster *v1alpha1.Cluster, err error) { + clusterConfig, err := commonValidation(ctx, uc.fileName) + if err != nil { + return nil, err + } + if !validations.KubeConfigExists(clusterConfig.Name, clusterConfig.Name, uc.wConfig, kubeconfigPattern) { + return nil, fmt.Errorf("KubeConfig doesn't exists for cluster %s", clusterConfig.Name) + } + return clusterConfig, nil +} diff --git a/cmd/eks-a/cmd/validations.go b/cmd/eks-a/cmd/validations.go new file mode 100644 index 000000000000..a38094cbdc43 --- /dev/null +++ b/cmd/eks-a/cmd/validations.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "context" + "fmt" + + "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/executables" + "github.com/aws/eks-anywhere/pkg/validations" +) + +func commonValidation(ctx context.Context, clusterConfigFile string) (*v1alpha1.Cluster, error) { + docker := executables.BuildDockerExecutable() + err := validations.CheckMinimumDockerVersion(ctx, docker) + if err != nil { + return nil, fmt.Errorf("failed to validate docker: %v", err) + } + validations.CheckDockerAllocatedMemory(ctx, docker) + clusterConfigFileExist := validations.FileExists(clusterConfigFile) + if !clusterConfigFileExist { + return nil, fmt.Errorf("the cluster config file %s does not exist", clusterConfigFile) + } + clusterConfig, err := v1alpha1.ValidateClusterConfig(clusterConfigFile) + if err != nil { + return nil, fmt.Errorf("unable to get cluster config from file: %v", err) + } + return clusterConfig, nil +} diff --git a/cmd/eks-a/cmd/version.go b/cmd/eks-a/cmd/version.go new file mode 100644 index 000000000000..8d87874c0892 --- /dev/null +++ b/cmd/eks-a/cmd/version.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/aws/eks-anywhere/pkg/version" +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Get the eks-a version", + Long: "This command prints the version of eks-a", + RunE: func(cmd *cobra.Command, args []string) error { + return printVersion() + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} + +func printVersion() error { + fmt.Println(version.Get().GitVersion) + return nil +} diff --git a/cmd/eks-a/main.go b/cmd/eks-a/main.go new file mode 100644 index 000000000000..49df39c87821 --- /dev/null +++ b/cmd/eks-a/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "os" + + "github.com/aws/eks-anywhere/cmd/eks-a/cmd" + "github.com/aws/eks-anywhere/pkg/eksctl" +) + +func main() { + if eksctl.Enabled() { + err := eksctl.ValidateVersion() + if err != nil { + fmt.Println(err) + os.Exit(-1) + } + } + if cmd.Execute() == nil { + os.Exit(0) + } + os.Exit(-1) +} diff --git a/cmd/integration_test/build/buildspecs/build-eks-a-cli.yml b/cmd/integration_test/build/buildspecs/build-eks-a-cli.yml new file mode 100644 index 000000000000..0bd7a4868267 --- /dev/null +++ b/cmd/integration_test/build/buildspecs/build-eks-a-cli.yml @@ -0,0 +1,13 @@ +version: 0.2 + +phases: + build: + commands: + - make e2e + - echo "$CODEBUILD_RESOLVED_SOURCE_VERSION" >> bin/githash + +artifacts: + files: + - "bin/**/*" + - "cmd/integration_test/build/**/*" + - "ATTRIBUTION.txt" \ No newline at end of file diff --git a/cmd/integration_test/build/buildspecs/conformance-eks-a-cli.yml b/cmd/integration_test/build/buildspecs/conformance-eks-a-cli.yml new file mode 100644 index 000000000000..e776190f0b49 --- /dev/null +++ b/cmd/integration_test/build/buildspecs/conformance-eks-a-cli.yml @@ -0,0 +1,53 @@ +version: 0.2 + +env: + variables: + T_VSPHERE_CIDR: "198.18.0.0/16" + secrets-manager: + VSPHERE_USERNAME: "vsphere_ci_beta_connection:vsphere_username" + VSPHERE_PASSWORD: "vsphere_ci_beta_connection:vsphere_password" + GOVC_URL: "vsphere_ci_beta_connection:vsphere_url" + GOVC_USERNAME: "vsphere_ci_beta_connection:vsphere_username" + GOVC_PASSWORD: "vsphere_ci_beta_connection:vsphere_password" + GOVC_INSECURE: "vsphere_ci_beta_connection:govc_insecure" + T_VSPHERE_DATACENTER: "vsphere_ci_beta_connection:vsphere_datacenter" + T_VSPHERE_DATASTORE: "vsphere_ci_beta_connection:datastore" + T_VSPHERE_FOLDER: "vsphere_ci_beta_connection:folder" + T_VSPHERE_NETWORK: "vsphere_ci_beta_connection:network" + T_VSPHERE_RESOURCE_POOL: "vsphere_ci_beta_connection:resource_pool" + T_VSPHERE_SERVER: "vsphere_ci_beta_connection:server" + T_VSPHERE_SSH_AUTHORIZED_KEY: "vsphere_ci_beta_connection:ssh_authorized_key" + T_VSPHERE_TEMPLATE_UBUNTU_1_18: "vsphere_ci_beta_connection:template_18" + T_VSPHERE_TEMPLATE_UBUNTU_1_19: "vsphere_ci_beta_connection:template_19" + T_VSPHERE_TEMPLATE_UBUNTU_1_20: "vsphere_ci_beta_connection:template_20" + T_VSPHERE_TEMPLATE_UBUNTU_1_21: "vsphere_ci_beta_connection:template_21" + T_VSPHERE_TEMPLATE_BR_1_20: "vsphere_ci_beta_connection:template_br_20" + T_VSPHERE_TEMPLATE_BR_1_21: "vsphere_ci_beta_connection:template_br_21" + T_VSPHERE_TLS_INSECURE: "vsphere_ci_beta_connection:tls_insecure" + T_VSPHERE_TLS_THUMBPRINT: "vsphere_ci_beta_connection:tls_thumbprint" + +phases: + pre_build: + commands: + - source ${CODEBUILD_SRC_DIR}/cmd/integration_test/build/script/set_profile.sh + - make e2e + - /docker.sh + - cp ./bin/linux/eks-a ./bin/eks-a + build: + commands: + - export JOB_ID=$CODEBUILD_BUILD_ID + - > + ./bin/test e2e run + -a ${INTEGRATION_TEST_AL2_AMI_ID} + -s ${INTEGRATION_TEST_STORAGE_BUCKET} + -j ${JOB_ID} + -i ${INTEGRATION_TEST_INSTANCE_PROFILE} + -n ${INTEGRATION_TEST_SUBNET_ID} + -m 25 + -r 'Test(VSphere|Docker)Kubernetes.*ConformanceFlow' + post_build: + commands: + - > + ./bin/test e2e cleanup vsphere + -n eksa-test + -v 4 diff --git a/cmd/integration_test/build/buildspecs/test-eks-a-cli.yml b/cmd/integration_test/build/buildspecs/test-eks-a-cli.yml new file mode 100644 index 000000000000..0e312361c431 --- /dev/null +++ b/cmd/integration_test/build/buildspecs/test-eks-a-cli.yml @@ -0,0 +1,60 @@ +version: 0.2 + +env: + variables: + T_VSPHERE_CIDR: "198.18.0.0/16" + secrets-manager: + VSPHERE_USERNAME: "vsphere_ci_beta_connection:vsphere_username" + VSPHERE_PASSWORD: "vsphere_ci_beta_connection:vsphere_password" + GOVC_URL: "vsphere_ci_beta_connection:vsphere_url" + GOVC_USERNAME: "vsphere_ci_beta_connection:vsphere_username" + GOVC_PASSWORD: "vsphere_ci_beta_connection:vsphere_password" + GOVC_INSECURE: "vsphere_ci_beta_connection:govc_insecure" + T_VSPHERE_DATACENTER: "vsphere_ci_beta_connection:vsphere_datacenter" + T_VSPHERE_DATASTORE: "vsphere_ci_beta_connection:datastore" + T_VSPHERE_FOLDER: "vsphere_ci_beta_connection:folder" + T_VSPHERE_NETWORK: "vsphere_ci_beta_connection:network" + T_VSPHERE_RESOURCE_POOL: "vsphere_ci_beta_connection:resource_pool" + T_VSPHERE_SERVER: "vsphere_ci_beta_connection:server" + T_VSPHERE_SSH_AUTHORIZED_KEY: "vsphere_ci_beta_connection:ssh_authorized_key" + T_VSPHERE_TEMPLATE_UBUNTU_1_18: "vsphere_ci_beta_connection:template_18" + T_VSPHERE_TEMPLATE_UBUNTU_1_19: "vsphere_ci_beta_connection:template_19" + T_VSPHERE_TEMPLATE_UBUNTU_1_20: "vsphere_ci_beta_connection:template_20" + T_VSPHERE_TEMPLATE_UBUNTU_1_21: "vsphere_ci_beta_connection:template_21" + T_VSPHERE_TEMPLATE_BR_1_20: "vsphere_ci_beta_connection:template_br_20" + T_VSPHERE_TEMPLATE_BR_1_21: "vsphere_ci_beta_connection:template_br_21" + T_VSPHERE_TLS_INSECURE: "vsphere_ci_beta_connection:tls_insecure" + T_VSPHERE_TLS_THUMBPRINT: "vsphere_ci_beta_connection:tls_thumbprint" + +phases: + pre_build: + commands: + - source ${CODEBUILD_SRC_DIR}/cmd/integration_test/build/script/set_profile.sh + - /docker.sh + - cp ./bin/linux/eks-a ./bin/eks-a + build: + commands: + - export JOB_ID=$CODEBUILD_BUILD_ID + - > + ./bin/test e2e run + -a ${INTEGRATION_TEST_AL2_AMI_ID} + -s ${INTEGRATION_TEST_STORAGE_BUCKET} + -j ${JOB_ID} + -i ${INTEGRATION_TEST_INSTANCE_PROFILE} + -n ${INTEGRATION_TEST_SUBNET_ID} + -m 35 + -r 'Test(VSphere|Docker)Kubernetes.*(SimpleFlow|OIDC|ExternalEtcd|Upgrade|Autoimport)' + - unset AWS_SDK_LOAD_CONFIG AWS_PROFILE + - export GIT_HASH=$(cat bin/githash) + - > + ./cmd/integration_test/build/script/upload_artifacts.sh + $ARTIFACTS_BUCKET + "eks-a-cli" + $CODEBUILD_BUILD_NUMBER + $GIT_HASH +# post_build: +# commands: +# - > +# ./bin/test e2e cleanup vsphere +# -n eksa-test +# -v 4 diff --git a/cmd/integration_test/build/script/set_profile.sh b/cmd/integration_test/build/script/set_profile.sh new file mode 100755 index 000000000000..ac820dcc444e --- /dev/null +++ b/cmd/integration_test/build/script/set_profile.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Copyright 2020 Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# 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. + +set -e +set -x +set -o pipefail + +if [ "$TEST_ROLE_ARN" == "" ]; then + echo "Empty TEST_ROLE_ARN, this script is used in CodeBuild to set profile to assume an IAM role" + exit 1 +fi + +export AWS_SDK_LOAD_CONFIG=1 +export AWS_CONFIG_FILE=$(pwd)/awscliconfig +export AWS_PROFILE=e2e-test-account + +cat << EOF > ${AWS_CONFIG_FILE} +[profile ${AWS_PROFILE}] +role_arn=${TEST_ROLE_ARN} +region=us-west-2 +credential_source=EcsContainer +EOF diff --git a/cmd/integration_test/build/script/upload_artifacts.sh b/cmd/integration_test/build/script/upload_artifacts.sh new file mode 100755 index 000000000000..bbe22e050543 --- /dev/null +++ b/cmd/integration_test/build/script/upload_artifacts.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +set -x +set -o errexit +set -o nounset +set -o pipefail + +ARTIFACTS_BUCKET="${1?Specify first argument - artifacts buckets}" +PROJECT_PATH="${2? Specify second argument - project path}" +BUILD_IDENTIFIER="${3? Specify third argument - build identifier}" +GIT_HASH="${4?Specify fourth argument - git hash of the tar builds}" + +REPO="eks-a" +BINARY_PATH="bin" +TAR_PATH="${CODEBUILD_SRC_DIR}/${PROJECT_PATH}/${BUILD_IDENTIFIER}-${GIT_HASH}/artifacts" + +function build::cli::move_artifacts() { + local -r os=$1 + local -r cli_artifacts_path=$2 + + mv ${BINARY_PATH}/${os}/eks-a ${cli_artifacts_path} + mv ATTRIBUTION.txt ${cli_artifacts_path} +} + +function build::cli::create_tarball() { + local -r os=$1 + local -r arch=$2 + local -r tar_file=$3 + local -r tar_path=$4 + local -r cli_artifacts_path=$5 + + build::ensure_tar + + "${TAR}" czf "${tar_path}/${os}/${tar_file}" -C ${cli_artifacts_path} . --owner=0 --group=0 +} + +function build::cli::generate_shasum() { + local -r tar_path=$1 + local -r os=$2 + + echo "Writing artifact hashes to shasum files..." + + if [ ! -d "$tar_path" ]; then + echo " Unable to find tar directory $tar_path" + exit 1 + fi + + cd $tar_path/$os + for file in $(find . -name '*.tar.gz'); do + filepath=$(basename $file) + sha256sum "$filepath" > "$file.sha256" + sha512sum "$filepath" > "$file.sha512" + done + cd - +} + +function build::ensure_tar() { + if [[ -n "${TAR:-}" ]]; then + return + fi + + # Find gnu tar if it is available, bomb out if not. + TAR=tar + if which gtar &>/dev/null; then + TAR=gtar + elif which gnutar &>/dev/null; then + TAR=gnutar + fi + if ! "${TAR}" --version | grep -q GNU; then + echo " !!! Cannot find GNU tar. Build on Linux or install GNU tar" + echo " on Mac OS X (brew install gnu-tar)." + return 1 + fi +} + +function build::cli::upload() { + local -r artifactspath=$1 + local -r artifactsbucket=$2 + local -r projectpath=$3 + local -r buildidentifier=$4 + local -r githash=$5 + + echo "$githash" >> "$artifactspath"/githash + + # Upload artifacts to s3 + # 1. To proper path on s3 with buildId-githash + # 2. Latest path to indicate the latest build, with --delete option to delete stale files in the dest path + aws s3 sync "$artifactspath" "$artifactsbucket"/"$projectpath"/"$buildidentifier"-"$githash"/artifacts --acl public-read + aws s3 sync "$artifactspath" "$artifactsbucket"/"$projectpath"/latest --delete --acl public-read +} + +SUPPORTED_PLATFORMS=( + "linux/amd64" + "darwin/amd64" +) + +for platform in "${SUPPORTED_PLATFORMS[@]}"; do + OS="$(cut -d '/' -f1 <<< ${platform})" + ARCH="$(cut -d '/' -f2 <<< ${platform})" + TAR_FILE="${REPO}-${OS}-${ARCH}.tar.gz" + CLI_ARTIFACTS_PATH="cli-artifacts/${OS}" + mkdir -p $TAR_PATH/$OS + mkdir -p $CLI_ARTIFACTS_PATH + + build::cli::move_artifacts $OS $CLI_ARTIFACTS_PATH + build::cli::create_tarball $OS $ARCH $TAR_FILE $TAR_PATH $CLI_ARTIFACTS_PATH + build::cli::generate_shasum $TAR_PATH $OS +done +build::cli::upload ${TAR_PATH} ${ARTIFACTS_BUCKET} ${PROJECT_PATH} ${BUILD_IDENTIFIER} ${GIT_HASH} diff --git a/cmd/integration_test/cmd/cleanup.go b/cmd/integration_test/cmd/cleanup.go new file mode 100644 index 000000000000..777a9e7bfee1 --- /dev/null +++ b/cmd/integration_test/cmd/cleanup.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var cleanUpInstancesCmd = &cobra.Command{ + Use: "cleanup", + Short: "Clean up e2e resources", + Long: "Clean up resources created for e2e testing", +} + +func init() { + integrationTestCmd.AddCommand(cleanUpInstancesCmd) +} diff --git a/cmd/integration_test/cmd/cleanupaws.go b/cmd/integration_test/cmd/cleanupaws.go new file mode 100644 index 000000000000..547c6716acb6 --- /dev/null +++ b/cmd/integration_test/cmd/cleanupaws.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/internal/test/e2e" + "github.com/aws/eks-anywhere/pkg/logger" +) + +const ( + maxAgeFlagName = "max-age" + tagFlagName = "tag" +) + +var cleanUpAwsCmd = &cobra.Command{ + Use: "aws", + Short: "Clean up e2e resources on aws", + Long: "Clean up resources created for e2e testing on aws", + SilenceUsage: true, + PreRun: preRunCleanUpAwsSetup, + RunE: func(cmd *cobra.Command, args []string) error { + err := cleanUpAwsTestResources(cmd.Context()) + if err != nil { + logger.Fatal(err, "Failed to cleanup e2e resources on aws") + } + return nil + }, +} + +func preRunCleanUpAwsSetup(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +var requiredAwsCleanUpFlags = []string{storageBucketFlagName, maxAgeFlagName, tagFlagName} + +func init() { + cleanUpInstancesCmd.AddCommand(cleanUpAwsCmd) + cleanUpAwsCmd.Flags().StringP(storageBucketFlagName, "s", "", "Name of s3 bucket used for e2e testing") + cleanUpAwsCmd.Flags().StringP(maxAgeFlagName, "a", "0", "Instance age in seconds after which it should be deleted") + cleanUpAwsCmd.Flags().StringP(tagFlagName, "t", "", "EC2 instance tag") + + for _, flag := range requiredAwsCleanUpFlags { + if err := cleanUpAwsCmd.MarkFlagRequired(flag); err != nil { + log.Fatalf("Error marking flag %s as required: %v", flag, err) + } + } +} + +func cleanUpAwsTestResources(ctx context.Context) error { + maxAge := viper.GetString(maxAgeFlagName) + storageBucket := viper.GetString(storageBucketFlagName) + tag := viper.GetString(tagFlagName) + + err := e2e.CleanUpAwsTestResources(storageBucket, maxAge, tag) + if err != nil { + return fmt.Errorf("error running cleanup for aws test resources: %v", err) + } + + return nil +} diff --git a/cmd/integration_test/cmd/cleanupvsphere.go b/cmd/integration_test/cmd/cleanupvsphere.go new file mode 100644 index 000000000000..05b37382efe5 --- /dev/null +++ b/cmd/integration_test/cmd/cleanupvsphere.go @@ -0,0 +1,65 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/internal/test/e2e" + "github.com/aws/eks-anywhere/pkg/logger" +) + +const ( + clusterNameFlagName = "cluster-name" +) + +var cleanUpVsphereCmd = &cobra.Command{ + Use: "vsphere", + Short: "Clean up e2e vms on vsphere vcenter", + Long: "Clean up vms created for e2e testing on vsphere vcenter", + SilenceUsage: true, + PreRun: preRunCleanUpVsphereSetup, + RunE: func(cmd *cobra.Command, args []string) error { + err := cleanUpVsphereTestResources(cmd.Context()) + if err != nil { + logger.Fatal(err, "Failed to cleanup e2e vms on vsphere vcenter") + } + return nil + }, +} + +func preRunCleanUpVsphereSetup(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +var requiredVsphereCleanUpFlags = []string{clusterNameFlagName} + +func init() { + cleanUpInstancesCmd.AddCommand(cleanUpVsphereCmd) + cleanUpVsphereCmd.Flags().StringP(clusterNameFlagName, "n", "", "Cluster name for associated vms") + + for _, flag := range requiredVsphereCleanUpFlags { + if err := cleanUpVsphereCmd.MarkFlagRequired(flag); err != nil { + log.Fatalf("Error marking flag %s as required: %v", flag, err) + } + } +} + +func cleanUpVsphereTestResources(ctx context.Context) error { + clusterName := viper.GetString(clusterNameFlagName) + err := e2e.CleanUpVsphereTestResources(ctx, clusterName) + if err != nil { + return fmt.Errorf("error running cleanup for vsphere vcenter vms: %v", err) + } + + return nil +} diff --git a/cmd/integration_test/cmd/dockertest.go b/cmd/integration_test/cmd/dockertest.go new file mode 100644 index 000000000000..b45d8814282d --- /dev/null +++ b/cmd/integration_test/cmd/dockertest.go @@ -0,0 +1,96 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws/session" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/logger" +) + +var dockerIntegrationTestCmd = &cobra.Command{ + Use: "docker", + Short: "End to end test with docker", + Long: "Run end to end test with docker", + PreRun: preRunSetup, + RunE: func(cmd *cobra.Command, args []string) error { + err := runDockerIntegrationTest(cmd.Context()) + if err != nil { + logger.Fatal(err, "Failed to run docker e2e test") + } + return nil + }, +} + +func preRunSetup(cmd *cobra.Command, args []string) { + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + err := viper.BindPFlag(flag.Name, flag) + if err != nil { + log.Fatalf("Error initializing flags: %v", err) + } + }) +} + +func init() { + integrationTestCmd.AddCommand(dockerIntegrationTestCmd) + dockerIntegrationTestCmd.Flags().StringP("ami-id", "a", "", "Ami id") + dockerIntegrationTestCmd.Flags().StringP("storage-bucket", "s", "", "S3 bucket name to store eks-a binary") + dockerIntegrationTestCmd.Flags().StringP("job-id", "j", "", "Id of the job being run") + dockerIntegrationTestCmd.Flags().StringP("instance-profile-name", "i", "", "IAM instance profile name to attach to ec2 instances") + dockerIntegrationTestCmd.Flags().StringP("subnet-id", "n", "", "EC2 subnet ID") + dockerIntegrationTestCmd.Flags().StringP("dry-run", "d", "false", "Dry run flag") +} + +func runDockerIntegrationTest(ctx context.Context) error { + fmt.Println("Running e2e test with docker") + amiId := viper.GetString("ami-id") + if amiId == "" { + log.Fatal(errors.New("no ami-id was provided")) + } + storageBucket := viper.GetString("storage-bucket") + if storageBucket == "" { + log.Fatal(errors.New("no storage bucket name was provided")) + } + jobId := viper.GetString("job-id") + + if jobId == "" { + log.Fatal(errors.New("no job id was provided")) + } + + instanceProfileName := viper.GetString("instance-profile-name") + + if instanceProfileName == "" { + log.Fatal(errors.New("no instance profile name was provided")) + } + + subnetId := viper.GetString("subnet-id") + if subnetId == "" { + log.Fatal(errors.New("no subnet id was provided")) + } + + dryRun := viper.GetString("dry-run") + + if dryRun == "true" { + return nil + } + + session := session.Must(session.NewSession()) + // Sending subnet id as an empty string for now. Will send an actual id when we create + // a subnet for this + instanceId := createTestSetup(session, amiId, instanceProfileName, storageBucket, jobId, "") + createCluster(session, instanceId) + deleteCluster(session, instanceId) + + key := "Integration-Test-Done" + value := "TRUE" + tagEc2Instance(session, instanceId, key, value) + + fmt.Println("Test ran successfully") + return nil +} diff --git a/cmd/integration_test/cmd/root.go b/cmd/integration_test/cmd/root.go new file mode 100644 index 000000000000..0f93d7affd87 --- /dev/null +++ b/cmd/integration_test/cmd/root.go @@ -0,0 +1,43 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/logger" +) + +var rootCmd = &cobra.Command{ + Use: "integration_test", + Short: "Integration test", + Long: `Run integration test`, + PersistentPreRun: rootPersistentPreRun, +} + +func init() { + rootCmd.PersistentFlags().IntP("verbosity", "v", 0, "Set the log level verbosity") + if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { + log.Fatalf("failed to bind flags for root: %v", err) + } +} + +func rootPersistentPreRun(cmd *cobra.Command, args []string) { + if err := initLogger(); err != nil { + log.Fatal(err) + } +} + +func initLogger() error { + if err := logger.InitZap(viper.GetInt("verbosity")); err != nil { + return fmt.Errorf("failed init zap logger in root command: %v", err) + } + + return nil +} + +func Execute() error { + return rootCmd.Execute() +} diff --git a/cmd/integration_test/cmd/run.go b/cmd/integration_test/cmd/run.go new file mode 100644 index 000000000000..72a761b8c712 --- /dev/null +++ b/cmd/integration_test/cmd/run.go @@ -0,0 +1,84 @@ +package cmd + +import ( + "context" + "fmt" + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/internal/test/e2e" + "github.com/aws/eks-anywhere/pkg/logger" +) + +const ( + amiIdFlagName = "ami-id" + storageBucketFlagName = "storage-bucket" + jobIdFlagName = "job-id" + instanceProfileFlagName = "instance-profile-name" + subnetIdFlagName = "subnet-id" + regexFlagName = "regex" + maxInstancesFlagName = "max-instances" +) + +var runE2ECmd = &cobra.Command{ + Use: "run", + Short: "Run E2E", + Long: "Run end to end tests", + SilenceUsage: true, + PreRun: preRunSetup, + RunE: func(cmd *cobra.Command, args []string) error { + err := runE2E(cmd.Context()) + if err != nil { + logger.Fatal(err, "Failed to run e2e test") + } + return nil + }, +} + +var requiredFlags = []string{amiIdFlagName, storageBucketFlagName, jobIdFlagName, instanceProfileFlagName} + +func init() { + integrationTestCmd.AddCommand(runE2ECmd) + runE2ECmd.Flags().StringP(amiIdFlagName, "a", "", "Ami id") + runE2ECmd.Flags().StringP(storageBucketFlagName, "s", "", "S3 bucket name to store eks-a binary") + runE2ECmd.Flags().StringP(jobIdFlagName, "j", "", "Id of the job being run") + runE2ECmd.Flags().StringP(instanceProfileFlagName, "i", "", "IAM instance profile name to attach to ec2 instances") + runE2ECmd.Flags().StringP(subnetIdFlagName, "n", "", "EC2 subnet ID") + runE2ECmd.Flags().StringP(regexFlagName, "r", "", "Run only those tests and examples matching the regular expression. Equivalent to go test -run") + runE2ECmd.Flags().IntP(maxInstancesFlagName, "m", 1, "Run tests in parallel with multiple EC2 instances") + + for _, flag := range requiredFlags { + if err := runE2ECmd.MarkFlagRequired(flag); err != nil { + log.Fatalf("Error marking flag %s as required: %v", flag, err) + } + } +} + +func runE2E(ctx context.Context) error { + amiId := viper.GetString(amiIdFlagName) + storageBucket := viper.GetString(storageBucketFlagName) + jobId := viper.GetString(jobIdFlagName) + instanceProfileName := viper.GetString(instanceProfileFlagName) + subnetId := viper.GetString(subnetIdFlagName) + testRegex := viper.GetString(regexFlagName) + maxInstances := viper.GetInt(maxInstancesFlagName) + + runConf := e2e.ParallelRunConf{ + MaxIntances: maxInstances, + AmiId: amiId, + InstanceProfileName: instanceProfileName, + StorageBucket: storageBucket, + JobId: jobId, + SubnetId: subnetId, + Regex: testRegex, + } + + err := e2e.RunTestsInParallel(runConf) + if err != nil { + return fmt.Errorf("error running e2e tests: %v", err) + } + + return nil +} diff --git a/cmd/integration_test/cmd/test.go b/cmd/integration_test/cmd/test.go new file mode 100644 index 000000000000..6d59625f667b --- /dev/null +++ b/cmd/integration_test/cmd/test.go @@ -0,0 +1,15 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var integrationTestCmd = &cobra.Command{ + Use: "e2e", + Short: "Integration test", + Long: "Run integration test on eks-d", +} + +func init() { + rootCmd.AddCommand(integrationTestCmd) +} diff --git a/cmd/integration_test/cmd/utils.go b/cmd/integration_test/cmd/utils.go new file mode 100644 index 000000000000..e13b679789ba --- /dev/null +++ b/cmd/integration_test/cmd/utils.go @@ -0,0 +1,285 @@ +package cmd + +import ( + "errors" + "fmt" + "log" + "os" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/aws/aws-sdk-go/service/ssm" +) + +func uploadToS3Bucket(session *session.Session, file string, key string, bucket string) { + s3Uploader := s3manager.NewUploader(session) + fileBody, err := os.Open(file) + if err != nil { + log.Fatal(err) + } + + _, err = s3Uploader.Upload(&s3manager.UploadInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + Body: fileBody, + }) + if err != nil { + log.Fatal(err) + } +} + +func createEc2Instance(session *session.Session, amiId string, key string, tag string, instanceProfileName string, subnetId string) *string { + service := ec2.New(session) + + input := ec2.RunInstancesInput{ + ImageId: aws.String(amiId), + InstanceType: aws.String("t3.2xlarge"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + BlockDeviceMappings: []*ec2.BlockDeviceMapping{ + { + DeviceName: aws.String("/dev/xvda"), + Ebs: &ec2.EbsBlockDevice{ + VolumeSize: aws.Int64(100), + }, + }, + }, + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Name: aws.String(instanceProfileName), + }, + SubnetId: aws.String(subnetId), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("instance"), + Tags: []*ec2.Tag{ + { + Key: aws.String(key), + Value: aws.String(tag), + }, + }, + }, + }, + } + if subnetId != "" { + input.SubnetId = aws.String(subnetId) + } + result, err := service.RunInstances(&input) + if err != nil { + log.Fatal(err) + } + fmt.Println("Instance created and Tagged") + + fmt.Println("Wait till the instance starts running") + instanceInput := &ec2.DescribeInstancesInput{ + InstanceIds: []*string{ + result.Instances[0].InstanceId, + }, + } + err = service.WaitUntilInstanceRunning(instanceInput) + if err != nil { + log.Fatal(err) + } + fmt.Println("Instance is running") + + return result.Instances[0].InstanceId +} + +func tagEc2Instance(session *session.Session, instanceId *string, key string, value string) { + fmt.Println("Tag ec2 instance") + service := ec2.New(session) + _, err := service.CreateTags(&ec2.CreateTagsInput{ + Resources: []*string{instanceId}, + Tags: []*ec2.Tag{ + { + Key: aws.String(key), + Value: aws.String(value), + }, + }, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully tagged ec2 instance") +} + +func runAndValidateSsmCommand(session *session.Session, instanceId *string, command string) error { + service := ssm.New(session) + fmt.Println("Running ssm command") + result, err := service.SendCommand( + &ssm.SendCommandInput{ + DocumentName: aws.String("AWS-RunShellScript"), + InstanceIds: []*string{instanceId}, + Parameters: map[string][]*string{"commands": {aws.String(command)}}, + }, + ) + if err != nil { + return err + } + + // Make sure ssm send command is registered + retryCount := 0 + registrationErr := err + commandStatus := "" + fmt.Println("Wait till the ssm command is registered") + for retryCount <= 9 { + status, registrationErr := service.GetCommandInvocation( + &ssm.GetCommandInvocationInput{ + CommandId: result.Command.CommandId, + InstanceId: instanceId, + }, + ) + if registrationErr != nil { + time.Sleep(20 * time.Second) + retryCount = retryCount + 1 + continue + } else { + commandStatus = *status.Status + fmt.Println("Command status: ", commandStatus) + if commandStatus != "Pending" && commandStatus != "InProgress" && commandStatus != "Delayed" { + fmt.Println("Command stdout: ", *status.StandardOutputContent) + fmt.Println("Command stderr: ", *status.StandardErrorContent) + fmt.Println("Command statusDetails: ", *status.StatusDetails) + } + break + } + } + if registrationErr != nil { + return registrationErr + } + if commandStatus == "Success" { + return nil + } + + fmt.Println("Checking command status") + retryCount = 0 + for retryCount <= 60 { + status, err := service.GetCommandInvocation( + &ssm.GetCommandInvocationInput{ + CommandId: result.Command.CommandId, + InstanceId: instanceId, + }, + ) + if err != nil { + return nil + } + commandStatus = *status.Status + fmt.Println("Command status: ", commandStatus) + if commandStatus != "Pending" && commandStatus != "InProgress" && commandStatus != "Delayed" { + fmt.Println("Command stdout: ", *status.StandardOutputContent) + fmt.Println("Command stderr: ", *status.StandardErrorContent) + fmt.Println("Command statusDetails: ", *status.StatusDetails) + break + } + retryCount = retryCount + 1 + time.Sleep(20 * time.Second) + } + if commandStatus != "Success" { + return errors.New("failed to execute ssm command") + } + return nil +} + +func getVSphereEnvVarCommand() string { + command := "" + if vSphereUsername, ok := os.LookupEnv("VSPHERE_USERNAME"); ok && len(vSphereUsername) > 0 { + command += "export VSPHERE_USERNAME=" + vSphereUsername + ";" + } + if vSpherePassword, ok := os.LookupEnv("VSPHERE_PASSWORD"); ok && len(vSpherePassword) > 0 { + command += "export VSPHERE_PASSWORD=" + vSpherePassword + ";" + } + if govcURL, ok := os.LookupEnv("GOVC_URL"); ok && len(govcURL) > 0 { + command += "export GOVC_URL=" + govcURL + ";" + } + if govcInsecure, ok := os.LookupEnv("GOVC_INSECURE"); ok && len(govcInsecure) > 0 { + command += "export GOVC_INSECURE=" + govcInsecure + ";" + } + return command +} + +func createTestSetup(session *session.Session, amiId string, instanceProfileName string, storageBucket string, jobId string, subnetId string) *string { + fmt.Println("Upload eks-a binary to s3 bucket") + file := "bin/linux/eks-a" + key := jobId + "/eks-a" + uploadToS3Bucket(session, file, key, storageBucket) + fmt.Println("Upload Completed") + + fmt.Println("Create an ec2 instance with an instance profile and tag it") + key = "Integration-Test" + tag := "EKSA-DOCKER" + instanceId := createEc2Instance(session, amiId, key, tag, instanceProfileName, subnetId) + fmt.Println("InstanceId: ", *instanceId) + + var err error + + command := "ls" + retryCount := 0 + fmt.Println("Run ssm sendCommand to execute test command: ", command) + + for retryCount <= 9 { + err = runAndValidateSsmCommand(session, instanceId, command) + if err == nil { + break + } + fmt.Println("Retrying ssm send to make sure that the ec2 instance is registered with ssm") + retryCount = retryCount + 1 + time.Sleep(20 * time.Second) + } + + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully executed test command") + + fmt.Println("Run ssm sendCommand to download eks-a binary from the s3 bucket") + command = "aws s3 cp s3://" + storageBucket + "/" + jobId + "/eks-a .; chmod 645 eks-a" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully downloaded eks-a binary") + return instanceId +} + +func createCluster(session *session.Session, instanceId *string) { + fmt.Println("Run ssm sendCommand to generate cluster config") + command := "./eks-a generate clusterconfig -p docker e2e-docker > eksa-cluster.yaml" + fmt.Println(command) + err := runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully generated cluster config") + + fmt.Println("Run ssm sendCommand to print the cluster config") + command = "cat eksa-cluster.yaml" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully printed cluster config") + + fmt.Println("Run ssm sendCommand to create eks-a cluster") + command = "./eks-a create cluster -v 6 -f eksa-cluster.yaml" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully created eks-a cluster") +} + +func deleteCluster(session *session.Session, instanceId *string) { + fmt.Println("Run ssm sendCommand to delete eks-a cluster") + command := "./eks-a delete cluster -v 6 -f eksa-cluster.yaml" + fmt.Println(command) + err := runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully deleted eks-a cluster") +} diff --git a/cmd/integration_test/cmd/vspheretest.go b/cmd/integration_test/cmd/vspheretest.go new file mode 100644 index 000000000000..d105c0c582e9 --- /dev/null +++ b/cmd/integration_test/cmd/vspheretest.go @@ -0,0 +1,168 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws/session" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/aws/eks-anywhere/pkg/logger" +) + +var vsphereIntegrationTestCmd = &cobra.Command{ + Use: "vsphere", + Short: "End to end test with vsphere", + Long: "Run end to end test with vsphere", + PreRun: preRunSetup, + RunE: func(cmd *cobra.Command, args []string) error { + err := runvsphereIntegrationTest(cmd.Context()) + if err != nil { + logger.Fatal(err, "Failed to run vsphere e2e test") + } + return nil + }, +} + +func init() { + integrationTestCmd.AddCommand(vsphereIntegrationTestCmd) + vsphereIntegrationTestCmd.Flags().StringP("ami-id", "a", "", "Ami id") + vsphereIntegrationTestCmd.Flags().StringP("storage-bucket", "s", "", "S3 bucket name to store eks-a binary") + vsphereIntegrationTestCmd.Flags().StringP("job-id", "j", "", "Id of the job being run") + vsphereIntegrationTestCmd.Flags().StringP("instance-profile-name", "i", "", "IAM instance profile name to attach to ec2 instances") + vsphereIntegrationTestCmd.Flags().StringP("subnet-id", "n", "", "EC2 subnet ID") + vsphereIntegrationTestCmd.Flags().StringP("dry-run", "d", "false", "Dry run flag") +} + +func runvsphereIntegrationTest(ctx context.Context) error { + fmt.Println("Running e2e test with vsphere") + amiId := viper.GetString("ami-id") + if amiId == "" { + log.Fatal(errors.New("no ami-id was provided")) + } + storageBucket := viper.GetString("storage-bucket") + if storageBucket == "" { + log.Fatal(errors.New("no storage bucket name was provided")) + } + jobId := viper.GetString("job-id") + + if jobId == "" { + log.Fatal(errors.New("no job id was provided")) + } + + instanceProfileName := viper.GetString("instance-profile-name") + + if instanceProfileName == "" { + log.Fatal(errors.New("no instance profile name was provided")) + } + + subnetId := viper.GetString("subnet-id") + dryRun := viper.GetString("dry-run") + + if dryRun == "true" { + return nil + } + + session := session.Must(session.NewSession()) + fmt.Println("Upload eks-a binary to s3 bucket") + file := "bin/linux/eks-a" + key := jobId + "/eks-a" + uploadToS3Bucket(session, file, key, storageBucket) + fmt.Println("Upload Completed") + + fmt.Println("Upload eks-a-tool binary to s3 bucket") + file = "bin/eks-a-tool" + key = jobId + "/eks-a-tool" + uploadToS3Bucket(session, file, key, storageBucket) + fmt.Println("Upload Completed") + + fmt.Println("Upload cluster config to s3 bucket") + file = "e2e-test" + key = jobId + "/e2e-test" + uploadToS3Bucket(session, file, key, storageBucket) + fmt.Println("Upload Completed") + + fmt.Println("Create an ec2 instance with an instance profile and tag it") + key = "Integration-Test" + tag := "EKSA-VSPHERE" + instanceId := createEc2Instance(session, amiId, key, tag, instanceProfileName, subnetId) + fmt.Println("InstanceId: ", *instanceId) + + var err error + + command := "ls" + retryCount := 0 + fmt.Println("Run ssm sendCommand to execute test command: ", command) + + for retryCount <= 9 { + err = runAndValidateSsmCommand(session, instanceId, command) + if err == nil { + break + } + fmt.Println("Retrying ssm send to make sure that the ec2 instance is registered with ssm") + retryCount = retryCount + 1 + time.Sleep(20 * time.Second) + } + + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully executed test command") + + fmt.Println("Run ssm sendCommand to download eks-a, eks-a-tools binary and cluster config from the s3 bucket") + command = "aws s3 cp s3://" + storageBucket + "/" + jobId + "/ . --recursive; chmod 645 eks-a; chmod 645 eks-a-tool" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully downloaded resources from S3 bucket") + + fmt.Println("Run ssm sendCommand to get a unique IP for Control plane IP and set CONTROL_PLANE_ENDPOINT_IP") + command = getVSphereEnvVarCommand() + command += "export CONTROL_PLANE_ENDPOINT_IP=$(./eks-a-tool unique-ip -c 198.18.0.0/16); " + command += "echo $CONTROL_PLANE_ENDPOINT_IP; " + command += "./eks-a-tool vsphere autofill -f e2e-test; cat e2e-test;" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully generated unique IP and set CONTROL_PLANE_ENDPOINT_IP") + + fmt.Println("Run ssm sendCommand to rename the cluster config") + command = "mv e2e-test e2e-test.yaml;" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully renamed cluster config") + + fmt.Println("Run ssm sendCommand to create eks-a cluster on vSphere") + command = getVSphereEnvVarCommand() + command += "./eks-a create cluster -v 4 -f e2e-test.yaml" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully created eks-a cluster") + + fmt.Println("Run ssm sendCommand to delete eks-a cluster on vSphere") + command = getVSphereEnvVarCommand() + command += "./eks-a delete cluster -v 4 -f e2e-test.yaml" + fmt.Println(command) + err = runAndValidateSsmCommand(session, instanceId, command) + if err != nil { + log.Fatal(err) + } + fmt.Println("Successfully deleted eks-a cluster") + + fmt.Println("Test ran Successfully") + return nil +} diff --git a/cmd/integration_test/main.go b/cmd/integration_test/main.go new file mode 100644 index 000000000000..1174d4e822e6 --- /dev/null +++ b/cmd/integration_test/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "os" + + "github.com/aws/eks-anywhere/cmd/integration_test/cmd" +) + +func main() { + if cmd.Execute() == nil { + os.Exit(0) + } + os.Exit(-1) +} diff --git a/config/.DS_Store b/config/.DS_Store new file mode 100644 index 000000000000..37de138f8b37 Binary files /dev/null and b/config/.DS_Store differ diff --git a/config/certmanager/certificate.yaml b/config/certmanager/certificate.yaml new file mode 100644 index 000000000000..52d866183c76 --- /dev/null +++ b/config/certmanager/certificate.yaml @@ -0,0 +1,25 @@ +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io +# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: selfsigned-issuer + namespace: system +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml + namespace: system +spec: + # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize + dnsNames: + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize diff --git a/config/certmanager/kustomization.yaml b/config/certmanager/kustomization.yaml new file mode 100644 index 000000000000..bebea5a595ee --- /dev/null +++ b/config/certmanager/kustomization.yaml @@ -0,0 +1,5 @@ +resources: +- certificate.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/certmanager/kustomizeconfig.yaml b/config/certmanager/kustomizeconfig.yaml new file mode 100644 index 000000000000..90d7c313ca10 --- /dev/null +++ b/config/certmanager/kustomizeconfig.yaml @@ -0,0 +1,16 @@ +# This configuration is for teaching kustomize how to update name ref and var substitution +nameReference: +- kind: Issuer + group: cert-manager.io + fieldSpecs: + - kind: Certificate + group: cert-manager.io + path: spec/issuerRef/name + +varReference: +- kind: Certificate + group: cert-manager.io + path: spec/commonName +- kind: Certificate + group: cert-manager.io + path: spec/dnsNames diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_awsdatacenterconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_awsdatacenterconfigs.yaml new file mode 100644 index 000000000000..b279bf6c2d9f --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_awsdatacenterconfigs.yaml @@ -0,0 +1,61 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: awsdatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: AWSDatacenterConfig + listKind: AWSDatacenterConfigList + plural: awsdatacenterconfigs + singular: awsdatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AWSDatacenterConfig is the Schema for the AWSDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AWSDatacenterConfigSpec defines the desired state of AWSDatacenterConfig + properties: + amiID: + type: string + region: + type: string + required: + - amiID + - region + type: object + status: + description: AWSDatacenterConfigStatus defines the observed state of AWSDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_bundles.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_bundles.yaml new file mode 100644 index 000000000000..6071232c2078 --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_bundles.yaml @@ -0,0 +1,1395 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: bundles.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: Bundles + listKind: BundlesList + plural: bundles + singular: bundles + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Bundles is the Schema for the bundles API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BundlesSpec defines the desired state of Bundles + properties: + cliMaxVersion: + type: string + cliMinVersion: + type: string + number: + description: Monotonically increasing release number + type: integer + versionsBundles: + items: + properties: + aws: + properties: + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - clusterTemplate + - components + - controller + - kubeProxy + - metadata + - version + type: object + bootstrap: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + bottlerocketBootstrap: + properties: + bootstrap: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - bootstrap + type: object + certManager: + properties: + acmesolver: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + cainjector: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + webhook: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - acmesolver + - cainjector + - controller + - webhook + type: object + cilium: + properties: + cilium: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manifest: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + operator: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - cilium + - manifest + - operator + type: object + clusterAPI: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + controlPlane: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + docker: + properties: + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manager: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - clusterTemplate + - components + - kubeProxy + - manager + - metadata + - version + type: object + eksD: + properties: + channel: + description: Release branch of the EKS-D release like 1-19, + 1-20 + type: string + gitCommit: + description: Git commit the component is built from, before + any patches + type: string + kindNode: + description: KindNode points to a kind image built with + this eks-d version + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeVersion: + description: Release number of EKS-D release + type: string + manifestUrl: + description: Url pointing to the EKS-D release manifest + using which assets where created + type: string + name: + type: string + ova: + description: Ova points to a collection of Ovas built with + this eks-d version + properties: + bottlerocket: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + sha256: + description: The sha256 of the asset, only applies + for 'file' store + type: string + sha512: + description: The sha512 of the asset, only applies + for 'file' store + type: string + uri: + description: The URI where the asset is located + type: string + type: object + ubuntu: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + sha256: + description: The sha256 of the asset, only applies + for 'file' store + type: string + sha512: + description: The sha512 of the asset, only applies + for 'file' store + type: string + uri: + description: The URI where the asset is located + type: string + type: object + type: object + type: object + eksa: + properties: + cliTools: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + required: + - cliTools + - components + type: object + etcdadmBootstrap: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + etcdadmController: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + flux: + properties: + helmController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kustomizeController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + notificationController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + sourceController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - helmController + - kustomizeController + - notificationController + - sourceController + type: object + kubeVersion: + type: string + vSphere: + properties: + clusterAPIController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + driver: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeVip: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manager: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + syncer: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + version: + type: string + required: + - clusterAPIController + - clusterTemplate + - components + - driver + - kubeProxy + - kubeVip + - manager + - metadata + - syncer + - version + type: object + required: + - aws + - bootstrap + - bottlerocketBootstrap + - certManager + - cilium + - clusterAPI + - controlPlane + - docker + - eksD + - eksa + - etcdadmBootstrap + - etcdadmController + - flux + - kubeVersion + - vSphere + type: object + type: array + required: + - cliMaxVersion + - cliMinVersion + - number + - versionsBundles + type: object + status: + description: BundlesStatus defines the observed state of Bundles + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml new file mode 100644 index 000000000000..e5d33db1e33b --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml @@ -0,0 +1,164 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: clusters.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: Cluster + listKind: ClusterList + plural: clusters + singular: cluster + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Cluster is the Schema for the clusters API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterSpec defines the desired state of Cluster + properties: + clusterNetwork: + properties: + cni: + description: CNI specifies the CNI plugin to be installed in the + cluster + type: string + pods: + description: Comma-separated list of CIDR blocks to use for pod + and service subnets. Defaults to 192.168.0.0/16 for pod subnet. + properties: + cidrBlocks: + items: + type: string + type: array + type: object + services: + properties: + cidrBlocks: + items: + type: string + type: array + type: object + type: object + controlPlaneConfiguration: + properties: + count: + description: Count defines the number of desired control plane + nodes. Defaults to 1. + type: integer + endpoint: + description: Endpoint defines the host ip and port to use for + the control plane. + properties: + host: + description: Host defines the ip that you want to use to connect + to the control plane + type: string + required: + - host + type: object + machineGroupRef: + description: MachineGroupRef defines the machine group configuration + for the control plane. + properties: + kind: + type: string + name: + type: string + type: object + type: object + datacenterRef: + properties: + kind: + type: string + name: + type: string + type: object + externalEtcdConfiguration: + description: ExternalEtcdConfiguration defines the configuration options + for using unstacked etcd topology + properties: + count: + type: integer + type: object + gitOpsRef: + properties: + kind: + type: string + name: + type: string + type: object + identityProviderRefs: + items: + properties: + kind: + type: string + name: + type: string + type: object + type: array + kubernetesVersion: + type: string + overrideClusterSpecFile: + type: string + proxyConfiguration: + properties: + httpProxy: + type: string + httpsProxy: + type: string + noProxy: + items: + type: string + type: array + type: object + workerNodeGroupConfigurations: + items: + properties: + count: + description: Count defines the number of desired worker nodes. + Defaults to 1. + type: integer + machineGroupRef: + description: MachineGroupRef defines the machine group configuration + for the worker nodes. + properties: + kind: + type: string + name: + type: string + type: object + type: object + type: array + type: object + status: + description: ClusterStatus defines the observed state of Cluster + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_dockerdatacenterconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_dockerdatacenterconfigs.yaml new file mode 100644 index 000000000000..3af76043a2b2 --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_dockerdatacenterconfigs.yaml @@ -0,0 +1,54 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: dockerdatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: DockerDatacenterConfig + listKind: DockerDatacenterConfigList + plural: dockerdatacenterconfigs + singular: dockerdatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DockerDatacenterConfig is the Schema for the DockerDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DockerDatacenterConfigSpec defines the desired state of DockerDatacenterConfig + type: object + status: + description: DockerDatacenterConfigStatus defines the observed state of + DockerDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_gitopsconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_gitopsconfigs.yaml new file mode 100644 index 000000000000..40e10ad2393c --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_gitopsconfigs.yaml @@ -0,0 +1,88 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: gitopsconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: GitOpsConfig + listKind: GitOpsConfigList + plural: gitopsconfigs + singular: gitopsconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GitOps defines the configurations of GitOps Toolkit and Git + repository it links to. + properties: + flux: + description: Flux defines the Git repository options for Flux v2 + properties: + github: + description: github is the name of the Git Provider to host the + Git repo. + properties: + branch: + description: Git branch. Defaults to main. + type: string + clusterConfigPath: + description: ClusterConfigPath relative to the repository + root, when specified the cluster sync will be scoped to + this path. + type: string + fluxSystemNamespace: + description: FluxSystemNamespace scope for this operation. + Defaults to flux-system. + type: string + owner: + description: Owner is the user or organization name of the + Git provider. + type: string + personal: + description: if true, the owner is assumed to be a Git user; + otherwise an org. + type: boolean + repository: + description: Repository name. + type: string + required: + - owner + - repository + type: object + type: object + type: object + status: + description: GitOpsConfigStatus defines the observed state of GitOpsConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_oidcconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_oidcconfigs.yaml new file mode 100644 index 000000000000..fd7803bce5f3 --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_oidcconfigs.yaml @@ -0,0 +1,91 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: oidcconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: OIDCConfig + listKind: OIDCConfigList + plural: oidcconfigs + singular: oidcconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OIDCConfig is the Schema for the oidcconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OIDCConfigSpec defines the desired state of OIDCConfig + properties: + clientId: + description: ClientId defines the client ID for the OpenID Connect + client + type: string + groupsClaim: + description: GroupsClaim defines the name of a custom OpenID Connect + claim for specifying user groups + type: string + groupsPrefix: + description: GroupsPrefix defines a string to be prefixed to all groups + to prevent conflicts with other authentication strategies + type: string + issuerUrl: + description: IssuerUrl defines the URL of the OpenID issuer, only + HTTPS scheme will be accepted + type: string + requiredClaims: + description: RequiredClaims defines a key=value pair that describes + a required claim in the ID Token + items: + properties: + claim: + type: string + value: + type: string + type: object + type: array + usernameClaim: + description: UsernameClaim defines the OpenID claim to use as the + user name. Note that claims other than the default ('sub') is not + guaranteed to be unique and immutable + type: string + usernamePrefix: + description: UsernamePrefix defines a string to prefixed to all usernames. + If not provided, username claims other than 'email' are prefixed + by the issuer URL to avoid clashes. To skip any prefixing, provide + the value '-'. + type: string + type: object + status: + description: OIDCConfigStatus defines the observed state of OIDCConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_vspheredatacenterconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_vspheredatacenterconfigs.yaml new file mode 100644 index 000000000000..9c7a9534dd69 --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_vspheredatacenterconfigs.yaml @@ -0,0 +1,72 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: vspheredatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: VSphereDatacenterConfig + listKind: VSphereDatacenterConfigList + plural: vspheredatacenterconfigs + singular: vspheredatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: VSphereDatacenterConfig is the Schema for the VSphereDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VSphereDatacenterConfigSpec defines the desired state of + VSphereDatacenterConfig + properties: + datacenter: + type: string + insecure: + type: boolean + network: + type: string + server: + type: string + thumbprint: + type: string + required: + - datacenter + - insecure + - network + - server + - thumbprint + type: object + status: + description: VSphereDatacenterConfigStatus defines the observed state + of VSphereDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_vspheremachineconfigs.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_vspheremachineconfigs.yaml new file mode 100644 index 000000000000..8879f63c7183 --- /dev/null +++ b/config/crd/bases/anywhere.eks.amazonaws.com_vspheremachineconfigs.yaml @@ -0,0 +1,96 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: vspheremachineconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: VSphereMachineConfig + listKind: VSphereMachineConfigList + plural: vspheremachineconfigs + singular: vspheremachineconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: VSphereMachineConfig is the Schema for the vspheremachineconfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VSphereMachineConfigSpec defines the desired state of VSphereMachineConfig + properties: + datastore: + type: string + diskGiB: + type: integer + folder: + type: string + memoryMiB: + type: integer + numCPUs: + type: integer + osFamily: + type: string + resourcePool: + type: string + storagePolicyName: + type: string + template: + type: string + users: + items: + description: UserConfiguration defines the configuration of the + user to be added to the VSphere VM + properties: + name: + type: string + sshAuthorizedKeys: + items: + type: string + type: array + required: + - name + - sshAuthorizedKeys + type: object + type: array + required: + - datastore + - folder + - memoryMiB + - numCPUs + - osFamily + - resourcePool + type: object + status: + description: VSphereMachineConfigStatus defines the observed state of + VSphereMachineConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 000000000000..fd37d0e73b65 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,28 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/anywhere.eks.amazonaws.com_clusters.yaml +- bases/anywhere.eks.amazonaws.com_awsdatacenterconfigs.yaml +- bases/anywhere.eks.amazonaws.com_dockerdatacenterconfigs.yaml +- bases/anywhere.eks.amazonaws.com_vspheredatacenterconfigs.yaml +- bases/anywhere.eks.amazonaws.com_vspheremachineconfigs.yaml +- bases/anywhere.eks.amazonaws.com_bundles.yaml +- bases/anywhere.eks.amazonaws.com_gitopsconfigs.yaml +- bases/anywhere.eks.amazonaws.com_oidcconfigs.yaml +#+kubebuilder:scaffold:crdkustomizeresource + +patchesStrategicMerge: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +- patches/webhook_in_clusters.yaml +#+kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +- patches/cainjection_in_clusters.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml new file mode 100644 index 000000000000..ec5c150a9df2 --- /dev/null +++ b/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/config/crd/patches/cainjection_in_clusters.yaml b/config/crd/patches/cainjection_in_clusters.yaml new file mode 100644 index 000000000000..b4aa41e30c46 --- /dev/null +++ b/config/crd/patches/cainjection_in_clusters.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: clusters.anywhere.eks.amazonaws.com diff --git a/config/crd/patches/webhook_in_clusters.yaml b/config/crd/patches/webhook_in_clusters.yaml new file mode 100644 index 000000000000..24b34397bef8 --- /dev/null +++ b/config/crd/patches/webhook_in_clusters.yaml @@ -0,0 +1,15 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusters.anywhere.eks.amazonaws.com +spec: + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + namespace: eksa-system + name: webhook-service + path: /convert diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 000000000000..7436e8c6bfbf --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,77 @@ +# Adds namespace to all resources. +namespace: eksa-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: eksa- + +resources: +- namespace.yaml + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +bases: +- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus + +patchesStrategicMerge: +# Protect the /metrics endpoint by putting it behind auth. +# If you want your controller-manager to expose the /metrics +# endpoint w/o any authn/z, please comment the following line. +- manager_auth_proxy_patch.yaml + +# Mount the controller config file for loading manager configurations +# through a ComponentConfig type +#- manager_config_patch.yaml + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +- manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. +# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. +# 'CERTMANAGER' needs to be enabled to use ca injection +- webhookcainjection_patch.yaml + +# the following config is for teaching kustomize how to do var substitution +vars: +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml + fieldref: + fieldpath: metadata.namespace +- name: CERTIFICATE_NAME + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml +- name: SERVICE_NAMESPACE # namespace of the service + objref: + kind: Service + version: v1 + name: webhook-service + fieldref: + fieldpath: metadata.namespace +- name: SERVICE_NAME + objref: + kind: Service + version: v1 + name: webhook-service diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 000000000000..a224be19ea19 --- /dev/null +++ b/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,26 @@ +# This patch inject a sidecar container which is a HTTP proxy for the +# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + name: https + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml new file mode 100644 index 000000000000..6c400155cfbc --- /dev/null +++ b/config/default/manager_config_patch.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + args: + - "--config=controller_manager_config.yaml" + volumeMounts: + - name: manager-config + mountPath: /controller_manager_config.yaml + subPath: controller_manager_config.yaml + volumes: + - name: manager-config + configMap: + name: manager-config diff --git a/config/default/manager_webhook_patch.yaml b/config/default/manager_webhook_patch.yaml new file mode 100644 index 000000000000..738de350b71e --- /dev/null +++ b/config/default/manager_webhook_patch.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert diff --git a/config/default/namespace.yaml b/config/default/namespace.yaml new file mode 100644 index 000000000000..1ab3a72555d9 --- /dev/null +++ b/config/default/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: system diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml new file mode 100644 index 000000000000..af621f4ad33c --- /dev/null +++ b/config/default/webhookcainjection_patch.yaml @@ -0,0 +1,15 @@ +# This patch add annotation to admission webhook config and +# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. +# apiVersion: admissionregistration.k8s.io/v1 +# kind: MutatingWebhookConfiguration +# metadata: +# name: eksa-mutating-webhook-configuration +# annotations: +# cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml new file mode 100644 index 000000000000..9f48ab4b8ff8 --- /dev/null +++ b/config/manager/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- manager.yaml + +patchesStrategicMerge: +- manager_service_account_patch.yaml diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml new file mode 100644 index 000000000000..61decb1bf90a --- /dev/null +++ b/config/manager/manager.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: eksa-controller-manager +spec: + selector: + matchLabels: + control-plane: eksa-controller-manager + replicas: 1 + template: + metadata: + labels: + control-plane: eksa-controller-manager + spec: + containers: + - args: + - --leader-elect + image: controller:latest + imagePullPolicy: Always + name: manager + ports: + - containerPort: 8081 + name: healthz + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz + livenessProbe: + httpGet: + path: /healthz + port: healthz + terminationGracePeriodSeconds: 10 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + serviceAccountName: manager diff --git a/config/manager/manager_image_patch.yaml b/config/manager/manager_image_patch.yaml new file mode 100644 index 000000000000..21357674ea0b --- /dev/null +++ b/config/manager/manager_image_patch.yaml @@ -0,0 +1,11 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - image: public.ecr.aws/l0g8r8j6/eks-anywhere-cluster-controller:v0.0.1-8539f509df046a4f567d2182dde824b957136599 + name: manager diff --git a/config/manager/manager_service_account_patch.yaml b/config/manager/manager_service_account_patch.yaml new file mode 100644 index 000000000000..5892631f4665 --- /dev/null +++ b/config/manager/manager_service_account_patch.yaml @@ -0,0 +1,11 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + serviceAccountName: controller-manager + securityContext: + fsGroup: 1000 diff --git a/config/manifest/eksa-components.yaml b/config/manifest/eksa-components.yaml new file mode 100644 index 000000000000..d6ddaf17f784 --- /dev/null +++ b/config/manifest/eksa-components.yaml @@ -0,0 +1,2501 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: eksa-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: awsdatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: AWSDatacenterConfig + listKind: AWSDatacenterConfigList + plural: awsdatacenterconfigs + singular: awsdatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AWSDatacenterConfig is the Schema for the AWSDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AWSDatacenterConfigSpec defines the desired state of AWSDatacenterConfig + properties: + amiID: + type: string + region: + type: string + required: + - amiID + - region + type: object + status: + description: AWSDatacenterConfigStatus defines the observed state of AWSDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: bundles.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: Bundles + listKind: BundlesList + plural: bundles + singular: bundles + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Bundles is the Schema for the bundles API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BundlesSpec defines the desired state of Bundles + properties: + cliMaxVersion: + type: string + cliMinVersion: + type: string + number: + description: Monotonically increasing release number + type: integer + versionsBundles: + items: + properties: + aws: + properties: + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - clusterTemplate + - components + - controller + - kubeProxy + - metadata + - version + type: object + bootstrap: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + bottlerocketBootstrap: + properties: + bootstrap: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - bootstrap + type: object + certManager: + properties: + acmesolver: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + cainjector: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + webhook: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - acmesolver + - cainjector + - controller + - webhook + type: object + cilium: + properties: + cilium: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manifest: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + operator: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - cilium + - manifest + - operator + type: object + clusterAPI: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + controlPlane: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + docker: + properties: + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manager: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - clusterTemplate + - components + - kubeProxy + - manager + - metadata + - version + type: object + eksD: + properties: + channel: + description: Release branch of the EKS-D release like 1-19, + 1-20 + type: string + gitCommit: + description: Git commit the component is built from, before + any patches + type: string + kindNode: + description: KindNode points to a kind image built with + this eks-d version + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeVersion: + description: Release number of EKS-D release + type: string + manifestUrl: + description: Url pointing to the EKS-D release manifest + using which assets where created + type: string + name: + type: string + ova: + description: Ova points to a collection of Ovas built with + this eks-d version + properties: + bottlerocket: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + sha256: + description: The sha256 of the asset, only applies + for 'file' store + type: string + sha512: + description: The sha512 of the asset, only applies + for 'file' store + type: string + uri: + description: The URI where the asset is located + type: string + type: object + ubuntu: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + sha256: + description: The sha256 of the asset, only applies + for 'file' store + type: string + sha512: + description: The sha512 of the asset, only applies + for 'file' store + type: string + uri: + description: The URI where the asset is located + type: string + type: object + type: object + type: object + eksa: + properties: + cliTools: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + required: + - cliTools + - components + type: object + etcdadmBootstrap: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + etcdadmController: + properties: + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + controller: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + version: + type: string + required: + - components + - controller + - kubeProxy + - metadata + - version + type: object + flux: + properties: + helmController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kustomizeController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + notificationController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + sourceController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + required: + - helmController + - kustomizeController + - notificationController + - sourceController + type: object + kubeVersion: + type: string + vSphere: + properties: + clusterAPIController: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + clusterTemplate: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + components: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + driver: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeProxy: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + kubeVip: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + manager: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + metadata: + properties: + uri: + description: URI points to the manifest yaml file + type: string + type: object + syncer: + properties: + arch: + description: Architectures of the asset + items: + type: string + type: array + description: + type: string + imageDigest: + description: The SHA256 digest of the image manifest + type: string + name: + description: The asset name + type: string + os: + description: Operating system of the asset + enum: + - linux + - darwin + - windows + type: string + osName: + description: Name of the OS like ubuntu, bottlerocket + type: string + uri: + description: The image repository, name, and tag + type: string + type: object + version: + type: string + required: + - clusterAPIController + - clusterTemplate + - components + - driver + - kubeProxy + - kubeVip + - manager + - metadata + - syncer + - version + type: object + required: + - aws + - bootstrap + - bottlerocketBootstrap + - certManager + - cilium + - clusterAPI + - controlPlane + - docker + - eksD + - eksa + - etcdadmBootstrap + - etcdadmController + - flux + - kubeVersion + - vSphere + type: object + type: array + required: + - cliMaxVersion + - cliMinVersion + - number + - versionsBundles + type: object + status: + description: BundlesStatus defines the observed state of Bundles + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: eksa-system/eksa-serving-cert + controller-gen.kubebuilder.io/version: v0.6.1 + name: clusters.anywhere.eks.amazonaws.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /convert + conversionReviewVersions: + - v1 + - v1beta1 + group: anywhere.eks.amazonaws.com + names: + kind: Cluster + listKind: ClusterList + plural: clusters + singular: cluster + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Cluster is the Schema for the clusters API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterSpec defines the desired state of Cluster + properties: + clusterNetwork: + properties: + cni: + description: CNI specifies the CNI plugin to be installed in the + cluster + type: string + pods: + description: Comma-separated list of CIDR blocks to use for pod + and service subnets. Defaults to 192.168.0.0/16 for pod subnet. + properties: + cidrBlocks: + items: + type: string + type: array + type: object + services: + properties: + cidrBlocks: + items: + type: string + type: array + type: object + type: object + controlPlaneConfiguration: + properties: + count: + description: Count defines the number of desired control plane + nodes. Defaults to 1. + type: integer + endpoint: + description: Endpoint defines the host ip and port to use for + the control plane. + properties: + host: + description: Host defines the ip that you want to use to connect + to the control plane + type: string + required: + - host + type: object + machineGroupRef: + description: MachineGroupRef defines the machine group configuration + for the control plane. + properties: + kind: + type: string + name: + type: string + type: object + type: object + datacenterRef: + properties: + kind: + type: string + name: + type: string + type: object + externalEtcdConfiguration: + description: ExternalEtcdConfiguration defines the configuration options + for using unstacked etcd topology + properties: + count: + type: integer + type: object + gitOpsRef: + properties: + kind: + type: string + name: + type: string + type: object + identityProviderRefs: + items: + properties: + kind: + type: string + name: + type: string + type: object + type: array + kubernetesVersion: + type: string + overrideClusterSpecFile: + type: string + proxyConfiguration: + properties: + httpProxy: + type: string + httpsProxy: + type: string + noProxy: + items: + type: string + type: array + type: object + workerNodeGroupConfigurations: + items: + properties: + count: + description: Count defines the number of desired worker nodes. + Defaults to 1. + type: integer + machineGroupRef: + description: MachineGroupRef defines the machine group configuration + for the worker nodes. + properties: + kind: + type: string + name: + type: string + type: object + type: object + type: array + type: object + status: + description: ClusterStatus defines the observed state of Cluster + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: dockerdatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: DockerDatacenterConfig + listKind: DockerDatacenterConfigList + plural: dockerdatacenterconfigs + singular: dockerdatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DockerDatacenterConfig is the Schema for the DockerDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DockerDatacenterConfigSpec defines the desired state of DockerDatacenterConfig + type: object + status: + description: DockerDatacenterConfigStatus defines the observed state of + DockerDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: gitopsconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: GitOpsConfig + listKind: GitOpsConfigList + plural: gitopsconfigs + singular: gitopsconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GitOps defines the configurations of GitOps Toolkit and Git + repository it links to. + properties: + flux: + description: Flux defines the Git repository options for Flux v2 + properties: + github: + description: github is the name of the Git Provider to host the + Git repo. + properties: + branch: + description: Git branch. Defaults to main. + type: string + clusterConfigPath: + description: ClusterConfigPath relative to the repository + root, when specified the cluster sync will be scoped to + this path. + type: string + fluxSystemNamespace: + description: FluxSystemNamespace scope for this operation. + Defaults to flux-system. + type: string + owner: + description: Owner is the user or organization name of the + Git provider. + type: string + personal: + description: if true, the owner is assumed to be a Git user; + otherwise an org. + type: boolean + repository: + description: Repository name. + type: string + required: + - owner + - repository + type: object + type: object + type: object + status: + description: GitOpsConfigStatus defines the observed state of GitOpsConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: oidcconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: OIDCConfig + listKind: OIDCConfigList + plural: oidcconfigs + singular: oidcconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OIDCConfig is the Schema for the oidcconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OIDCConfigSpec defines the desired state of OIDCConfig + properties: + clientId: + description: ClientId defines the client ID for the OpenID Connect + client + type: string + groupsClaim: + description: GroupsClaim defines the name of a custom OpenID Connect + claim for specifying user groups + type: string + groupsPrefix: + description: GroupsPrefix defines a string to be prefixed to all groups + to prevent conflicts with other authentication strategies + type: string + issuerUrl: + description: IssuerUrl defines the URL of the OpenID issuer, only + HTTPS scheme will be accepted + type: string + requiredClaims: + description: RequiredClaims defines a key=value pair that describes + a required claim in the ID Token + items: + properties: + claim: + type: string + value: + type: string + type: object + type: array + usernameClaim: + description: UsernameClaim defines the OpenID claim to use as the + user name. Note that claims other than the default ('sub') is not + guaranteed to be unique and immutable + type: string + usernamePrefix: + description: UsernamePrefix defines a string to prefixed to all usernames. + If not provided, username claims other than 'email' are prefixed + by the issuer URL to avoid clashes. To skip any prefixing, provide + the value '-'. + type: string + type: object + status: + description: OIDCConfigStatus defines the observed state of OIDCConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: vspheredatacenterconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: VSphereDatacenterConfig + listKind: VSphereDatacenterConfigList + plural: vspheredatacenterconfigs + singular: vspheredatacenterconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: VSphereDatacenterConfig is the Schema for the VSphereDatacenterConfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VSphereDatacenterConfigSpec defines the desired state of + VSphereDatacenterConfig + properties: + datacenter: + type: string + insecure: + type: boolean + network: + type: string + server: + type: string + thumbprint: + type: string + required: + - datacenter + - insecure + - network + - server + - thumbprint + type: object + status: + description: VSphereDatacenterConfigStatus defines the observed state + of VSphereDatacenterConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.1 + creationTimestamp: null + name: vspheremachineconfigs.anywhere.eks.amazonaws.com +spec: + group: anywhere.eks.amazonaws.com + names: + kind: VSphereMachineConfig + listKind: VSphereMachineConfigList + plural: vspheremachineconfigs + singular: vspheremachineconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: VSphereMachineConfig is the Schema for the vspheremachineconfigs + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VSphereMachineConfigSpec defines the desired state of VSphereMachineConfig + properties: + datastore: + type: string + diskGiB: + type: integer + folder: + type: string + memoryMiB: + type: integer + numCPUs: + type: integer + osFamily: + type: string + resourcePool: + type: string + storagePolicyName: + type: string + template: + type: string + users: + items: + description: UserConfiguration defines the configuration of the + user to be added to the VSphere VM + properties: + name: + type: string + sshAuthorizedKeys: + items: + type: string + type: array + required: + - name + - sshAuthorizedKeys + type: object + type: array + required: + - datastore + - folder + - memoryMiB + - numCPUs + - osFamily + - resourcePool + type: object + status: + description: VSphereMachineConfigStatus defines the observed state of + VSphereMachineConfig + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: eksa-controller-manager + namespace: eksa-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: eksa-leader-election-role + namespace: eksa-system +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: eksa-manager-role +rules: +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles + - clusters + - dockerdatacenterconfigs + - vspheredatacenterconfigs + - vspheremachineconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles/finalizers + - clusters/finalizers + - dockerdatacenterconfigs/finalizers + - vspheredatacenterconfigs/finalizers + - vspheremachineconfigs/finalizers + verbs: + - update +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles/status + - clusters/status + - dockerdatacenterconfigs/status + - vspheredatacenterconfigs/status + - vspheremachineconfigs/status + verbs: + - get + - patch + - update +- apiGroups: + - cluster.x-k8s.io + resources: + - clusters + - clusters/status + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - controlplane.cluster.x-k8s.io + resources: + - '*' + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinedeployments/status + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - bootstrap.cluster.x-k8s.io + resources: + - kubeadmconfigtemplates + - kubeadmconfigtemplates/status + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - addons.cluster.x-k8s.io + resources: + - clusterresourcesets + - clusterresourcesets/status + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - vsphereclusters + - vsphereclusters/status + - vspheremachinetemplates + - vspheremachinetemplates/status + - dockerclusters + - dockerclusters/status + - dockermachinetemplates + - dockermachinetemplates/status + verbs: + - get + - list + - patch + - update + - watch + - create +- apiGroups: + - etcdcluster.cluster.x-k8s.io + resources: + - etcdadmclusters + - etcdadmclusters/status + verbs: + - get + - list + - watch + - patch + - update +- apiGroups: + - "" + resources: + - secrets + - secrets/status + - configmaps + - configmaps/status + verbs: + - get + - list + - patch + - update + - watch + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: eksa-proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: eksa-leader-election-rolebinding + namespace: eksa-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: eksa-leader-election-role +subjects: +- kind: ServiceAccount + name: eksa-controller-manager + namespace: eksa-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: eksa-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: eksa-manager-role +subjects: +- kind: ServiceAccount + name: eksa-controller-manager + namespace: eksa-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: eksa-proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: eksa-proxy-role +subjects: +- kind: ServiceAccount + name: eksa-controller-manager + namespace: eksa-system +--- +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + name: eksa-controller-manager-metrics-service + namespace: eksa-system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager +--- +apiVersion: v1 +kind: Service +metadata: + name: eksa-webhook-service + namespace: eksa-system +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: eksa-controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + control-plane: eksa-controller-manager + name: eksa-controller-manager + namespace: eksa-system +spec: + replicas: 1 + selector: + matchLabels: + control-plane: eksa-controller-manager + template: + metadata: + labels: + control-plane: eksa-controller-manager + spec: + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + image: public.ecr.aws/l0g8r8j6/eks-anywhere-cluster-controller:aebda61a1f141b2857b3f4375e39d4590c40ada8-05d36a07f78af1c16d04dbbaba22013c64e25bd0 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: healthz + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + - containerPort: 8081 + name: healthz + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=10 + image: public.ecr.aws/l0g8r8j6/brancz/kube-rbac-proxy:v0.8.0-25df7d96779e2a305a22c6e3f9425c3465a77244 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + securityContext: + fsGroup: 1000 + serviceAccountName: eksa-controller-manager + terminationGracePeriodSeconds: 10 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: eksa-serving-cert + namespace: eksa-system +spec: + dnsNames: + - eksa-webhook-service.eksa-system.svc + - eksa-webhook-service.eksa-system.svc.cluster.local + issuerRef: + kind: Issuer + name: eksa-selfsigned-issuer + secretName: webhook-server-cert +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: eksa-selfsigned-issuer + namespace: eksa-system +spec: + selfSigned: {} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + annotations: + cert-manager.io/inject-ca-from: eksa-system/eksa-serving-cert + name: eksa-validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-cluster + failurePolicy: Fail + name: validation.cluster.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - clusters + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-gitopsconfig + failurePolicy: Fail + name: validation.gitopsconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - gitopsconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-oidcconfig + failurePolicy: Fail + name: validation.oidcconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - oidcconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-vspheredatacenterconfig + failurePolicy: Fail + name: validation.vspheredatacenterconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - vspheredatacenterconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: eksa-webhook-service + namespace: eksa-system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-vspheremachineconfig + failurePolicy: Fail + name: validation.vspheremachineconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - vspheremachineconfigs + sideEffects: None diff --git a/config/prod/kustomization.yaml b/config/prod/kustomization.yaml new file mode 100644 index 000000000000..1ea51fea6a40 --- /dev/null +++ b/config/prod/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../default + +images: +- name: controller + newName: public.ecr.aws/l0g8r8j6/eks-anywhere-cluster-controller + newTag: aebda61a1f141b2857b3f4375e39d4590c40ada8-05d36a07f78af1c16d04dbbaba22013c64e25bd0 +- name: gcr.io/kubebuilder/kube-rbac-proxy + newName: public.ecr.aws/l0g8r8j6/brancz/kube-rbac-proxy + newTag: v0.8.0-25df7d96779e2a305a22c6e3f9425c3465a77244 diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml new file mode 100644 index 000000000000..80e1857c594f --- /dev/null +++ b/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 000000000000..ec7acc0a1b79 --- /dev/null +++ b/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml new file mode 100644 index 000000000000..6cf656be1491 --- /dev/null +++ b/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml new file mode 100644 index 000000000000..c6c7daff5dd4 --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- role.yaml +- role_binding.yaml +- service_account.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +- auth_proxy_service.yaml +- auth_proxy_role.yaml +- auth_proxy_role_binding.yaml + +patchesJson6902: +- target: + group: rbac.authorization.k8s.io + version: v1 + kind: ClusterRole + name: manager-role + path: manager_extraroles_patch.yaml diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml new file mode 100644 index 000000000000..4190ec8059e2 --- /dev/null +++ b/config/rbac/leader_election_role.yaml @@ -0,0 +1,37 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 000000000000..1d1321ed4f02 --- /dev/null +++ b/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/manager_extraroles_patch.yaml b/config/rbac/manager_extraroles_patch.yaml new file mode 100644 index 000000000000..1bf1e02b0bfe --- /dev/null +++ b/config/rbac/manager_extraroles_patch.yaml @@ -0,0 +1,121 @@ +- op: add + path: /rules/- + value: + apiGroups: + - cluster.x-k8s.io + resources: + - clusters + - clusters/status + verbs: + - get + - list + - patch + - update + - watch +- op: add + path: /rules/- + value: + apiGroups: + - controlplane.cluster.x-k8s.io + resources: + - '*' + verbs: + - get + - list + - patch + - update + - watch +- op: add + path: /rules/- + value: + apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinedeployments/status + verbs: + - get + - list + - patch + - update + - watch +- op: add + path: /rules/- + value: + apiGroups: + - bootstrap.cluster.x-k8s.io + resources: + - kubeadmconfigtemplates + - kubeadmconfigtemplates/status + verbs: + - get + - list + - patch + - update + - watch +- op: add + path: /rules/- + value: + apiGroups: + - addons.cluster.x-k8s.io + resources: + - clusterresourcesets + - clusterresourcesets/status + verbs: + - get + - list + - patch + - update + - watch +- op: add + path: /rules/- + value: + apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - vsphereclusters + - vsphereclusters/status + - vspheremachinetemplates + - vspheremachinetemplates/status + - dockerclusters + - dockerclusters/status + - dockermachinetemplates + - dockermachinetemplates/status + verbs: + - get + - list + - patch + - update + - watch + - create +- op: add + path: /rules/- + value: + apiGroups: + - etcdcluster.cluster.x-k8s.io + resources: + - etcdadmclusters + - etcdadmclusters/status + verbs: + - get + - list + - watch + - patch + - update +- op: add + path: /rules/- + value: + apiGroups: + - "" + resources: + - secrets + - secrets/status + - configmaps + - configmaps/status + verbs: + - get + - list + - patch + - update + - watch + - create \ No newline at end of file diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 000000000000..bff33e158b60 --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,46 @@ + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles + - clusters + - dockerdatacenterconfigs + - vspheredatacenterconfigs + - vspheremachineconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles/finalizers + - clusters/finalizers + - dockerdatacenterconfigs/finalizers + - vspheredatacenterconfigs/finalizers + - vspheremachineconfigs/finalizers + verbs: + - update +- apiGroups: + - anywhere.eks.amazonaws.com + resources: + - bundles/status + - clusters/status + - dockerdatacenterconfigs/status + - vspheredatacenterconfigs/status + - vspheremachineconfigs/status + verbs: + - get + - patch + - update diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml new file mode 100644 index 000000000000..2070ede4462f --- /dev/null +++ b/config/rbac/role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml new file mode 100644 index 000000000000..7cd6025bfc4a --- /dev/null +++ b/config/rbac/service_account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: controller-manager + namespace: system diff --git a/config/tilt/kustomization.yaml b/config/tilt/kustomization.yaml new file mode 100644 index 000000000000..71f2d86a5564 --- /dev/null +++ b/config/tilt/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../default + +images: +- name: controller + newName: cluster-controller + newTag: latest diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml new file mode 100644 index 000000000000..6a64e975aabf --- /dev/null +++ b/config/webhook/kustomization.yaml @@ -0,0 +1,9 @@ +resources: +- manifests.yaml +- service.yaml + +configurations: +- kustomizeconfig.yaml + +patchesStrategicMerge: + - service_selector_patch.yaml diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml new file mode 100644 index 000000000000..25e21e3c963f --- /dev/null +++ b/config/webhook/kustomizeconfig.yaml @@ -0,0 +1,25 @@ +# the following config is for teaching kustomize where to look at when substituting vars. +# It requires kustomize v2.1.0 or newer to work properly. +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + - kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + +namespace: +- kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true +- kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true + +varReference: +- path: metadata/annotations diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml new file mode 100644 index 000000000000..d7462e5f9f2c --- /dev/null +++ b/config/webhook/manifests.yaml @@ -0,0 +1,113 @@ + +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-cluster + failurePolicy: Fail + name: validation.cluster.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - clusters + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-gitopsconfig + failurePolicy: Fail + name: validation.gitopsconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - gitopsconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-oidcconfig + failurePolicy: Fail + name: validation.oidcconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - oidcconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-vspheredatacenterconfig + failurePolicy: Fail + name: validation.vspheredatacenterconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - vspheredatacenterconfigs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-anywhere-eks-amazonaws-com-v1alpha1-vspheremachineconfig + failurePolicy: Fail + name: validation.vspheremachineconfig.anywhere.amazonaws.com + rules: + - apiGroups: + - anywhere.eks.amazonaws.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - vspheremachineconfigs + sideEffects: None diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml new file mode 100644 index 000000000000..31e0f8295919 --- /dev/null +++ b/config/webhook/service.yaml @@ -0,0 +1,12 @@ + +apiVersion: v1 +kind: Service +metadata: + name: webhook-service + namespace: system +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: controller-manager diff --git a/config/webhook/service_selector_patch.yaml b/config/webhook/service_selector_patch.yaml new file mode 100644 index 000000000000..b0979bba2b15 --- /dev/null +++ b/config/webhook/service_selector_patch.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Service +metadata: + name: webhook-service + namespace: system +spec: + selector: + control-plane: eksa-controller-manager diff --git a/controllers/.gitignore b/controllers/.gitignore new file mode 100644 index 000000000000..cc61b7546693 --- /dev/null +++ b/controllers/.gitignore @@ -0,0 +1,3 @@ +tilt_modules +tilt-settings.json +bin/* diff --git a/controllers/README.md b/controllers/README.md new file mode 100644 index 000000000000..b91a5a9151ba --- /dev/null +++ b/controllers/README.md @@ -0,0 +1,43 @@ +# eksa controller + +## Install kubebuilder +```sh +make hack/tools/bin/kubebuilder +``` + +## Create new webhooks with kubebuilder +Since we use a non standard (according to kubebuilder) repo structure, kubebuilder commands won't work. For this purpose, we have a script that temporally changes our folder structure to one that kubebuilder understands and restores the original one after executing the kubebuilder command. + +Example +```sh +./hack/kubebuilder.sh create webhook --group anywhere --version v1alpha1 --programmatic-validation --kind WhateverKind +``` + +## Run controller from local repo source with tilt +When using tilt, any changes to the yaml files in `config` or `go` code in `pkg/api` and `controllers` will automatically rebuild and update your resources in the cluster. + +Note: the folder `config/tilt` is ignored. This folder is supposed to contain tilt exclusive kustomize files and is not intended for manual changes (in order to keep the tilt environment as close as possible to the real one, its patches should be minimum). If you make changes to this folder you will need to restart tilt. +### Setup tilt config +Create a `tilt-settings.json` file in this folder +```json +{ + "default_registry": "public.ecr.aws/xxxxxx", + "allowed_contexts": ["yyyyyy@zzzzz"] +} +``` +* `default_registry`: your own registry where you want to push the controller images built by tilt. If using ECR, you will need to create the repository in advance (repo name is `cluster-controller`, same as the var `IMG` in the Tiltfile). You will need to be authenticated and have permissions to push images. Example for ECR: +```sh +aws ecr-public get-login-password --region ${REGION} | docker login --username AWS --password-stdin public.ecr.aws/${REGISTRY_ALIAS} +``` +* `allowed_contexts`: list here the kube context of your cluster. By default, tilt won't interact with "non local" clusters and any eksa cluster, including the docker ones, are recognized as non local +### Point tilt to your cluster +Tilt uses whatever cluster `kubectl` is configured to use. The easiest option here is to set `KUBECONFIG` envar pointing to your eksa kubeconfig file: + +```sh +export KUBECONFIG=${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig +``` + +### Start tilt +```sh +make run-controller +``` \ No newline at end of file diff --git a/controllers/Tiltfile b/controllers/Tiltfile new file mode 100644 index 000000000000..3820df4ec57e --- /dev/null +++ b/controllers/Tiltfile @@ -0,0 +1,49 @@ +# -*- mode: Python -*- +settings = read_json('tilt-settings.json', default={}) + +load('ext://restart_process', 'docker_build_with_restart') +allow_k8s_contexts(settings.get("allowed_contexts")) +default_registry(settings.get('default_registry')) + +IMG = 'cluster-controller:latest' +PROJECT_ROOT='./../' +CONTROLLERS_FOLDER = PROJECT_ROOT + 'controllers' +CONTROLLERS_BIN_FOLDER = CONTROLLERS_FOLDER + '/bin' +BIN_FOLDER = PROJECT_ROOT + 'bin' +API_FOLDER = PROJECT_ROOT + 'pkg/api' +CONFIG_FOLDER = PROJECT_ROOT + 'config' +KUSTOMIZE_TILT_FOLDER = CONFIG_FOLDER + '/tilt' +KUSTOMIZE_BIN = os.path.abspath(PROJECT_ROOT + 'hack/tools/bin/kustomize') +watch_settings(ignore=[KUSTOMIZE_TILT_FOLDER]) #ignore kustomize tilt folder to avoid infinite loop + +def yaml(): + local('cd ' + KUSTOMIZE_TILT_FOLDER + ' && ' + KUSTOMIZE_BIN + ' edit set image controller=' + IMG) + return kustomize(KUSTOMIZE_TILT_FOLDER) + +def binary(): + return 'CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -o ./bin/manager ' + CONTROLLERS_FOLDER + '/main.go' + +local_resource( + 'eksa-controller-compile', + binary(), + deps=[CONTROLLERS_FOLDER, API_FOLDER], + ignore=[CONTROLLERS_BIN_FOLDER, API_FOLDER + '/*/zz_generated.deepcopy.go']) + +DOCKERFILE = '''FROM golang:alpine +WORKDIR / +COPY ./bin/manager / +CMD ["/manager"] +''' + +k8s_yaml(yaml()) + +docker_build_with_restart( + IMG, + '.', + dockerfile_contents=DOCKERFILE, + entrypoint='/manager', + only=['./bin/manager'], + live_update=[ + sync('./bin/manager', '/manager'), + ] +) \ No newline at end of file diff --git a/controllers/controllers/cluster_controller.go b/controllers/controllers/cluster_controller.go new file mode 100644 index 000000000000..681066381616 --- /dev/null +++ b/controllers/controllers/cluster_controller.go @@ -0,0 +1,121 @@ +package controllers + +import ( + "context" + "time" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + kerrors "k8s.io/apimachinery/pkg/util/errors" + "sigs.k8s.io/cluster-api/util/patch" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/source" + + "github.com/aws/eks-anywhere/controllers/controllers/resource" + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" +) + +// ClusterReconciler reconciles a Cluster object +type ClusterReconciler struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme + reconcilers []resource.Reconciler + resourceFetcher resource.ResourceFetcher +} + +func NewClusterReconciler(client client.Client, log logr.Logger, scheme *runtime.Scheme) *ClusterReconciler { + return &ClusterReconciler{ + Client: client, + Log: log, + Scheme: scheme, + reconcilers: []resource.Reconciler{ + resource.NewClusterReconciler( + resource.NewCapiResourceFetcher(client, log), + resource.NewCapiResourceUpdater(client, log), + time.Now, + log), + }, + resourceFetcher: resource.NewCapiResourceFetcher(client, log), + } +} + +//+kubebuilder:rbac:groups=anywhere.eks.amazonaws.com,resources=clusters;vspheredatacenterconfigs;vspheremachineconfigs;dockerdatacenterconfigs;bundles,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=anywhere.eks.amazonaws.com,resources=clusters/status;vspheredatacenterconfigs/status;vspheremachineconfigs/status;dockerdatacenterconfigs/status;bundles/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=anywhere.eks.amazonaws.com,resources=clusters/finalizers;vspheredatacenterconfigs/finalizers;vspheremachineconfigs/finalizers;dockerdatacenterconfigs/finalizers;bundles/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + _ = r.Log.WithValues("cluster", req.NamespacedName) + // Fetch the Cluster instance. + cluster, err := r.resourceFetcher.FetchCluster(ctx, req.NamespacedName) + if err != nil { + return ctrl.Result{}, err + } + // Initialize the patch helper + patchHelper, err := patch.NewHelper(cluster, r.Client) + if err != nil { + return ctrl.Result{}, err + } + + defer func() { + // Always attempt to patch the object and status after each reconciliation. + if err := patchHelper.Patch(ctx, cluster); err != nil { + reterr = kerrors.NewAggregate([]error{reterr, err}) + } + }() + + // Ignore deleted Clusters, this can happen when foregroundDeletion + // is enabled + if !cluster.DeletionTimestamp.IsZero() { + return ctrl.Result{}, nil + } + + // If the external object is paused, return without any further processing. + if cluster.IsReconcilePaused() { + r.Log.Info("eksa reconcilation is paused") + return ctrl.Result{}, nil + } + + // dry run + result, err := r.reconcile(ctx, req.NamespacedName, true) + if err != nil { + r.Log.Error(err, "Dry run failed to reconcile Cluster") + return result, err + } + // non dry run + result, err = r.reconcile(ctx, req.NamespacedName, false) + if err != nil { + r.Log.Error(err, "Failed to reconcile Cluster") + } + return result, err +} + +func (r *ClusterReconciler) reconcile(ctx context.Context, objectKey types.NamespacedName, dryRun bool) (ctrl.Result, error) { + r.Log.Info("Reconcile EKS-A Cluster", "dryRun", dryRun) + errs := []error{} + for _, phase := range r.reconcilers { + err := phase.Reconcile(ctx, objectKey, dryRun) + if err != nil { + errs = append(errs, err) + } + if len(errs) > 0 { + continue + } + } + return ctrl.Result{}, kerrors.NewAggregate(errs) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&anywherev1.Cluster{}). + Watches(&source.Kind{Type: &anywherev1.VSphereDatacenterConfig{}}, &handler.EnqueueRequestForObject{}). + Watches(&source.Kind{Type: &anywherev1.VSphereMachineConfig{}}, &handler.EnqueueRequestForObject{}). + Watches(&source.Kind{Type: &anywherev1.DockerDatacenterConfig{}}, &handler.EnqueueRequestForObject{}). + Complete(r) +} diff --git a/controllers/controllers/resource/fetcher.go b/controllers/controllers/resource/fetcher.go new file mode 100644 index 000000000000..4f2cc8bc8fe7 --- /dev/null +++ b/controllers/controllers/resource/fetcher.go @@ -0,0 +1,279 @@ +package resource + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" + vspherev3 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha3" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + kubeadmnv1alpha3 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3" + "sigs.k8s.io/controller-runtime/pkg/client" + + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/cluster" + releasev1alpha1 "github.com/aws/eks-anywhere/release/api/v1alpha1" +) + +type ResourceFetcher interface { + MachineDeployment(ctx context.Context, cs *anywherev1.Cluster) (*clusterv1.MachineDeployment, error) + VSphereMachineTemplate(ctx context.Context, cs *anywherev1.Cluster) (*vspherev3.VSphereMachineTemplate, error) + FetchObject(ctx context.Context, objectKey types.NamespacedName, obj client.Object) error + FetchObjectByName(ctx context.Context, name string, namespace string, obj client.Object) error + Fetch(ctx context.Context, name string, namespace string, kind string, apiVersion string) (*unstructured.Unstructured, error) + FetchCluster(ctx context.Context, objectKey types.NamespacedName) (*anywherev1.Cluster, error) + ExistingVSphereDatacenterConfig(ctx context.Context, cs *anywherev1.Cluster) (*anywherev1.VSphereDatacenterConfig, error) + ExistingVSphereWorkerMachineConfig(ctx context.Context, cs *anywherev1.Cluster) (*anywherev1.VSphereMachineConfig, error) + ControlPlane(ctx context.Context, cs *anywherev1.Cluster) (*kubeadmnv1alpha3.KubeadmControlPlane, error) + FetchAppliedSpec(ctx context.Context, cs *anywherev1.Cluster) (*cluster.Spec, error) +} + +type capiResourceFetcher struct { + client client.Reader + log logr.Logger +} + +func NewCapiResourceFetcher(client client.Reader, Log logr.Logger) *capiResourceFetcher { + return &capiResourceFetcher{ + client: client, + log: Log, + } +} + +func (r *capiResourceFetcher) FetchObjectByName(ctx context.Context, name string, namespace string, obj client.Object) error { + err := r.FetchObject(ctx, types.NamespacedName{Namespace: namespace, Name: name}, obj) + if err != nil { + return err + } + return nil +} + +func (r *capiResourceFetcher) FetchObject(ctx context.Context, objectKey types.NamespacedName, obj client.Object) error { + err := r.client.Get(ctx, objectKey, obj) + if err != nil { + return err + } + return nil +} + +func (r *capiResourceFetcher) fetchClusterKind(ctx context.Context, objectKey types.NamespacedName) (string, error) { + supportedKinds := []string{anywherev1.ClusterKind, anywherev1.VSphereDatacenterKind, anywherev1.DockerDatacenterKind, anywherev1.VSphereMachineConfigKind} + for _, kind := range supportedKinds { + obj := &unstructured.Unstructured{} + obj.SetKind(kind) + obj.SetAPIVersion(anywherev1.GroupVersion.String()) + err := r.FetchObject(ctx, objectKey, obj) + if err != nil && !apierrors.IsNotFound(err) { + return "", err + } + if err == nil { + return obj.GetKind(), nil + } + } + return "", fmt.Errorf("no object found for %v", objectKey) +} + +func (r *capiResourceFetcher) FetchCluster(ctx context.Context, objectKey types.NamespacedName) (*anywherev1.Cluster, error) { + r.log.Info("looking up cluster", "objectKey", objectKey) + kind, err := r.fetchClusterKind(ctx, objectKey) + if err != nil { + return nil, err + } + switch kind { + case anywherev1.ClusterKind: + cluster := &anywherev1.Cluster{} + if err := r.FetchObject(ctx, objectKey, cluster); err != nil { + return nil, err + } + return cluster, nil + default: + return r.fetchClusterForRef(ctx, objectKey, kind) + } +} + +func (r *capiResourceFetcher) clusterByName(ctx context.Context, namespace, name string) (*clusterv1.Cluster, error) { + cluster := &clusterv1.Cluster{} + key := client.ObjectKey{ + Namespace: namespace, + Name: name, + } + if err := r.FetchObject(ctx, key, cluster); err != nil { + return nil, err + } + return cluster, nil +} + +func (r *capiResourceFetcher) fetchClusterForRef(ctx context.Context, refId types.NamespacedName, kind string) (*anywherev1.Cluster, error) { + clusters := &anywherev1.ClusterList{} + o := &client.ListOptions{Raw: &metav1.ListOptions{TypeMeta: metav1.TypeMeta{Kind: anywherev1.ClusterKind, APIVersion: anywherev1.GroupVersion.String()}}, Namespace: refId.Namespace} + err := r.client.List(ctx, clusters, o) + if err != nil { + return nil, err + } + for _, c := range clusters.Items { + if kind == anywherev1.VSphereDatacenterKind || kind == anywherev1.DockerDatacenterKind { + if c.Spec.DatacenterRef.Name == refId.Name { + if _, err := r.clusterByName(ctx, refId.Namespace, c.Name); err == nil { // further validates a capi cluster exists + return &c, nil + } + } + } + if kind == anywherev1.VSphereMachineConfigKind { + for _, machineRef := range c.Spec.WorkerNodeGroupConfigurations { + if machineRef.MachineGroupRef != nil && machineRef.MachineGroupRef.Name == refId.Name { + if _, err := r.clusterByName(ctx, refId.Namespace, c.Name); err == nil { // further validates a capi cluster exists + return &c, nil + } + } + } + if c.Spec.ControlPlaneConfiguration.MachineGroupRef != nil && c.Spec.ControlPlaneConfiguration.MachineGroupRef.Name == refId.Name { + if _, err := r.clusterByName(ctx, refId.Namespace, c.Name); err == nil { // further validates a capi cluster exists + return &c, nil + } + } + } + } + return nil, fmt.Errorf("eksa cluster not found for datacenterRef %v", refId) +} + +func (r *capiResourceFetcher) machineDeployments(ctx context.Context, c *anywherev1.Cluster) ([]*clusterv1.MachineDeployment, error) { + machineDeployments := &clusterv1.MachineDeploymentList{} + req, err := labels.NewRequirement(clusterv1.ClusterLabelName, selection.Equals, []string{c.Name}) + if err != nil { + return nil, err + } + o := &client.ListOptions{LabelSelector: labels.NewSelector().Add(*req), Namespace: c.Namespace} + err = r.client.List(ctx, machineDeployments, o) + if err != nil { + return nil, err + } + deployments := make([]*clusterv1.MachineDeployment, 0, len(machineDeployments.Items)) + for _, md := range machineDeployments.Items { + deployments = append(deployments, &md) + } + return deployments, nil +} + +func (r *capiResourceFetcher) MachineDeployment(ctx context.Context, cs *anywherev1.Cluster) (*clusterv1.MachineDeployment, error) { + deployments, err := r.machineDeployments(ctx, cs) + if err != nil { + return nil, err + } + + if len(deployments) < 1 { + return nil, fmt.Errorf("no machine deployments found for cluster %s", cs.Name) + } + + return deployments[0], nil +} + +func (r *capiResourceFetcher) Fetch(ctx context.Context, name string, namespace string, kind string, apiVersion string) (*unstructured.Unstructured, error) { + us := &unstructured.Unstructured{} + us.SetKind(kind) + us.SetAPIVersion(apiVersion) + key := client.ObjectKey{Name: name, Namespace: namespace} + if err := r.client.Get(ctx, key, us); err != nil { + return nil, err + } + return us, nil +} + +func (r *capiResourceFetcher) VSphereMachineTemplate(ctx context.Context, cs *anywherev1.Cluster) (*vspherev3.VSphereMachineTemplate, error) { + md, err := r.MachineDeployment(ctx, cs) + if err != nil { + return nil, err + } + vsphereMachineTemplate := &vspherev3.VSphereMachineTemplate{} + err = r.FetchObjectByName(ctx, md.Spec.Template.Spec.InfrastructureRef.Name, md.GetNamespace(), vsphereMachineTemplate) + if err != nil { + return nil, err + } + return vsphereMachineTemplate, nil +} + +func (r *capiResourceFetcher) clusterBundle(ctx context.Context, cs *anywherev1.Cluster) (*releasev1alpha1.Bundles, error) { + clusterBundle := &releasev1alpha1.Bundles{} + err := r.FetchObjectByName(ctx, cs.Name, cs.Namespace, clusterBundle) + if err != nil { + return nil, err + } + return clusterBundle, nil +} + +func (r *capiResourceFetcher) ControlPlane(ctx context.Context, cs *anywherev1.Cluster) (*kubeadmnv1alpha3.KubeadmControlPlane, error) { + // Fetch capi cluster + capiCluster := &clusterv1.Cluster{} + err := r.FetchObjectByName(ctx, cs.Name, cs.Namespace, capiCluster) + if err != nil { + return nil, err + } + cpRef := capiCluster.Spec.ControlPlaneRef + cp := &kubeadmnv1alpha3.KubeadmControlPlane{} + err = r.FetchObjectByName(ctx, cpRef.Name, cpRef.Namespace, cp) + if err != nil { + return nil, err + } + return cp, nil +} + +func (r *capiResourceFetcher) FetchAppliedSpec(ctx context.Context, cs *anywherev1.Cluster) (*cluster.Spec, error) { + bundle, err := r.clusterBundle(ctx, cs) + if err != nil { + return nil, err + } + spec, err := cluster.BuildSpecFromBundles(cs, bundle) + if err != nil { + return nil, err + } + return spec, nil +} + +func (r *capiResourceFetcher) ExistingVSphereDatacenterConfig(ctx context.Context, cs *anywherev1.Cluster) (*anywherev1.VSphereDatacenterConfig, error) { + vsMachineTemplate, err := r.VSphereMachineTemplate(ctx, cs) + if err != nil { + return nil, err + } + return MapMachineTemplateToVSphereDatacenterConfigSpec(vsMachineTemplate) +} + +func (r *capiResourceFetcher) ExistingVSphereWorkerMachineConfig(ctx context.Context, cs *anywherev1.Cluster) (*anywherev1.VSphereMachineConfig, error) { + vsMachineTemplate, err := r.VSphereMachineTemplate(ctx, cs) + if err != nil { + return nil, err + } + return MapMachineTemplateToVSphereWorkerMachineConfigSpec(vsMachineTemplate) +} + +func MapMachineTemplateToVSphereDatacenterConfigSpec(vsMachineTemplate *vspherev3.VSphereMachineTemplate) (*anywherev1.VSphereDatacenterConfig, error) { + vsSpec := &anywherev1.VSphereDatacenterConfig{} + vsSpec.Spec.Thumbprint = vsMachineTemplate.Spec.Template.Spec.Thumbprint + vsSpec.Spec.Server = vsMachineTemplate.Spec.Template.Spec.Server + vsSpec.Spec.Datacenter = vsMachineTemplate.Spec.Template.Spec.Datacenter + + if len(vsMachineTemplate.Spec.Template.Spec.Network.Devices) == 0 { + return nil, fmt.Errorf("networkName under devices not found on object %s", vsMachineTemplate.Kind) + } + vsSpec.Spec.Network = vsMachineTemplate.Spec.Template.Spec.Network.Devices[0].NetworkName + + return vsSpec, nil +} + +func MapMachineTemplateToVSphereWorkerMachineConfigSpec(vsMachineTemplate *vspherev3.VSphereMachineTemplate) (*anywherev1.VSphereMachineConfig, error) { + vsSpec := &anywherev1.VSphereMachineConfig{} + vsSpec.Spec.MemoryMiB = int(vsMachineTemplate.Spec.Template.Spec.MemoryMiB) + vsSpec.Spec.DiskGiB = int(vsMachineTemplate.Spec.Template.Spec.DiskGiB) + vsSpec.Spec.NumCPUs = int(vsMachineTemplate.Spec.Template.Spec.NumCPUs) + vsSpec.Spec.Template = vsMachineTemplate.Spec.Template.Spec.Template + vsSpec.Spec.ResourcePool = vsMachineTemplate.Spec.Template.Spec.ResourcePool + vsSpec.Spec.Datastore = vsMachineTemplate.Spec.Template.Spec.Datastore + vsSpec.Spec.Folder = vsMachineTemplate.Spec.Template.Spec.Folder + vsSpec.Spec.StoragePolicyName = vsMachineTemplate.Spec.Template.Spec.StoragePolicyName + + return vsSpec, nil +} diff --git a/controllers/controllers/resource/fetcher_test.go b/controllers/controllers/resource/fetcher_test.go new file mode 100644 index 000000000000..c8eb682edb63 --- /dev/null +++ b/controllers/controllers/resource/fetcher_test.go @@ -0,0 +1,339 @@ +package resource_test + +import ( + "context" + "reflect" + "testing" + + "k8s.io/api/node/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + vspherev3 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha3" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/aws/eks-anywhere/controllers/controllers/resource" + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" +) + +func TestMapMachineTemplateToVSphereDatacenterConfigSpec(t *testing.T) { + type args struct { + vsMachineTemplate *vspherev3.VSphereMachineTemplate + } + tests := []struct { + name string + args args + want *anywherev1.VSphereDatacenterConfig + wantErr bool + }{ + { + name: "All path are available", + wantErr: false, + args: args{ + vsMachineTemplate: &vspherev3.VSphereMachineTemplate{ + Spec: vspherev3.VSphereMachineTemplateSpec{ + Template: vspherev3.VSphereMachineTemplateResource{ + Spec: vspherev3.VSphereMachineSpec{ + VirtualMachineCloneSpec: vspherev3.VirtualMachineCloneSpec{ + MemoryMiB: int64(64), + DiskGiB: int32(100), + NumCPUs: int32(3), + Template: "templateA", + Thumbprint: "aaa", + Server: "ssss", + ResourcePool: "poolA", + Datacenter: "daaa", + Datastore: "ds-aaa", + Folder: "folder/A", + Network: vspherev3.NetworkSpec{ + Devices: []vspherev3.NetworkDeviceSpec{ + { + NetworkName: "networkA", + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: &anywherev1.VSphereDatacenterConfig{ + Spec: anywherev1.VSphereDatacenterConfigSpec{ + Thumbprint: "aaa", + Server: "ssss", + Datacenter: "daaa", + Network: "networkA", + }, + }, + }, + { + name: "NetworkName missing, throw error", + wantErr: true, + args: args{ + vsMachineTemplate: &vspherev3.VSphereMachineTemplate{ + Spec: vspherev3.VSphereMachineTemplateSpec{ + Template: vspherev3.VSphereMachineTemplateResource{ + Spec: vspherev3.VSphereMachineSpec{ + VirtualMachineCloneSpec: vspherev3.VirtualMachineCloneSpec{ + MemoryMiB: int64(64), + DiskGiB: int32(100), + NumCPUs: int32(3), + Template: "templateA", + Thumbprint: "aaa", + Server: "ssss", + ResourcePool: "poolA", + Datacenter: "daaa", + Datastore: "ds-aaa", + Folder: "folder/A", + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := resource.MapMachineTemplateToVSphereDatacenterConfigSpec(tt.args.vsMachineTemplate) + if (err != nil) != tt.wantErr { + t.Errorf("MapMachineTemplateToVSphereDatacenterConfigSpec() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err == nil && !reflect.DeepEqual(got, tt.want) { + t.Errorf("MapMachineTemplateToVSphereDatacenterConfigSpec() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMapMachineTemplateToVSphereWorkerMachineConfigSpec(t *testing.T) { + type args struct { + vsMachineTemplate *vspherev3.VSphereMachineTemplate + } + tests := []struct { + name string + args args + want *anywherev1.VSphereMachineConfig + wantErr bool + }{ + { + name: "All path are available", + wantErr: false, + args: args{ + vsMachineTemplate: &vspherev3.VSphereMachineTemplate{ + Spec: vspherev3.VSphereMachineTemplateSpec{ + Template: vspherev3.VSphereMachineTemplateResource{ + Spec: vspherev3.VSphereMachineSpec{ + VirtualMachineCloneSpec: vspherev3.VirtualMachineCloneSpec{ + MemoryMiB: int64(64), + DiskGiB: int32(100), + NumCPUs: int32(3), + Template: "templateA", + Thumbprint: "aaa", + Server: "ssss", + ResourcePool: "poolA", + Datacenter: "daaa", + Datastore: "ds-aaa", + Folder: "folder/A", + Network: vspherev3.NetworkSpec{ + Devices: []vspherev3.NetworkDeviceSpec{ + { + NetworkName: "networkA", + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: &anywherev1.VSphereMachineConfig{ + Spec: anywherev1.VSphereMachineConfigSpec{ + MemoryMiB: 64, + DiskGiB: 100, + NumCPUs: 3, + Template: "templateA", + ResourcePool: "poolA", + Datastore: "ds-aaa", + Folder: "folder/A", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := resource.MapMachineTemplateToVSphereWorkerMachineConfigSpec(tt.args.vsMachineTemplate) + if (err != nil) != tt.wantErr { + t.Errorf("MapMachineTemplateToVSphereWorkerMachineConfigSpec() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err == nil && !reflect.DeepEqual(got, tt.want) { + t.Errorf("MapMachineTemplateToVSphereWorkerMachineConfigSpec() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCapiResourceFetcherFetchCluster(t *testing.T) { + type fields struct { + client client.Reader + } + type args struct { + objectKey types.NamespacedName + } + tests := []struct { + name string + fields fields + args args + want *anywherev1.Cluster + wantErr bool + }{ + { + name: "fetch cluster from VSphereDatacenterKind", + fields: fields{ + client: &stubbedReader{ + clusterName: "testCluster", + kind: anywherev1.VSphereDatacenterKind, + cluster: anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + DatacenterRef: anywherev1.Ref{ + Name: "testVSphereDatacenter", + Kind: anywherev1.VSphereDatacenterKind, + }, + }, + }, + }, + }, + args: args{ + objectKey: types.NamespacedName{Name: "testVSphereDatacenter", Namespace: "default"}, + }, + want: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + DatacenterRef: anywherev1.Ref{ + Name: "testVSphereDatacenter", + Kind: anywherev1.VSphereDatacenterKind, + }, + }, + }, + }, + { + name: "fetch cluster from DockerDatacenterKind", + fields: fields{ + client: &stubbedReader{ + clusterName: "testCluster", + kind: anywherev1.DockerDatacenterKind, + cluster: anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + DatacenterRef: anywherev1.Ref{ + Name: "testDockerDatacenter", + Kind: anywherev1.DockerDatacenterKind, + }, + }, + }, + }, + }, + args: args{ + objectKey: types.NamespacedName{Name: "testDockerDatacenter", Namespace: "default"}, + }, + want: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + DatacenterRef: anywherev1.Ref{ + Name: "testDockerDatacenter", + Kind: anywherev1.DockerDatacenterKind, + }, + }, + }, + }, + { + name: "fetch cluster from VSphereMachineConfigKind", + fields: fields{ + client: &stubbedReader{ + clusterName: "testCluster", + kind: anywherev1.VSphereMachineConfigKind, + cluster: anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + WorkerNodeGroupConfigurations: []anywherev1.WorkerNodeGroupConfiguration{ + { + MachineGroupRef: &anywherev1.Ref{ + Name: "testVSphereMachineConfig", + }, + }, + }, + }, + }, + }, + }, + args: args{ + objectKey: types.NamespacedName{Name: "testVSphereMachineConfig", Namespace: "default"}, + }, + want: &anywherev1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testCluster", + }, + Spec: anywherev1.ClusterSpec{ + WorkerNodeGroupConfigurations: []anywherev1.WorkerNodeGroupConfiguration{ + { + MachineGroupRef: &anywherev1.Ref{ + Name: "testVSphereMachineConfig", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := resource.NewCapiResourceFetcher(tt.fields.client, log.NullLogger{}) + got, err := r.FetchCluster(context.Background(), tt.args.objectKey) + if (err != nil) != tt.wantErr { + t.Errorf("FetchCluster() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FetchCluster() got = %v, want %v", got, tt.want) + } + }) + } +} + +type stubbedReader struct { + kind string + cluster anywherev1.Cluster + clusterName string +} + +func (s *stubbedReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if s.kind == obj.GetObjectKind().GroupVersionKind().Kind { + return nil + } + if key.Name == s.clusterName { + return nil + } + return errors.NewNotFound(v1alpha1.Resource("foo"), "kind not found") +} + +func (s *stubbedReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + clusterList := list.(*anywherev1.ClusterList) + clusterList.Items = []anywherev1.Cluster{s.cluster} + return nil +} diff --git a/controllers/controllers/resource/mocks/resource.go b/controllers/controllers/resource/mocks/resource.go new file mode 100644 index 000000000000..7966c3553aa5 --- /dev/null +++ b/controllers/controllers/resource/mocks/resource.go @@ -0,0 +1,285 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/aws/eks-anywhere/controllers/controllers/resource (interfaces: ResourceFetcher,ResourceUpdater) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + v1alpha1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + cluster "github.com/aws/eks-anywhere/pkg/cluster" + gomock "github.com/golang/mock/gomock" + unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + types "k8s.io/apimachinery/pkg/types" + v1alpha3 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha3" + v1alpha30 "sigs.k8s.io/cluster-api/api/v1alpha3" + v1alpha31 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3" + client "sigs.k8s.io/controller-runtime/pkg/client" +) + +// MockResourceFetcher is a mock of ResourceFetcher interface. +type MockResourceFetcher struct { + ctrl *gomock.Controller + recorder *MockResourceFetcherMockRecorder +} + +// MockResourceFetcherMockRecorder is the mock recorder for MockResourceFetcher. +type MockResourceFetcherMockRecorder struct { + mock *MockResourceFetcher +} + +// NewMockResourceFetcher creates a new mock instance. +func NewMockResourceFetcher(ctrl *gomock.Controller) *MockResourceFetcher { + mock := &MockResourceFetcher{ctrl: ctrl} + mock.recorder = &MockResourceFetcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockResourceFetcher) EXPECT() *MockResourceFetcherMockRecorder { + return m.recorder +} + +// ControlPlane mocks base method. +func (m *MockResourceFetcher) ControlPlane(arg0 context.Context, arg1 *v1alpha1.Cluster) (*v1alpha31.KubeadmControlPlane, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ControlPlane", arg0, arg1) + ret0, _ := ret[0].(*v1alpha31.KubeadmControlPlane) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ControlPlane indicates an expected call of ControlPlane. +func (mr *MockResourceFetcherMockRecorder) ControlPlane(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControlPlane", reflect.TypeOf((*MockResourceFetcher)(nil).ControlPlane), arg0, arg1) +} + +// ExistingVSphereDatacenterConfig mocks base method. +func (m *MockResourceFetcher) ExistingVSphereDatacenterConfig(arg0 context.Context, arg1 *v1alpha1.Cluster) (*v1alpha1.VSphereDatacenterConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistingVSphereDatacenterConfig", arg0, arg1) + ret0, _ := ret[0].(*v1alpha1.VSphereDatacenterConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExistingVSphereDatacenterConfig indicates an expected call of ExistingVSphereDatacenterConfig. +func (mr *MockResourceFetcherMockRecorder) ExistingVSphereDatacenterConfig(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistingVSphereDatacenterConfig", reflect.TypeOf((*MockResourceFetcher)(nil).ExistingVSphereDatacenterConfig), arg0, arg1) +} + +// ExistingVSphereWorkerMachineConfig mocks base method. +func (m *MockResourceFetcher) ExistingVSphereWorkerMachineConfig(arg0 context.Context, arg1 *v1alpha1.Cluster) (*v1alpha1.VSphereMachineConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistingVSphereWorkerMachineConfig", arg0, arg1) + ret0, _ := ret[0].(*v1alpha1.VSphereMachineConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExistingVSphereWorkerMachineConfig indicates an expected call of ExistingVSphereWorkerMachineConfig. +func (mr *MockResourceFetcherMockRecorder) ExistingVSphereWorkerMachineConfig(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistingVSphereWorkerMachineConfig", reflect.TypeOf((*MockResourceFetcher)(nil).ExistingVSphereWorkerMachineConfig), arg0, arg1) +} + +// Fetch mocks base method. +func (m *MockResourceFetcher) Fetch(arg0 context.Context, arg1, arg2, arg3, arg4 string) (*unstructured.Unstructured, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Fetch", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*unstructured.Unstructured) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Fetch indicates an expected call of Fetch. +func (mr *MockResourceFetcherMockRecorder) Fetch(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockResourceFetcher)(nil).Fetch), arg0, arg1, arg2, arg3, arg4) +} + +// FetchAppliedSpec mocks base method. +func (m *MockResourceFetcher) FetchAppliedSpec(arg0 context.Context, arg1 *v1alpha1.Cluster) (*cluster.Spec, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchAppliedSpec", arg0, arg1) + ret0, _ := ret[0].(*cluster.Spec) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchAppliedSpec indicates an expected call of FetchAppliedSpec. +func (mr *MockResourceFetcherMockRecorder) FetchAppliedSpec(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchAppliedSpec", reflect.TypeOf((*MockResourceFetcher)(nil).FetchAppliedSpec), arg0, arg1) +} + +// FetchCluster mocks base method. +func (m *MockResourceFetcher) FetchCluster(arg0 context.Context, arg1 types.NamespacedName) (*v1alpha1.Cluster, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchCluster", arg0, arg1) + ret0, _ := ret[0].(*v1alpha1.Cluster) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchCluster indicates an expected call of FetchCluster. +func (mr *MockResourceFetcherMockRecorder) FetchCluster(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCluster", reflect.TypeOf((*MockResourceFetcher)(nil).FetchCluster), arg0, arg1) +} + +// FetchObject mocks base method. +func (m *MockResourceFetcher) FetchObject(arg0 context.Context, arg1 types.NamespacedName, arg2 client.Object) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchObject", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// FetchObject indicates an expected call of FetchObject. +func (mr *MockResourceFetcherMockRecorder) FetchObject(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchObject", reflect.TypeOf((*MockResourceFetcher)(nil).FetchObject), arg0, arg1, arg2) +} + +// FetchObjectByName mocks base method. +func (m *MockResourceFetcher) FetchObjectByName(arg0 context.Context, arg1, arg2 string, arg3 client.Object) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchObjectByName", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// FetchObjectByName indicates an expected call of FetchObjectByName. +func (mr *MockResourceFetcherMockRecorder) FetchObjectByName(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchObjectByName", reflect.TypeOf((*MockResourceFetcher)(nil).FetchObjectByName), arg0, arg1, arg2, arg3) +} + +// MachineDeployment mocks base method. +func (m *MockResourceFetcher) MachineDeployment(arg0 context.Context, arg1 *v1alpha1.Cluster) (*v1alpha30.MachineDeployment, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MachineDeployment", arg0, arg1) + ret0, _ := ret[0].(*v1alpha30.MachineDeployment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MachineDeployment indicates an expected call of MachineDeployment. +func (mr *MockResourceFetcherMockRecorder) MachineDeployment(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MachineDeployment", reflect.TypeOf((*MockResourceFetcher)(nil).MachineDeployment), arg0, arg1) +} + +// VSphereMachineTemplate mocks base method. +func (m *MockResourceFetcher) VSphereMachineTemplate(arg0 context.Context, arg1 *v1alpha1.Cluster) (*v1alpha3.VSphereMachineTemplate, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "VSphereMachineTemplate", arg0, arg1) + ret0, _ := ret[0].(*v1alpha3.VSphereMachineTemplate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// VSphereMachineTemplate indicates an expected call of VSphereMachineTemplate. +func (mr *MockResourceFetcherMockRecorder) VSphereMachineTemplate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VSphereMachineTemplate", reflect.TypeOf((*MockResourceFetcher)(nil).VSphereMachineTemplate), arg0, arg1) +} + +// MockResourceUpdater is a mock of ResourceUpdater interface. +type MockResourceUpdater struct { + ctrl *gomock.Controller + recorder *MockResourceUpdaterMockRecorder +} + +// MockResourceUpdaterMockRecorder is the mock recorder for MockResourceUpdater. +type MockResourceUpdaterMockRecorder struct { + mock *MockResourceUpdater +} + +// NewMockResourceUpdater creates a new mock instance. +func NewMockResourceUpdater(ctrl *gomock.Controller) *MockResourceUpdater { + mock := &MockResourceUpdater{ctrl: ctrl} + mock.recorder = &MockResourceUpdaterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockResourceUpdater) EXPECT() *MockResourceUpdaterMockRecorder { + return m.recorder +} + +// ApplyTemplate mocks base method. +func (m *MockResourceUpdater) ApplyTemplate(arg0 context.Context, arg1 *unstructured.Unstructured, arg2 map[string]interface{}, arg3 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyTemplate", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// ApplyTemplate indicates an expected call of ApplyTemplate. +func (mr *MockResourceUpdaterMockRecorder) ApplyTemplate(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyTemplate", reflect.TypeOf((*MockResourceUpdater)(nil).ApplyTemplate), arg0, arg1, arg2, arg3) +} + +// ApplyUpdatedTemplate mocks base method. +func (m *MockResourceUpdater) ApplyUpdatedTemplate(arg0 context.Context, arg1 *unstructured.Unstructured, arg2 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ApplyUpdatedTemplate", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ApplyUpdatedTemplate indicates an expected call of ApplyUpdatedTemplate. +func (mr *MockResourceUpdaterMockRecorder) ApplyUpdatedTemplate(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyUpdatedTemplate", reflect.TypeOf((*MockResourceUpdater)(nil).ApplyUpdatedTemplate), arg0, arg1, arg2) +} + +// CreateResource mocks base method. +func (m *MockResourceUpdater) CreateResource(arg0 context.Context, arg1 *unstructured.Unstructured, arg2 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateResource", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateResource indicates an expected call of CreateResource. +func (mr *MockResourceUpdaterMockRecorder) CreateResource(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateResource", reflect.TypeOf((*MockResourceUpdater)(nil).CreateResource), arg0, arg1, arg2) +} + +// ForceApplyTemplate mocks base method. +func (m *MockResourceUpdater) ForceApplyTemplate(arg0 context.Context, arg1 *unstructured.Unstructured, arg2 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ForceApplyTemplate", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ForceApplyTemplate indicates an expected call of ForceApplyTemplate. +func (mr *MockResourceUpdaterMockRecorder) ForceApplyTemplate(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForceApplyTemplate", reflect.TypeOf((*MockResourceUpdater)(nil).ForceApplyTemplate), arg0, arg1, arg2) +} + +// UpdateTemplate mocks base method. +func (m *MockResourceUpdater) UpdateTemplate(arg0 *unstructured.Unstructured, arg1 map[string]interface{}) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplate", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTemplate indicates an expected call of UpdateTemplate. +func (mr *MockResourceUpdaterMockRecorder) UpdateTemplate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplate", reflect.TypeOf((*MockResourceUpdater)(nil).UpdateTemplate), arg0, arg1) +} diff --git a/controllers/controllers/resource/reconciler.go b/controllers/controllers/resource/reconciler.go new file mode 100644 index 000000000000..5f5008d930dc --- /dev/null +++ b/controllers/controllers/resource/reconciler.go @@ -0,0 +1,121 @@ +package resource + +import ( + "context" + "fmt" + "strings" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + anywhereTypes "github.com/aws/eks-anywhere/pkg/types" +) + +var excludeReconcilation = map[string]bool{"kubeadmcontrolplane": true, "etcdadmcluster": true} + +type Reconciler interface { + Reconcile(ctx context.Context, objectKey types.NamespacedName, dryRun bool) error +} + +type clusterReconciler struct { + Log logr.Logger + ResourceFetcher + ResourceUpdater + vsphereTemplate VsphereTemplate + dockerTemplate DockerTemplate +} + +func NewClusterReconciler(resourceFetcher ResourceFetcher, resourceUpdater ResourceUpdater, now anywhereTypes.NowFunc, log logr.Logger) *clusterReconciler { + return &clusterReconciler{ + Log: log, + ResourceFetcher: resourceFetcher, + ResourceUpdater: resourceUpdater, + vsphereTemplate: VsphereTemplate{ + ResourceFetcher: resourceFetcher, + now: now, + }, + dockerTemplate: DockerTemplate{ + ResourceFetcher: resourceFetcher, + now: now, + }, + } +} + +func (cor *clusterReconciler) Reconcile(ctx context.Context, objectKey types.NamespacedName, dryRun bool) error { + cs, err := cor.FetchCluster(ctx, objectKey) + if err != nil { + return err + } + spec, err := cor.FetchAppliedSpec(ctx, cs) + if err != nil { + return err + } + switch cs.Spec.DatacenterRef.Kind { + case anywherev1.VSphereDatacenterKind: + vdc := &anywherev1.VSphereDatacenterConfig{} + vmc := &anywherev1.VSphereMachineConfig{} + err := cor.FetchObject(ctx, types.NamespacedName{Namespace: objectKey.Namespace, Name: cs.Spec.DatacenterRef.Name}, vdc) + if err != nil { + return err + } + if len(cs.Spec.WorkerNodeGroupConfigurations) != 1 { + return fmt.Errorf("expects WorkerNodeGroupConfigurations's length to be 1, but found %d", len(cs.Spec.WorkerNodeGroupConfigurations)) + } + err = cor.FetchObject(ctx, types.NamespacedName{Namespace: objectKey.Namespace, Name: cs.Spec.WorkerNodeGroupConfigurations[0].MachineGroupRef.Name}, vmc) + if err != nil { + return err + } + resources, err := cor.vsphereTemplate.TemplateResources(ctx, cs, spec, *vdc, *vmc) + if err != nil { + return err + } + return cor.applyTemplates(ctx, resources, dryRun) + case anywherev1.DockerDatacenterKind: + resources, err := cor.dockerTemplate.TemplateResources(ctx, cs, spec) + if err != nil { + return err + } + return cor.applyTemplates(ctx, resources, dryRun) + default: + return fmt.Errorf("unsupport Provider %s", cs.Spec.DatacenterRef.Kind) + } +} + +func (cor *clusterReconciler) applyTemplates(ctx context.Context, resources []*unstructured.Unstructured, dryRun bool) error { + for _, resource := range resources { + kind := resource.GetKind() + name := resource.GetName() + if skipReconciliation(resource.GetKind()) { + cor.Log.Info("skipping object", "kind", kind, "name", name, "dryRun", dryRun) + continue + } + cor.Log.Info("applying object", "kind", kind, "name", name, "dryRun", dryRun) + fetch, err := cor.Fetch(ctx, resource.GetName(), resource.GetNamespace(), resource.GetKind(), resource.GetAPIVersion()) + if err == nil { + resource.SetResourceVersion(fetch.GetResourceVersion()) + if err := cor.ApplyUpdatedTemplate(ctx, resource, dryRun); err != nil { + return err + } + continue + } + if statusError, isStatus := err.(*errors.StatusError); isStatus && statusError.Status().Reason == metav1.StatusReasonNotFound { + if err := cor.ForceApplyTemplate(ctx, resource, dryRun); err != nil { + return err + } + continue + } + return err + } + return nil +} + +func skipReconciliation(kind string) bool { + if _, ok := excludeReconcilation[strings.ToLower(kind)]; ok { + return true + } + return false +} diff --git a/controllers/controllers/resource/reconciler_test.go b/controllers/controllers/resource/reconciler_test.go new file mode 100644 index 000000000000..0ec7eadd0943 --- /dev/null +++ b/controllers/controllers/resource/reconciler_test.go @@ -0,0 +1,243 @@ +package resource_test + +import ( + "context" + _ "embed" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + kubeadmnv1alpha3 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/yaml" + + "github.com/aws/eks-anywhere/controllers/controllers/resource" + "github.com/aws/eks-anywhere/controllers/controllers/resource/mocks" + "github.com/aws/eks-anywhere/internal/test" + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" +) + +//go:embed testdata/kubeadmcontrolplane.yaml +var kubeadmcontrolplaneFile string + +//go:embed testdata/vsphereMachineTemplate.yaml +var vsphereMachineTemplateFile string + +//go:embed testdata/machineDeployment.yaml +var machineDeploymentFile string + +//go:embed testdata/expectedMachineDeployment.yaml +var expectedMachineDeploymentFile string + +//go:embed testdata/expectedMachineDeploymentOnlyReplica.yaml +var expectedMachineDeploymentOnlyReplica string + +//go:embed testdata/vsphereDatacenterConfigSpec.yaml +var vsphereDatacenterConfigSpecPath string + +//go:embed testdata/vsphereMachineConfigSpec.yaml +var vsphereMachineConfigSpecPath string + +func TestClusterReconcilerReconcile(t *testing.T) { + type args struct { + objectKey types.NamespacedName + name string + namespace string + } + tests := []struct { + name string + args args + want controllerruntime.Result + wantErr bool + prepare func(context.Context, *mocks.MockResourceFetcher, *mocks.MockResourceUpdater, string, string) + }{ + { + name: "worker node reconcile (Vsphere provider) - worker nodes has changes", + args: args{ + namespace: "namespaceA", + name: "nameA", + objectKey: types.NamespacedName{ + Name: "nameA", + Namespace: "namespaceA", + }, + }, + want: controllerruntime.Result{}, + prepare: func(ctx context.Context, fetcher *mocks.MockResourceFetcher, resourceUpdater *mocks.MockResourceUpdater, name string, namespace string) { + replicasInput := 3 + cluster := &anywherev1.Cluster{} + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec.DatacenterRef.Name = "testDataRef" + cluster.Spec.DatacenterRef.Kind = anywherev1.VSphereDatacenterKind + cluster.Spec.WorkerNodeGroupConfigurations = []anywherev1.WorkerNodeGroupConfiguration{{Count: replicasInput, MachineGroupRef: &anywherev1.Ref{Name: "testMachineGroupRef"}}} + cluster.Spec.ClusterNetwork.Pods.CidrBlocks = []string{"192.168.0.0/16"} + cluster.Spec.ClusterNetwork.Services.CidrBlocks = []string{"10.96.0.0/12"} + + fetcher.EXPECT().FetchCluster(gomock.Any(), gomock.Any()).Return(cluster, nil) + + spec := test.NewFullClusterSpec(t, "testdata/eksa-cluster.yaml") + + fetcher.EXPECT().FetchAppliedSpec(ctx, gomock.Any()).Return(spec, nil) + + fetcher.EXPECT().FetchObject(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(ctx context.Context, objectKey types.NamespacedName, obj client.Object) { + clusterSpec := &anywherev1.VSphereDatacenterConfig{} + if err := yaml.Unmarshal([]byte(vsphereDatacenterConfigSpecPath), clusterSpec); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + cluster := obj.(*anywherev1.VSphereDatacenterConfig) + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec = clusterSpec.Spec + assert.Equal(t, objectKey.Name, "testDataRef", "expected Name to be testDataRef") + }).Return(nil) + fetcher.EXPECT().FetchObject(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(ctx context.Context, objectKey types.NamespacedName, obj client.Object) { + clusterSpec := &anywherev1.VSphereMachineConfig{} + if err := yaml.Unmarshal([]byte(vsphereMachineConfigSpecPath), clusterSpec); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + cluster := obj.(*anywherev1.VSphereMachineConfig) + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec = clusterSpec.Spec + assert.Equal(t, objectKey.Name, "testMachineGroupRef", "expected Name to be testMachineGroupRef") + }).Return(nil) + + kubeAdmControlPlane := &kubeadmnv1alpha3.KubeadmControlPlane{} + if err := yaml.Unmarshal([]byte(kubeadmcontrolplaneFile), kubeAdmControlPlane); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + + fetcher.EXPECT().ControlPlane(ctx, gomock.Any()).Return(kubeAdmControlPlane, nil) + fetcher.EXPECT().ExistingVSphereDatacenterConfig(ctx, gomock.Any()).Return(&anywherev1.VSphereDatacenterConfig{}, nil) + fetcher.EXPECT().ExistingVSphereWorkerMachineConfig(ctx, gomock.Any()).Return(&anywherev1.VSphereMachineConfig{}, nil) + fetcher.EXPECT().Fetch(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil, errors.NewNotFound(schema.GroupResource{Group: "testgroup", Resource: "testresource"}, "")) + + resourceUpdater.EXPECT().ForceApplyTemplate(ctx, gomock.Any(), gomock.Any()).Do(func(ctx context.Context, template *unstructured.Unstructured, dryRun bool) { + assert.Equal(t, false, dryRun, "Expected dryRun didn't match") + switch template.GetKind() { + case "VSphereMachineTemplate": + expectedMachineTemplate := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(vsphereMachineTemplateFile), expectedMachineTemplate); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + assert.Equal(t, expectedMachineTemplate, template, "values", expectedMachineTemplate, template) + case "MachineDeployment": + expectedMCDeployment := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(expectedMachineDeploymentFile), expectedMCDeployment); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + assert.Equal(t, expectedMCDeployment, template, "values", expectedMCDeployment, template) + } + }).AnyTimes().Return(nil) + }, + }, + { + name: "worker node reconcile (Vsphere provider) - worker nodes has NO machine-template changes", + args: args{ + namespace: "namespaceA", + name: "nameA", + objectKey: types.NamespacedName{ + Name: "nameA", + Namespace: "namespaceA", + }, + }, + want: controllerruntime.Result{}, + prepare: func(ctx context.Context, fetcher *mocks.MockResourceFetcher, resourceUpdater *mocks.MockResourceUpdater, name string, namespace string) { + cluster := &anywherev1.Cluster{} + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec.DatacenterRef.Name = "testDataRef" + cluster.Spec.DatacenterRef.Kind = anywherev1.VSphereDatacenterKind + cluster.Spec.WorkerNodeGroupConfigurations = []anywherev1.WorkerNodeGroupConfiguration{{Count: 1, MachineGroupRef: &anywherev1.Ref{Name: "testMachineGroupRef"}}} + fetcher.EXPECT().FetchCluster(gomock.Any(), gomock.Any()).Return(cluster, nil) + + spec := test.NewFullClusterSpec(t, "testdata/eksa-cluster_no_changes.yaml") + fetcher.EXPECT().FetchAppliedSpec(ctx, gomock.Any()).Return(spec, nil) + + datacenterSpec := &anywherev1.VSphereDatacenterConfig{} + if err := yaml.Unmarshal([]byte(vsphereDatacenterConfigSpecPath), datacenterSpec); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + + fetcher.EXPECT().FetchObject(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(ctx context.Context, objectKey types.NamespacedName, obj client.Object) { + cluster := obj.(*anywherev1.VSphereDatacenterConfig) + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec = datacenterSpec.Spec + assert.Equal(t, objectKey.Name, "testDataRef", "expected Name to be testDataRef") + }).Return(nil) + + existingVSDatacenter := &anywherev1.VSphereDatacenterConfig{} + existingVSDatacenter.Spec = datacenterSpec.Spec + fetcher.EXPECT().ExistingVSphereDatacenterConfig(ctx, gomock.Any()).Return(existingVSDatacenter, nil) + + machineSpec := &anywherev1.VSphereMachineConfig{} + if err := yaml.Unmarshal([]byte(vsphereMachineConfigSpecPath), machineSpec); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + + fetcher.EXPECT().FetchObject(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(ctx context.Context, objectKey types.NamespacedName, obj client.Object) { + cluster := obj.(*anywherev1.VSphereMachineConfig) + cluster.SetName(name) + cluster.SetNamespace(namespace) + cluster.Spec = machineSpec.Spec + assert.Equal(t, objectKey.Name, "testMachineGroupRef", "expected Name to be testMachineGroupRef") + }).Return(nil) + + existingVSMachine := &anywherev1.VSphereMachineConfig{} + existingVSMachine.Spec = machineSpec.Spec + fetcher.EXPECT().ExistingVSphereWorkerMachineConfig(ctx, gomock.Any()).Return(existingVSMachine, nil) + + kubeAdmControlPlane := &kubeadmnv1alpha3.KubeadmControlPlane{} + if err := yaml.Unmarshal([]byte(kubeadmcontrolplaneFile), kubeAdmControlPlane); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + + mcDeployment := &clusterv1.MachineDeployment{} + if err := yaml.Unmarshal([]byte(machineDeploymentFile), mcDeployment); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + + fetcher.EXPECT().ControlPlane(ctx, gomock.Any()).Return(kubeAdmControlPlane, nil) + fetcher.EXPECT().MachineDeployment(ctx, gomock.Any()).Return(mcDeployment, nil) + + fetcher.EXPECT().Fetch(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil, errors.NewNotFound(schema.GroupResource{Group: "testgroup", Resource: "testresource"}, "")) + + resourceUpdater.EXPECT().ForceApplyTemplate(ctx, gomock.Any(), gomock.Any()).Do(func(ctx context.Context, template *unstructured.Unstructured, dryRun bool) { + assert.Equal(t, false, dryRun, "Expected dryRun didn't match") + println(template.GetName(), " : ", template.GetKind()) + switch template.GetKind() { + case "MachineDeployment": + expectedMCDeployment := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(expectedMachineDeploymentOnlyReplica), expectedMCDeployment); err != nil { + t.Errorf("unmarshal failed: %v", err) + } + assert.Equal(t, expectedMCDeployment, template, "values", expectedMCDeployment, template) + } + }).AnyTimes().Return(nil) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + mockCtrl := gomock.NewController(t) + fetcher := mocks.NewMockResourceFetcher(mockCtrl) + resourceUpdater := mocks.NewMockResourceUpdater(mockCtrl) + tt.prepare(ctx, fetcher, resourceUpdater, tt.args.name, tt.args.namespace) + + cor := resource.NewClusterReconciler(fetcher, resourceUpdater, test.FakeNow, log.NullLogger{}) + + if err := cor.Reconcile(ctx, tt.args.objectKey, false); (err != nil) != tt.wantErr { + t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/controllers/controllers/resource/template.go b/controllers/controllers/resource/template.go new file mode 100644 index 000000000000..37092b4c5308 --- /dev/null +++ b/controllers/controllers/resource/template.go @@ -0,0 +1,111 @@ +package resource + +import ( + "context" + "strings" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/yaml" + + anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/providers" + "github.com/aws/eks-anywhere/pkg/providers/docker" + "github.com/aws/eks-anywhere/pkg/providers/vsphere" + anywhereTypes "github.com/aws/eks-anywhere/pkg/types" +) + +type DockerTemplate struct { + ResourceFetcher + now anywhereTypes.NowFunc +} + +type VsphereTemplate struct { + ResourceFetcher + now anywhereTypes.NowFunc +} + +func (r *VsphereTemplate) TemplateResources(ctx context.Context, eksaCluster *anywherev1.Cluster, clusterSpec *cluster.Spec, vdcSpec anywherev1.VSphereDatacenterConfig, vmcSpec anywherev1.VSphereMachineConfig) ([]*unstructured.Unstructured, error) { + // passing the same vspheremachineconfig for worker and cp as control plane updates are prohibited in controller + templateBuilder := vsphere.NewVsphereTemplateBuilder(&vdcSpec.Spec, &vmcSpec.Spec, &vmcSpec.Spec, r.now) + clusterName := clusterSpec.ObjectMeta.Name + kubeadmControlPlane, err := r.ControlPlane(ctx, eksaCluster) + if err != nil { + return nil, err + } + oldVdcSpec, err := r.ExistingVSphereDatacenterConfig(ctx, eksaCluster) + if err != nil { + return nil, err + } + oldVmcSpec, err := r.ExistingVSphereWorkerMachineConfig(ctx, eksaCluster) + if err != nil { + return nil, err + } + var workloadTemplateName string + updateWorkloadTemplate := vsphere.AnyImmutableFieldChanged(oldVdcSpec, &vdcSpec, oldVmcSpec, &vmcSpec) + if updateWorkloadTemplate { + workloadTemplateName = templateBuilder.WorkerMachineTemplateName(clusterName) + } else { + mcDeployment, err := r.MachineDeployment(ctx, eksaCluster) + if err != nil { + return nil, err + } + workloadTemplateName = mcDeployment.Spec.Template.Spec.InfrastructureRef.Name + } + if len(vmcSpec.Spec.Users) <= 0 { + vmcSpec.Spec.Users = []anywherev1.UserConfiguration{{}} + } + if len(vmcSpec.Spec.Users[0].SshAuthorizedKeys) <= 0 { + vmcSpec.Spec.Users[0].SshAuthorizedKeys = []string{""} + } + valuesOpt := func(values map[string]interface{}) { + values["needsNewControlPlaneTemplate"] = false // not supported in flux + values["controlPlaneTemplateName"] = kubeadmControlPlane.Spec.InfrastructureTemplate.Name + values["needsNewWorkloadTemplate"] = updateWorkloadTemplate + values["workloadTemplateName"] = workloadTemplateName + values["clusterName"] = clusterName + values["vsphereWorkerSshAuthorizedKey"] = vmcSpec.Spec.Users[0].SshAuthorizedKeys[0] + values["needsNewEtcdTemplate"] = false + } + return generateTemplateResources(templateBuilder, clusterSpec, valuesOpt) +} + +func generateTemplateResources(builder providers.TemplateBuilder, clusterSpec *cluster.Spec, buildOptions ...providers.BuildMapOption) ([]*unstructured.Unstructured, error) { + content, err := builder.GenerateDeploymentFile(clusterSpec, buildOptions...) + if err != nil { + return nil, err + } + var resources []*unstructured.Unstructured + templates := strings.Split(string(content), "---") + for _, template := range templates { + u := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(template), u); err != nil { + continue + } + if u.GetKind() != "" { + resources = append(resources, u) + } + } + return resources, nil +} + +func (r *DockerTemplate) TemplateResources(ctx context.Context, eksaCluster *anywherev1.Cluster, clusterSpec *cluster.Spec) ([]*unstructured.Unstructured, error) { + templateBuilder := docker.NewDockerTemplateBuilder(r.now) + mcDeployment, err := r.MachineDeployment(ctx, eksaCluster) + if err != nil { + return nil, err + } + kubeadmControlPlane, err := r.ControlPlane(ctx, eksaCluster) + if err != nil { + return nil, err + } + valuesOpt := func(values map[string]interface{}) { + values["clusterName"] = clusterSpec.ObjectMeta.Name + values["needsNewControlPlaneTemplate"] = false + values["controlPlaneTemplateName"] = kubeadmControlPlane.Spec.InfrastructureTemplate.Name + values["needsNewWorkloadTemplate"] = false + values["workloadTemplateName"] = mcDeployment.Spec.Template.Spec.InfrastructureRef.Name + values["needsNewEtcdTemplate"] = false + } + return generateTemplateResources(templateBuilder, clusterSpec, valuesOpt) +} diff --git a/controllers/controllers/resource/testdata/eksa-cluster.yaml b/controllers/controllers/resource/testdata/eksa-cluster.yaml new file mode 100644 index 000000000000..0ec89b08ef55 --- /dev/null +++ b/controllers/controllers/resource/testdata/eksa-cluster.yaml @@ -0,0 +1,61 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: test_cluster +spec: + controlPlaneConfiguration: + count: 3 + endpoint: + host: "198.18.40.234" + machineGroupRef: + name: test_cluster + kind: VSphereMachineConfig + kubernetesVersion: "1.19" + workerNodeGroupConfigurations: + - count: 4 + machineGroupRef: + name: test_cluster + kind: VSphereMachineConfig + datacenterRef: + kind: VSphereDatacenter + name: test_cluster + clusterNetwork: + cni: "cilium" + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereMachineConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + diskGiB: 25 + datastore: /SDDC-Datacenter/datastore/WorkloadDatastore + folder: /SDDC-Datacenter/vm/capv/testuser + memoryMiB: 8192 + numCPUs: 3 + osFamily: ubuntu + resourcePool: "*/Resources/Compute-ResourcePool" + template: /SDDC-Datacenter/vm/Templates/ubuntu-v1.19.12-eks-d-1-19-5-eks-a-0.0.1-amd64 + users: + - name: capv + sshAuthorizedKeys: + - "ssh-rsa ssh_key_value" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereDatacenterConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + datacenter: SDDC-Datacenter + network: /SDDC-Datacenter/network/sddc-cgw-network-1 + server: vc_host + insecure: false + thumbprint: "" +status: {} diff --git a/controllers/controllers/resource/testdata/eksa-cluster_no_changes.yaml b/controllers/controllers/resource/testdata/eksa-cluster_no_changes.yaml new file mode 100644 index 000000000000..81ad530a0d6e --- /dev/null +++ b/controllers/controllers/resource/testdata/eksa-cluster_no_changes.yaml @@ -0,0 +1,61 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: test_cluster +spec: + controlPlaneConfiguration: + count: 1 + endpoint: + host: "198.18.40.234" + machineGroupRef: + name: test_cluster + kind: VSphereMachineConfig + kubernetesVersion: "1.19" + workerNodeGroupConfigurations: + - count: 3 + machineGroupRef: + name: test_cluster + kind: VSphereMachineConfig + datacenterRef: + kind: VSphereDatacenter + name: test_cluster + clusterNetwork: + cni: "cilium" + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereMachineConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + diskGiB: 25 + datastore: /SDDC-Datacenter/datastore/WorkloadDatastore + folder: /SDDC-Datacenter/vm/capv/testuser + memoryMiB: 8192 + numCPUs: 2 + osFamily: ubuntu + resourcePool: "*/Resources/Compute-ResourcePool" + template: /SDDC-Datacenter/vm/Templates/ubuntu-v1.19.12-eks-d-1-19-5-eks-a-0.0.1-amd64 + users: + - name: capv + sshAuthorizedKeys: + - "ssh-rsa ssh_key_value" +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereDatacenterConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + datacenter: SDDC-Datacenter + network: /SDDC-Datacenter/network/sddc-cgw-network-1 + server: vc_host + insecure: false + thumbprint: "" +status: {} diff --git a/controllers/controllers/resource/testdata/expectedMachineDeployment.yaml b/controllers/controllers/resource/testdata/expectedMachineDeployment.yaml new file mode 100644 index 000000000000..703128a60a32 --- /dev/null +++ b/controllers/controllers/resource/testdata/expectedMachineDeployment.yaml @@ -0,0 +1,28 @@ +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: MachineDeployment +metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + name: test_cluster-md-0 + namespace: default +spec: + clusterName: test_cluster + replicas: 4 + selector: + matchLabels: {} + template: + metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 + kind: KubeadmConfigTemplate + name: test_cluster-md-0 + clusterName: test_cluster + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: VSphereMachineTemplate + name: test_cluster-worker-node-template-1234567890000 + version: v1.19.8-eks-1-19-4 diff --git a/controllers/controllers/resource/testdata/expectedMachineDeploymentOnlyReplica.yaml b/controllers/controllers/resource/testdata/expectedMachineDeploymentOnlyReplica.yaml new file mode 100644 index 000000000000..edcc1e12e730 --- /dev/null +++ b/controllers/controllers/resource/testdata/expectedMachineDeploymentOnlyReplica.yaml @@ -0,0 +1,28 @@ +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: MachineDeployment +metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + name: test_cluster-md-0 + namespace: default +spec: + clusterName: test_cluster + replicas: 3 + selector: + matchLabels: {} + template: + metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 + kind: KubeadmConfigTemplate + name: test_cluster-md-0 + clusterName: test_cluster + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: VSphereMachineTemplate + name: test_cluster-workload-template-1 + version: v1.19.8-eks-1-19-4 diff --git a/controllers/controllers/resource/testdata/kubeadmcontrolplane.yaml b/controllers/controllers/resource/testdata/kubeadmcontrolplane.yaml new file mode 100644 index 000000000000..ca5f3597b508 --- /dev/null +++ b/controllers/controllers/resource/testdata/kubeadmcontrolplane.yaml @@ -0,0 +1,101 @@ +apiVersion: controlplane.cluster.x-k8s.io/v1alpha3 +kind: KubeadmControlPlane +metadata: + name: test_cluster + namespace: default +spec: + infrastructureTemplate: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: VSphereMachineTemplate + name: test_cluster-control-plane-template-v1.19.8-eks-1-19-4 + kubeadmConfigSpec: + clusterConfiguration: + imageRepository: public.ecr.aws/eks-distro/kubernetes + etcd: + local: + imageRepository: public.ecr.aws/eks-distro/etcd-io + imageTag: v3.4.14-eks-1-19-4 + dns: + type: CoreDNS + imageRepository: public.ecr.aws/eks-distro/coredns + imageTag: v1.8.0-eks-1-19-4 + apiServer: + extraArgs: + cloud-provider: external + controllerManager: + extraArgs: + cloud-provider: external + files: + - content: | + apiVersion: v1 + kind: Pod + metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system + spec: + containers: + - args: + - start + env: + - name: vip_arp + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_address + value: 198.18.40.234 + - name: vip_interface + value: eth0 + - name: vip_leaseduration + value: "15" + - name: vip_renewdeadline + value: "10" + - name: vip_retryperiod + value: "2" + image: public.ecr.aws/l0g8r8j6/plunder-app/kube-vip:v0.3.2-2093eaeda5a4567f0e516d652e0b25b1d7abc774 + imagePullPolicy: IfNotPresent + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + type: FileOrCreate + name: kubeconfig + status: {} + owner: root:root + path: /etc/kubernetes/manifests/kube-vip.yaml + initConfiguration: + nodeRegistration: + criSocket: /var/run/containerd/containerd.sock + kubeletExtraArgs: + cloud-provider: external + name: '{{ ds.meta_data.hostname }}' + joinConfiguration: + nodeRegistration: + criSocket: /var/run/containerd/containerd.sock + kubeletExtraArgs: + cloud-provider: external + name: '{{ ds.meta_data.hostname }}' + preKubeadmCommands: + - hostname "{{ ds.meta_data.hostname }}" + - echo "::1 ipv6-localhost ipv6-loopback" >/etc/hosts + - echo "127.0.0.1 localhost" >>/etc/hosts + - echo "127.0.0.1 {{ ds.meta_data.hostname }}" >>/etc/hosts + - echo "{{ ds.meta_data.hostname }}" >/etc/hostname + useExperimentalRetryJoin: true + users: + - name: capv + sshAuthorizedKeys: + - 'ssh-rsa ssh_key_value' + sudo: ALL=(ALL) NOPASSWD:ALL + replicas: 1 + version: v1.19.8-eks-1-19-4 \ No newline at end of file diff --git a/controllers/controllers/resource/testdata/machineDeployment.yaml b/controllers/controllers/resource/testdata/machineDeployment.yaml new file mode 100644 index 000000000000..e1144e69fc33 --- /dev/null +++ b/controllers/controllers/resource/testdata/machineDeployment.yaml @@ -0,0 +1,28 @@ +apiVersion: cluster.x-k8s.io/v1alpha3 +kind: MachineDeployment +metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + name: test_cluster-md-0 + namespace: default +spec: + clusterName: test_cluster + replicas: 1 + selector: + matchLabels: {} + template: + metadata: + labels: + cluster.x-k8s.io/cluster-name: test_cluster + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3 + kind: KubeadmConfigTemplate + name: test_cluster-md-0 + clusterName: test_cluster + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 + kind: VSphereMachineTemplate + name: test_cluster-workload-template-1 + version: v1.19.8-eks-1-19-4 diff --git a/controllers/controllers/resource/testdata/vsphereDatacenterConfigSpec.yaml b/controllers/controllers/resource/testdata/vsphereDatacenterConfigSpec.yaml new file mode 100644 index 000000000000..9ad17f95f7ea --- /dev/null +++ b/controllers/controllers/resource/testdata/vsphereDatacenterConfigSpec.yaml @@ -0,0 +1,12 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereDatacenterConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + datacenter: SDDC-Datacenter + network: /SDDC-Datacenter/network/sddc-cgw-network-1 + server: vc_host + insecure: false + thumbprint: "" +status: {} \ No newline at end of file diff --git a/controllers/controllers/resource/testdata/vsphereMachineConfigSpec.yaml b/controllers/controllers/resource/testdata/vsphereMachineConfigSpec.yaml new file mode 100644 index 000000000000..cde6c989ddf1 --- /dev/null +++ b/controllers/controllers/resource/testdata/vsphereMachineConfigSpec.yaml @@ -0,0 +1,19 @@ +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereMachineConfig +metadata: + creationTimestamp: null + name: test_cluster +spec: + diskGiB: 25 + datastore: /SDDC-Datacenter/datastore/WorkloadDatastore + folder: /SDDC-Datacenter/vm/capv/testuser + memoryMiB: 8192 + numCPUs: 3 + osFamily: ubuntu + resourcePool: '*/Resources/Compute-ResourcePool' + template: /SDDC-Datacenter/vm/Templates/ubuntu-v1.19.12-eks-d-1-19-5-eks-a-0.0.1-amd64 + users: + - name: capv + sshAuthorizedKeys: + - "ssh-rsa ssh_key_value" +status: {} \ No newline at end of file diff --git a/controllers/controllers/resource/testdata/vsphereMachineTemplate.yaml b/controllers/controllers/resource/testdata/vsphereMachineTemplate.yaml new file mode 100644 index 000000000000..d94b3b13cbb4 --- /dev/null +++ b/controllers/controllers/resource/testdata/vsphereMachineTemplate.yaml @@ -0,0 +1,24 @@ +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 +kind: VSphereMachineTemplate +metadata: + name: test_cluster-worker-node-template-1234567890000 + namespace: default +spec: + template: + spec: + cloneMode: linkedClone + datacenter: SDDC-Datacenter + datastore: /SDDC-Datacenter/datastore/WorkloadDatastore + diskGiB: 25 + folder: '/SDDC-Datacenter/vm/capv/testuser' + memoryMiB: 8192 + network: + devices: + - dhcp4: true + networkName: /SDDC-Datacenter/network/sddc-cgw-network-1 + numCPUs: 3 + resourcePool: '*/Resources/Compute-ResourcePool' + server: vc_host + template: /SDDC-Datacenter/vm/Templates/ubuntu-v1.19.12-eks-d-1-19-5-eks-a-0.0.1-amd64 + thumbprint: '' + diff --git a/controllers/controllers/resource/updater.go b/controllers/controllers/resource/updater.go new file mode 100644 index 000000000000..c7f400d8d7e7 --- /dev/null +++ b/controllers/controllers/resource/updater.go @@ -0,0 +1,124 @@ +package resource + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type ResourceUpdater interface { + CreateResource(ctx context.Context, obj *unstructured.Unstructured, dryRun bool) error + UpdateTemplate(template *unstructured.Unstructured, values map[string]interface{}) (hasDiff bool, err error) + ApplyTemplate(ctx context.Context, template *unstructured.Unstructured, values map[string]interface{}, dryRun bool) error + ForceApplyTemplate(ctx context.Context, template *unstructured.Unstructured, dryRun bool) error + ApplyUpdatedTemplate(ctx context.Context, template *unstructured.Unstructured, dryRun bool) error +} + +type capiResourceUpdater struct { + client client.Client + Log logr.Logger +} + +func NewCapiResourceUpdater(client client.Client, log logr.Logger) *capiResourceUpdater { + return &capiResourceUpdater{ + client: client, + Log: log, + } +} + +func (u *capiResourceUpdater) applyPatch(ctx context.Context, obj client.Object, dryRun bool) error { + dryRunStage := []string{} + if dryRun { + dryRunStage = []string{"All"} + } + err := u.client.Patch(ctx, obj, client.Merge, &client.PatchOptions{FieldManager: "eks-controller", DryRun: dryRunStage}) + if err != nil { + return err + } + return nil +} + +func (u *capiResourceUpdater) CreateResource(ctx context.Context, obj *unstructured.Unstructured, dryRun bool) error { + dryRunStage := []string{} + if dryRun { + dryRunStage = []string{"All"} + } + obj.SetResourceVersion("") + err := u.client.Create(ctx, obj, &client.CreateOptions{FieldManager: "eks-controller", DryRun: dryRunStage}) + if err != nil { + return err + } + return nil +} + +func (u *capiResourceUpdater) UpdateTemplate(template *unstructured.Unstructured, values map[string]interface{}) (hasDiff bool, err error) { + originalTemplate := template.DeepCopy() + for k, v := range values { + path := strings.Split(k, ",") + err := validatePath(template, path) + if err != nil { + return false, err + } + err = unstructured.SetNestedField(template.Object, v, path...) + if err != nil { + return false, err + } + } + return !reflect.DeepEqual(originalTemplate.Object, template.Object), err +} + +func validatePath(template *unstructured.Unstructured, path []string) error { + _, exists, err := unstructured.NestedFieldNoCopy(template.Object, path...) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the path provided %v doesn't exists on the object %s", path, template.GetName()) + } + return nil +} + +func (u *capiResourceUpdater) ApplyTemplate(ctx context.Context, template *unstructured.Unstructured, values map[string]interface{}, dryRun bool) error { + _, err := u.UpdateTemplate(template, values) + if err != nil { + return err + } + u.Log.Info("Applying patch", "object", template.GetName(), "kind", template.GetKind(), "values", values) + err = u.applyPatch(ctx, template, dryRun) + if err != nil { + return err + } + return nil +} + +func (u *capiResourceUpdater) ApplyUpdatedTemplate(ctx context.Context, template *unstructured.Unstructured, dryRun bool) error { + u.Log.Info("applied template", "object", template.GetName(), "kind", template.GetKind(), "dryRun", dryRun) + dryRunStage := []string{} + if dryRun { + dryRunStage = []string{"All"} + } + err := u.client.Update(ctx, template, &client.UpdateOptions{FieldManager: "eks-controller", DryRun: dryRunStage}) + if err != nil { + return err + } + return nil +} + +func (u *capiResourceUpdater) ForceApplyTemplate(ctx context.Context, template *unstructured.Unstructured, dryRun bool) error { + u.Log.Info("force applying template", "object", template.GetName(), "kind", template.GetKind(), "dryRun", dryRun) + force := true + dryRunStage := []string{} + if dryRun { + dryRunStage = []string{"All"} + } + err := u.client.Patch(ctx, template, client.Apply, &client.PatchOptions{FieldManager: "eks-controller", DryRun: dryRunStage, Force: &force}) + if err != nil { + return err + } + return nil +} diff --git a/controllers/main.go b/controllers/main.go new file mode 100644 index 000000000000..aacad938bf4f --- /dev/null +++ b/controllers/main.go @@ -0,0 +1,114 @@ +package main + +import ( + "flag" + "os" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth" + vspherev3 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha3" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/aws/eks-anywhere/controllers/controllers" + anywherev1alpha1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + releasev1alpha1 "github.com/aws/eks-anywhere/release/api/v1alpha1" +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +const WEBHOOK = "webhook" + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(anywherev1alpha1.AddToScheme(scheme)) + utilruntime.Must(releasev1alpha1.AddToScheme(scheme)) + utilruntime.Must(clusterv1.AddToScheme(scheme)) + utilruntime.Must(controlplanev1.AddToScheme(scheme)) + utilruntime.Must(vspherev3.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "f64ae69e.eks.amazonaws.com", + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (controllers.NewClusterReconciler( + mgr.GetClient(), + ctrl.Log.WithName("controllers").WithName(anywherev1alpha1.ClusterKind), + mgr.GetScheme())).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", anywherev1alpha1.ClusterKind) + os.Exit(1) + } + if err = (&anywherev1alpha1.Cluster{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", WEBHOOK, anywherev1alpha1.ClusterKind) + os.Exit(1) + } + if err = (&anywherev1alpha1.VSphereDatacenterConfig{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", WEBHOOK, anywherev1alpha1.VSphereDatacenterKind) + os.Exit(1) + } + if err = (&anywherev1alpha1.VSphereMachineConfig{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", WEBHOOK, anywherev1alpha1.VSphereMachineConfigKind) + os.Exit(1) + } + + if err = (&anywherev1alpha1.GitOpsConfig{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", WEBHOOK, anywherev1alpha1.GitOpsConfigKind) + os.Exit(1) + } + if err = (&anywherev1alpha1.OIDCConfig{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", WEBHOOK, anywherev1alpha1.OIDCConfigKind) + os.Exit(1) + } + //+kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 000000000000..2b2a26243c8b Binary files /dev/null and b/docs/.DS_Store differ diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000000..335827e283a9 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +public/ +resources/ +node_modules/ +tech-doc-hugo diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 000000000000..4a66718bee07 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,7 @@ +FROM klakegg/hugo:ext-alpine + +RUN apk add git npm + +COPY package.json package-lock.json . + +RUN npm install diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000000..551ec827c611 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,51 @@ +IMAGE_REGISTRY ?= public.ecr.aws/eks-distro-build-tooling +CONTAINER_IMAGE = $(IMAGE_REGISTRY)/eks-a-hugo +CONTAINER_RUN = docker run --rm --interactive --tty --volume $(CURDIR)/../:/src +DOCS_ARCHIVE = public.zip + +.PHONY: help build submodule zip deploy serve server container-build container-serve container-server clean + +help: ## Show this help. Requires locally installed npm and hugo. + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +build: submodule ## Generate the static site into the /public folder + npm install + hugo --environment production --cleanDestinationDir + +submodule: ## initialize the docsy theme submodule + git submodule update --init --recursive + +submodule-reset: ## reset submodules to tracked commit + git submodule foreach --recursive git reset --hard + +zip: clean build ## Create zip file of assets to upload + # move into public folder so zip file doesn't have a public folder + # put the zip file up one directory in docs to be used by deploy target + cd public && zip -r --quiet ../$(DOCS_ARCHIVE) ./ + +deploy: zip ## Deploy docs to Amplify + bash ./deploy-docs.sh public.zip + +serve: submodule ## Boot the development server. + hugo server --buildFuture --baseUrl http://127.0.0.1 + +server: serve + +container-build: submodule ## Build a container image for the preview of the website + docker build -t $(CONTAINER_IMAGE) . + +container-serve: ## Boot the development server using container. Run `make container-image` before this. + $(CONTAINER_RUN) --mount type=tmpfs,destination=/tmp,tmpfs-mode=01777 \ + --workdir /src/docs \ + -p 1313:1313 $(CONTAINER_IMAGE) server \ + --buildFuture \ + --buildDrafts \ + --bind 0.0.0.0 \ + --destination /tmp/hugo \ + --cleanDestinationDir \ + --baseUrl http://0.0.0.0 + +container-server: container-serve + +clean: ## Delete generated content. (requires sudo if using container-serve) + rm -rf public resources node_modules public.zip diff --git a/docs/OWNERS b/docs/OWNERS new file mode 100644 index 000000000000..6ae574b1f349 --- /dev/null +++ b/docs/OWNERS @@ -0,0 +1,8 @@ +approvers: +- chrisnegus +- rothgar +reviewers: +- chrisnegus +- rothgar +labels: +- documentation diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000000..8e05472a7468 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,34 @@ +# EKS Anywhere Documentation + +EKS Documentation lives in this folder. +It uses [`hugo`](https://gohugo.io/) for static site generation with the [docsy](https://docsy.dev) for a theme. + +## Local development + +To run the local documentation server you can use the provided make targets to create a container with the required dependencies. + +```bash +make container-build +make container-serve +``` + +Open http://127.0.0.1:1313 to see the local site. +With the serve container running you can now edit the documentation in your git clone and changes will be rebuilt automatically. + +## Production site + +The production website is hosted on Amplify. +To deploy the docs to a personal amplify app you need to first create an app with a branch. +Export your `${AWS_PROFILE}`, `${AMPLIFY_APP_ID}`, and `${AMPLIFY_APP_BRANCH}` (default: main). + +Then run +```bash +make deploy +``` +It will build the site, create a zip, and deploy it to your Amplify app. + +If you want to connect a custom domain you can do that manually in Amplify/Route53 or you can look at the CDK deployment infrastructure. + +### Website versions + +Each website version has a unique subdomain url (eg v1.anywhere.eks.amazonaws.com) so users can view different versions of the documentation. \ No newline at end of file diff --git a/docs/archetypes/default.md b/docs/archetypes/default.md new file mode 100644 index 000000000000..00e77bd79be4 --- /dev/null +++ b/docs/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/docs/assets/icons/eks-anywhere-icon-blue.svg b/docs/assets/icons/eks-anywhere-icon-blue.svg new file mode 100644 index 000000000000..e30c5efcec24 --- /dev/null +++ b/docs/assets/icons/eks-anywhere-icon-blue.svg @@ -0,0 +1,7 @@ + + + Icon-Service/64/Amazon-EKS-Anywhere_64_White + + + + diff --git a/docs/assets/icons/logo.png b/docs/assets/icons/logo.png new file mode 100644 index 000000000000..555faefd10db Binary files /dev/null and b/docs/assets/icons/logo.png differ diff --git a/docs/assets/icons/logo.svg b/docs/assets/icons/logo.svg new file mode 100644 index 000000000000..41534f672265 --- /dev/null +++ b/docs/assets/icons/logo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/assets/scss/_variables_project.scss b/docs/assets/scss/_variables_project.scss new file mode 100644 index 000000000000..9561065139c3 --- /dev/null +++ b/docs/assets/scss/_variables_project.scss @@ -0,0 +1 @@ +$primary: #3371E2; \ No newline at end of file diff --git a/docs/config.toml b/docs/config.toml new file mode 100644 index 000000000000..28c223c5e652 --- /dev/null +++ b/docs/config.toml @@ -0,0 +1,184 @@ +baseURL = "/" +title = "Amazon EKS Anywhere" + +enableRobotsTXT = true + +# Hugo allows theme composition (and inheritance). The precedence is from left to right. +theme = ["docsy"] + +# Will give values to .Lastmod etc. +enableGitInfo = true + +# Language settings +contentDir = "content/en" +defaultContentLanguage = "en" +defaultContentLanguageInSubdir = false +# Useful when translating. +enableMissingTranslationPlaceholders = true + +disableKinds = ["taxonomy", "taxonomyTerm"] + +# Highlighting config +pygmentsCodeFences = true +pygmentsUseClasses = false +# Use the new Chroma Go highlighter in Hugo. +pygmentsUseClassic = false +#pygmentsOptions = "linenos=table" +# See https://help.farbox.com/pygments.html +pygmentsStyle = "tango" + +# Configure how URLs look like per section. +[permalinks] +blog = "/:section/:year/:month/:day/:slug/" + +## Configuration for BlackFriday markdown parser: https://github.com/russross/blackfriday +[blackfriday] +plainIDAnchors = true +hrefTargetBlank = true +angledQuotes = false +latexDashes = true + +# Image processing configuration. +[imaging] +resampleFilter = "CatmullRom" +quality = 75 +anchor = "smart" + +[services] +[services.googleAnalytics] +# Comment out the next line to disable GA tracking. Also disables the feature described in [params.ui.feedback]. +#id = "UA-00000000-0" + +# Language configuration + +[languages] +[languages.en] +title = "EKS Anywhere" +description = "Documentation for Amazon EKS Anywhere" +languageName ="English" +# Weight used for sorting. +weight = 1 + +[markup] + [markup.goldmark] + [markup.goldmark.renderer] + unsafe = true + [markup.highlight] + # See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html + style = "tango" + # Uncomment if you want your chosen highlight style used for code blocks without a specified language + # guessSyntax = "true" + +# Everything below this are Site Params + +# Comment out if you don't want the "print entire section" link enabled. +[outputs] +section = ["HTML", "print"] + + +[[menu.main]] + name = "Community" + weight = 40 + url = "/docs/community" + pre = "" + +[[menu.main]] + name = "GitHub" + weight = 50 + url = "https://github.com/aws/eks-anywhere" + pre = "" + +[params] +copyright = "Amazon.com, Inc. or its affilliates." +# privacy_policy = "https://policies.google.com/privacy" + +# First one is picked as the Twitter card image if not set on page. +# images = ["images/project-illustration.png"] + +# Menu title if your navbar has a versions selector to access old versions of your site. +# This menu appears only if you have at least one [params.versions] set. +version_menu = "Releases" + +# Flag used in the "version-banner" partial to decide whether to display a +# banner on every page indicating that this is an archived version of the docs. +# Set this flag to "true" if you want to display the banner. +archived_version = false + +# The version number for the version of the docs represented in this doc set. +# Used in the "version-banner" partial to display a version number for the +# current doc set. +version = "0.3.0" + +# A link to latest version of the docs. Used in the "version-banner" partial to +# point people to the main doc site. +url_latest_version = "https://anywhere.eks.amazonaws.com" + +# Repository configuration (URLs for in-page links to opening issues and suggesting changes) +# github_repo = "https://github.com/aws/eks-anywhere" +# An optional link to a related project repo. For example, the sibling repository where your product code lives. +github_project_repo = "https://github.com/aws/eks-anywhere" + +# Specify a value here if your content directory is not in your repo's root directory +github_subdir = "docs" + +# Uncomment this if you have a newer GitHub repo with "main" as the default branch, +# or specify a new value if you want to reference another branch in your GitHub links +# github_branch= "main" + +# Google Custom Search Engine ID. Remove or comment out to disable search. +# gcs_engine_id = "d72aa9b2712488cc3" + +# Enable Algolia DocSearch +algolia_docsearch = false + +# Enable Lunr.js offline search +offlineSearch = true + +# Enable syntax highlighting and copy buttons on code blocks with Prism +prism_syntax_highlighting = true + +# User interface configuration +[params.ui] +# Enable to show the side bar menu in its compact state. +sidebar_menu_compact = true +sidebar_menu_foldable = true +# Set to true to disable breadcrumb navigation. +breadcrumb_disable = false +# Set to true to hide the sidebar search box (the top nav search box will still be displayed if search is enabled) +sidebar_search_disable = false +# Set to false if you don't want to display a logo (/assets/icons/logo.svg) in the top nav bar +navbar_logo = true +# Set to true to disable the About link in the site footer +# footer_about_disable = false +footer_about_disable = true + +# Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events. +# This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set. +# If you want this feature, but occasionally need to remove the "Feedback" section from a single page, +# add "hide_feedback: true" to the page's front matter. +[params.ui.feedback] +enable = true +# The responses that the user sees after clicking "yes" (the page was helpful) or "no" (the page was not helpful). +yes = 'Glad to hear it! Please tell us how we can improve.' +no = 'Sorry to hear that. Please tell us how we can improve.' + +# Adds a reading time to the top of each doc. +# If you want this feature, but occasionally need to remove the Reading time from a single page, +# add "hide_readingtime: true" to the page's front matter +[params.ui.readingtime] +enable = false + +[params.links] +# Developer relevant links. These will show up on right side of footer and in the community page if you have one. +[[params.links.developer]] + name = "GitHub" + url = "https://github.com/aws/eks-anywhere" + icon = "fab fa-github" + desc = "Development takes place here!" + +[[params.versions]] +fullversion = "main" +version = "main" +githubbranch = "main" +docsbranch = "main" +url = "/docs" diff --git a/docs/content/en/_index.html b/docs/content/en/_index.html new file mode 100644 index 000000000000..4c9038d86d8d --- /dev/null +++ b/docs/content/en/_index.html @@ -0,0 +1,39 @@ ++++ +title = "EKS Anywhere" +linkTitle = "EKS-A" + ++++ + +{{< blocks/cover title="Amazon EKS Anywhere" image_anchor="top" height="min" color="orange" >}} +

Run EKS in your datacenter

+ +{{< /blocks/cover >}} + +{{< blocks/section color="white" class="w-75 mx-auto" >}} + +{{< blocks/feature title="" class="text-xl text-center mb-5" >}} +EKS Anywhere (EKS-A) is an open-source packaging of Kubernetes based on EKS Distro. +It builds on all of the amazing features of upstream Kubernetes with the operational excellence of Amazon Web Services from running millions of containers in EKS. +{{< /blocks/feature >}} + +{{< blocks/feature title="Operational Excellence" image="/images/thumbs-up.svg" order="left" >}} +Leverage proven Amazon Elastic Kubernetes Service (EKS) features with existing on-prem investments +{{< /blocks/feature >}} + +{{< blocks/feature title="Supported Ecosystem" image="/images/cloud-disk.svg" order="right" >}} +Accelerate adoption with partner integrations, managed add-ons, and curated open source tools +{{< /blocks/feature >}} + +{{< blocks/feature title="Infrastructure as Software" image="/images/network.svg" order="left" >}} +Create, deploy, and maintain clusters to fit your CI/CD needs with integrated GitOps controllers +{{< /blocks/feature >}} + +{{< blocks/feature title="Any Size" image="/images/data-server.svg" order="right" >}} +Start from anywhere and scale up—from a local machine to thousand-node production clusters +{{< /blocks/feature >}} + +{{< /blocks/section >}} diff --git a/docs/content/en/docs/_index.md b/docs/content/en/docs/_index.md new file mode 100755 index 000000000000..366a101a4368 --- /dev/null +++ b/docs/content/en/docs/_index.md @@ -0,0 +1,24 @@ +--- +title: "Elastic Kubernetes Service - Anywhere Documentation" +linkTitle: Documentation +noedit: true +weight: 10 +menu: + main: + weight: 20 + pre: +description: > + EKS Anywhere provides a means of managing Kubernetes clusters using the same Kubernetes platform that Amazon Web Services uses for its Amazon Elastic Kubernetes Service. + Based on [EKS Distro](https://github.com/aws/eks-distro), EKS-A adds methods for deploying, using, and managing Kubernetes clusters that run in your own data centers. + Its goal is to include full lifecycle management of multiple EKS Distro clusters that are capable of operating completely independently of any AWS services. +--- + +The tenets of the EKS Anywhere (EKS-A) project are: + +- **The Source**: The goal of the EKS Anywhere is to be the Kubernetes source for EKS and EKS Anywhere +- **Simple**: Make using a Kubernetes distribution simple and boring (reliable and secure). +- **Opinionated Modularity**: Provide opinionated defaults about the best components to include with Kubernetes, but give customers the ability to swap them out +- **Open**: Provide open source tooling backed, validated and maintained by Amazon +- **Ubiquitous**: Enable customers and partners to integrate a Kubernetes distribution in the most common tooling. +- **Stand Alone**: Provided for use anywhere without AWS dependencies +- **Better with AWS**: Enable AWS customers to easily adopt additional AWS services diff --git a/docs/content/en/docs/community/_index.md b/docs/content/en/docs/community/_index.md new file mode 100644 index 000000000000..35aabb4b3350 --- /dev/null +++ b/docs/content/en/docs/community/_index.md @@ -0,0 +1,16 @@ +--- +title: Community +weight: 90 +description: > + Guidelines for community contribution +--- + +We work hard to provide a high-quality Kubernetes installer for EKS, +and we greatly value feedback and contributions from our community. Please +review the [contribution guidelines](contributing.md) before +submitting any [issues](https://github.com/aws/eks-anywhere/issues) or +[pull requests](https://github.com/aws/eks-anywhere/pulls) to ensure we have +all the necessary information to respond to your bug report or contribution +effectively. If you have a concern with a security vulnerability, please +review our [reporting a vulnerability policy](https://github.com/aws/eks-anywhere/security/policy). + diff --git a/docs/content/en/docs/community/code_of_conduct.md b/docs/content/en/docs/community/code_of_conduct.md new file mode 100644 index 000000000000..7bd3b650c014 --- /dev/null +++ b/docs/content/en/docs/community/code_of_conduct.md @@ -0,0 +1,13 @@ +--- +title: "Code of Conduct" +weight: 30 +description: > + Details on the project code of conduct +--- + +This project has adopted the +[Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information, see the +[Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. + diff --git a/docs/content/en/docs/community/contributing.md b/docs/content/en/docs/community/contributing.md new file mode 100644 index 000000000000..9c22e63f0e43 --- /dev/null +++ b/docs/content/en/docs/community/contributing.md @@ -0,0 +1,88 @@ +--- +title: "Contributing Guidelines" +weight: 20 +description: > + How to best contribute to the project +--- + +Thank you for your interest in contributing to the project. Whether it's +a bug report, new feature, correction, or additional documentation, we +greatly value feedback and contributions from the community. + +Please read through this document before submitting any issues or pull +requests to ensure we have all the necessary information to respond +to your bug report or contribution effectively. + +## Reporting Bugs/Feature Requests + +We welcome you to use the GitHub issue tracker to report bugs or suggest +features. + +When filing an issue, please check +[existing open](https://github.com/aws/eks-anywhere/issues) or +[recently closed](https://github.com/aws/eks-anywhere/issues?q=is%3Aissue+is%3Aclosed), +issues to make sure somebody else hasn't already reported the issue. Please +try to include as much information as you can. Details like these are +incredibly useful: + +* A reproducible test case or series of steps +* The version of the code being used +* Any modifications you've made relevant to the bug +* Anything unusual about your environment or deployment + +## Contributing via Pull Requests +Contributions via pull requests are much appreciated. Before sending us a +pull request, please ensure that: + +1. You are working against the latest source on the *main* branch. +2. You check existing open, and recently merged, pull requests to make sure +someone else hasn't addressed the problem already. +3. You open an issue to discuss any significant work - we would hate for your +time to be wasted. + +To send us a pull request, please: + +1. Fork the repository. +2. Modify the source; please focus on the specific change you are contributing. +If you also reformat all the code, it will be hard for us to focus on your change. +3. Ensure local tests pass. +4. Commit to your fork using clear commit messages. +5. Send us a pull request, answering any default questions in the pull request +interface. +6. Pay attention to any automated CI failures reported in the pull request +and stay involved in the conversation. + +GitHub provides additional documentation on +[forking a repository](https://help.github.com/articles/fork-a-repo/) and +[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). + +## Finding contributions to work on +Looking at the existing issues is a great way to find something to contribute on. +The project uses the default GitHub issue labels +(enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any +['help wanted'](https://github.com/aws/eks-anywhere/labels/help%20wanted) +issues is a great place to start. + +## Code of Conduct +This project has adopted the +[Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information, see the +[Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. + +## Security issue notifications +If you discover a potential security issue in this project, we ask that you +notify AWS/Amazon Security via our +[vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). +Please do **not** create a public GitHub issue. + +## Licensing + +See the +[LICENSE](https://github.com/aws/eks-anywhere/blob/main/LICENSE) +file for the project's licensing. We will ask you to confirm the licensing +of your contribution. + +We may ask you to sign a +[Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) +for larger changes. diff --git a/docs/content/en/docs/community/governance.md b/docs/content/en/docs/community/governance.md new file mode 100644 index 000000000000..e3535e594d07 --- /dev/null +++ b/docs/content/en/docs/community/governance.md @@ -0,0 +1,43 @@ +--- +title: "Project governance" +weight: 40 +description: > + Roles and responsibilities of the project +--- + + +This document lays out the guidelines under which the +EKS Anywhere (EKS-A) project will be governed. The goal +is to make sure that the roles and responsibilities +are well-defined and clarify how decisions are made. + +## Roles + +In the context of EKS-A, we consider the following roles: + +* __Users__ ... everyone using EKS-A, typically willing to provide +feedback on EKS-A by proposing features and/or filing issues. +* __Contributors__ ... everyone contributing code, documentation, +examples, testing infra, and participating in feature proposals as +well as design discussions. +* __Maintainers__ ... are responsible for engaging with and assisting +contributors to iterate on the contributions until it reaches acceptable +quality. Maintainers can decide whether the contributions can be accepted +into the project or rejected. + +## Communication + +The primary mechanism for communication will be via the `#provider-aws` +channel on the Kubernetes Slack community. All features and bug fixes will be +tracked as issues in GitHub. All decisions will be documented in GitHub issues. + +In the future, we may consider using a public mailing list, which can be better +archived. + +## Release Management + +The release process will be governed by AWS and will coincide with the release of EKS. + +## Roadmap Planning + +Maintainers will share roadmap and release versions as milestones in GitHub. diff --git a/docs/content/en/docs/concepts/_index.md b/docs/content/en/docs/concepts/_index.md new file mode 100644 index 000000000000..04ddebcd36e7 --- /dev/null +++ b/docs/content/en/docs/concepts/_index.md @@ -0,0 +1,12 @@ +--- +title: "Concepts" +linkTitle: "Concepts" +weight: 40 +description: > + The Concepts section will describe the components and overall architecture of EKS Anywhere. +--- + +{{% pageinfo %}} +Most of the content of this section will cover how EKS Anywhere deploys, upgrades and otherwise manages Kubernetes clusters. It will point to Kubernetes documentation for specifics on how Kuberntes itself works. +{{% /pageinfo %}} + diff --git a/docs/content/en/docs/concepts/clusterworkflow.md b/docs/content/en/docs/concepts/clusterworkflow.md new file mode 100644 index 000000000000..e42db2c01544 --- /dev/null +++ b/docs/content/en/docs/concepts/clusterworkflow.md @@ -0,0 +1,10 @@ +--- +title: "Cluster creation workflow" +linkTitle: "Cluster creation workflow" +weight: 5 +date: 2017-01-05 +description: > + Explanation of the process of creating an EKS-A cluster +--- + + diff --git a/docs/content/en/docs/concepts/eksafeatures.md b/docs/content/en/docs/concepts/eksafeatures.md new file mode 100644 index 000000000000..e0bda61dc15b --- /dev/null +++ b/docs/content/en/docs/concepts/eksafeatures.md @@ -0,0 +1,42 @@ +--- +title: "Compare EKS-A and EKS" +linkTitle: "Compare EKS-A and EKS" +weight: 4 +date: 2017-01-05 +description: > + Comparing Amazon EKS-A features to Amazon EKS +--- + +Amazon EKS Anywhere is a new deployment option for Amazon EKS +that enables you to easily create and operate Kubernetes clusters on-premises. +EKS Anywhere provides an installable software package for creating and operating Kubernetes clusters on-premises +and automation tooling for cluster lifecycle support. +To learn more, see [EKS Anywhere](https://aws.amazon.com/eks/eks-anywhere/). + + +Amazon Elastic Kubernetes Service (Amazon EKS) is a managed Kubernetes service that makes it easy for you to run Kubernetes on AWS and on-premises. +Amazon EKS is certified Kubernetes conformant, so existing applications that run on upstream Kubernetes are compatible with Amazon EKS. +To learn more about Amazon EKS, see [Amazon Elastic Kubernetes Service](https://aws.amazon.com/eks/). + + +### Comparing Amazon EKS Anywhere to Amazon EKS + +| Feature | Amazon EKS Anywhere | Amazon EKS | +|-------------------------------|--------------------------------------|---------------------------------| +| Control plane management | Managed by customer | Managed by AWS | +| Control plane location | Customer's datacenter | AWS cloud | +| Supported Operating Systems | Ubuntu: 20.04, BottleRocket | Linux x86, ARM, and Windows Server operating system distributions | +| Cluster Updates | CLI (Flux supported rolling update for data plane, Manual update for control plane) | Managed in-place update process for control plane and data plane | +| Networking and Security | Cilium CNI | Amazon VPC CNI, Other compatible 3rd party CNI plugins | +| Console | Connect to EKS console using EKS Connector (Public Preview) | EKS Console | +| GitOps | Flux controller | Flux controller | +| Deployment Types | EKS-A clusters on VMware vSphere | Amazon EC2, AWS Fargate | +| Hardware (Server, Network Equiment, Storage, etc.) | Managed by customer | Managed by AWS | +| Load Balancer | [3rd party partner solutions](link) | Elastic Load Balancing including Application Load Balancer (ALB), Network Load Balancer (NLB), and Classic Load Balancer | +| Support | AWS Support (EKS-A Subscription required) | AWS Support | +| Pricing | Free to download, Annual subscription for AWS Support | Hourly pricing per cluster | +| Serverless | Not supported | Amazon EKS on AWS Fargate | +| Logging and monitoring | [3rd party software](link) | CloudWatch, CloudTrail, 3rd party software (link) | +| Service mesh | [3rd party partner solutions](link) | AWS App Mesh, 3rd party partner solutions (link) | +| Infrastructure-as-Code | [3rd party partner solutions](link) | AWS CloudFormation, 3rd party partner solutions (link) | +| Command Line Interface (CLI) | eksctl (OSS command line tool) | eksctl (OSS command line tool) | diff --git a/docs/content/en/docs/getting-started/_index.md b/docs/content/en/docs/getting-started/_index.md new file mode 100644 index 000000000000..e9c1c56e00a3 --- /dev/null +++ b/docs/content/en/docs/getting-started/_index.md @@ -0,0 +1,39 @@ +--- +title: Getting started +main_menu: true +weight: 20 +no_list: true +card: + name: setup + weight: 20 + anchors: + - anchor: "#local-environment" + title: Local environment + - anchor: "#production-environment" + title: Production environment +description: > + The Getting started section includes information on starting to set up your own EKS-A local or production environment. +--- + + + +EKS Anywhere can be deployed as a simple, unsupported local environment or as a production-quality environment that can become a supported on-premises Kubernetes platform. +This section lists the different ways to set up and run EKS Anywhere. +When you install EKS Anywhere, choose an installation type based on: ease of maintenance, security, control, available resources, and expertise required to operate and manage a cluster. + + + +## Install EKS Anywhere + +To create an EKS Anywhere cluster you'll need to download the command line tool that is used to create and manage a cluster. +You can install it using the [installation guide]({{< relref "beta-install" >}}) + +## Local environment + +If you just want to try out EKS Anywhere, there is a single-system method for installing and running EKS Anywhere using Docker. +See [EKS Anywhere local environment]({{< relref "local-environment" >}}). + +## Production environment + +When evaluating a solution for a production environment +consider deploying EKS Anywhere on [vSphere]({{< relref "production-environment" >}}). diff --git a/docs/content/en/docs/getting-started/beta-install/_index.md b/docs/content/en/docs/getting-started/beta-install/_index.md new file mode 100644 index 000000000000..45bd8ef1ab3a --- /dev/null +++ b/docs/content/en/docs/getting-started/beta-install/_index.md @@ -0,0 +1,65 @@ +--- +title: Install EKS Anywhere for Beta +weight: 5 +--- + +To create an EKS Anywhere (EKS-A) cluster you will need [`eksctl`](https://eksctl.io) and the `eks-a` binaries. +These binaries are provided as part of the beta package. +This will let you create a cluster in multiple providers for local development or production workloads. + +### Local machine prerequisites + +- Docker 20.x.x +- Operating System: + - Mac OS (10.15) or + - Ubuntu (20.04.2 LTS) +- 4 CPU cores +- 16GB memory +- 30GB free disk space + +> **_NOTE:_** If you are using Ubuntu, use the installation instructions below to install Docker and not the Snap installation. + +### Set up your Ubuntu administrative machine + +All of these commands should be run from your administrative machine + +```bash +sudo apt update +sudo apt install -y docker.io +sudo usermod -a -G docker $USER +wget https://distro.eks.amazonaws.com/kubernetes-1-21/releases/4/artifacts/kubernetes/v1.21.2/bin/linux/amd64/kubectl +mkdir -p $HOME/bin +chmod +x kubectl +mv kubectl $HOME/bin/ +echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc +``` + +Now you need to log out and log back into the system to get the correct group permissions and path. + +### Install EKS Anywhere + +To install the `eksctl` and `eks-a` commands you can extract the pre-built binaries from the provided archive. + +Give the binaries execute permission and move them into your `$HOME/bin` folder. + +```bash +chmod +x ./eksctl +chmod +x ./eks-a +mv ./eksctl $HOME/bin/ +mv ./eks-a $HOME/bin/ +``` + +### Verify installation + +You can verify your installed version with + +```bash +eksctl anywhere version +``` + +## Deploy a cluster + +Once you have the tools installed you can deploy a local cluster or production cluster in the next steps. + +* [Create local cluster](../local-environment/) +* [Create production cluster](../production-environment/) diff --git a/docs/content/en/docs/getting-started/install/_index.md b/docs/content/en/docs/getting-started/install/_index.md new file mode 100644 index 000000000000..503d3397880f --- /dev/null +++ b/docs/content/en/docs/getting-started/install/_index.md @@ -0,0 +1,88 @@ +--- +title: Install EKS Anywhere (under construction) +weight: 10 +toc_hide: true +hide_summary: true +--- + +To create an EKS Anywhere (EKS-A) cluster you will need [`eksctl`](https://eksctl.io) and the `eksctl-anywhere` plugin. +This will let you create a cluster in multiple providers for local development or production workloads. + +### Local machine prerequisites + +- Docker 20.x.x +- Mac OS (10.15) / Ubuntu (20.04.2 LTS) +- 4 CPU cores +- 16GB memory +- 30GB free disk space + +> **_NOTE:_** If you are using Ubuntu use the [Docker CE](https://docs.docker.com/engine/install/ubuntu/) installation instructions to install Docker and not the Snap installation. + +### Install EKS Anywhere + +#### Via Homebrew (macOS and Linux) + +You can install `eksctl` and `eksctl-anywhere` with [homebrew](http://homebrew.sh/). + +```bash +brew install aws/tap/eks-anywhere +``` + +#### Manually (macOS and Linux) + +Install the latest release of `eksctl`. + +```bash +curl "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" \ + --silent --location \ + | tar xz -C /tmp +sudo mv /tmp/eksctl /usr/local/bin/ +``` + +Install the `eksctl-anywhere` plugin. + +```bash +curl "https://github.com/aws/eks-anywhere/releases/latest/download/eksctl-anywhere_$(uname -s)_amd64.tar.gz" \ + --silent --location \ + | tar xz -C /tmp +sudo mv /tmp/eksctl-anywhere /usr/local/bin/ +``` + +### (Optional) Install additional tools + +There are some additional tools you may want for your EKS-A clusters. +The EKS Distro project publishes some additional binaries and EKS-A bundles them for usage. + +This brew formula includes + +* eksctl +* eksctl-anywhere +* kubectl +* aws-iam-authenticator + +```bash +brew install aws/tap/eks-anywhere-bundle +``` + +### Upgrade eksctl-anywhere + +If you installed `eksctl-anywhere` via homebrew you can upgrade the binary with + +```bash +brew update +brew upgrade eksctl-anywhere +``` + +If you installed `eksctl-anywhere` manually you should follow the installation steps to download the latest release. +You can verify your installed version with + +```bash +eksctl anywhere version +``` + +## Deploy a cluster + +Once you have the tools installed you can deploy a local cluster or production cluster in the next steps. + +* [Create local cluster](../local-environment/) +* [Create production cluster](../production-environment/) \ No newline at end of file diff --git a/docs/content/en/docs/getting-started/local-environment/_index.md b/docs/content/en/docs/getting-started/local-environment/_index.md new file mode 100644 index 000000000000..764f9b311c92 --- /dev/null +++ b/docs/content/en/docs/getting-started/local-environment/_index.md @@ -0,0 +1,79 @@ +--- +title: Create local cluster +weight: 20 +--- + +## EKS Anywhere docker provider deployments + +EKS Anywhere supports a Docker provider for *development and testing use cases only.* +This allows you to try EKS-A on your local system before deploying to a supported provider. + +To install the EKS-A binaries and see system requirements please follow the [installation guide]({{< relref "../install" >}}). + +## Steps + + +1. Generate a cluster config + ```bash + CLUSTER_NAME=dev-cluster + eksctl anywhere generate clusterconfig $CLUSTER_NAME \ + --provider docker > $CLUSTER_NAME.yaml + ``` + +1. Create a cluster + + ```bash + eksctl anywhere create cluster -f $CLUSTER_NAME.yaml + ``` + Example command output + ``` + Performing setup and validations + ✅ validation succeeded {"validation": "docker Provider setup is valid"} + Creating new bootstrap cluster + Installing cluster-api providers on bootstrap cluster + Provider specific setup + Creating new workload cluster + Installing networking on workload cluster + Installing cluster-api providers on workload cluster + Moving cluster management from bootstrap to workload cluster + Installing EKS-A custom components (CRD and controller) on workload cluster + Creating EKS-A CRDs instances on workload cluster + Installing AddonManager and GitOps Toolkit on workload cluster + GitOps field not specified, bootstrap flux skipped + Deleting bootstrap cluster + 🎉 Cluster created! + ``` + +1. Use the cluster + + Once the cluster is created you can use it with the generated `KUBECONFIG` file in your local directory + + ```bash + export KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig + kubectl get ns + ``` + Example command output + ``` + NAME STATUS AGE + capd-system Active 21m + capi-kubeadm-bootstrap-system Active 21m + capi-kubeadm-control-plane-system Active 21m + capi-system Active 21m + capi-webhook-system Active 21m + cert-manager Active 22m + default Active 23m + eksa-system Active 20m + kube-node-lease Active 23m + kube-public Active 23m + kube-system Active 23m + ``` + + You can now use the cluster like you would any Kubernetes cluster. + Deploy the test application with: + + ```bash + kubectl apply -f "https://anywhere.eks.amazonaws.com/manifests/hello-eks-a.yaml" + ``` + + Verify the test application in the [deploy test application section]({{< relref "../../tasks/workload/test-app" >}}). + See the [Cluster management]({{< relref "../../tasks/cluster" >}}) section with more information on common operational tasks like scaling and deleting the cluster. diff --git a/docs/content/en/docs/getting-started/production-environment/_index.md b/docs/content/en/docs/getting-started/production-environment/_index.md new file mode 100644 index 000000000000..5e78b4eeee86 --- /dev/null +++ b/docs/content/en/docs/getting-started/production-environment/_index.md @@ -0,0 +1,126 @@ +--- +title: "Create production cluster" +weight: 40 +--- + +EKS Anywhere supports a vSphere provider for production grade EKS Anywhere deployments. +The purpose of this doc is to walk you through getting set-up with EKS Anywhere (EKS-A). +EKS-A allows you to provision and manage Amazon EKS on your own infrastructure. + +## Prerequisite Checklist + +EKS Anywhere needs to be run on an administrative machine that has certain [machine +requirements]({{< relref "../install" >}}). +An EKS Anywhere deployment will also require the availability of certain +[resources from your VMware vSphere deployment]({{< relref "../../reference/clusterspec/vsphere" >}}). + +To run EKS Anywhere, you will need the following: + +## Steps + + +1. Generate a cluster config + ```bash + CLUSTER_NAME=prod + eksctl anywhere generate clusterconfig $CLUSTER_NAME \ + --provider vsphere > eksa-cluster.yaml + ``` + + A production grade EKS-A cluster should be made with at least three control plane nodes and three worker nodes + for high availability and rolling upgrades.: + ``` + controlPlaneConfiguration: + count: 3 + endpoint: + host: 198.18.100.79 + machineGroupRef: + kind: VSphereMachineConfig + name: prod-control-plane + workerNodeGroupConfigurations: + - count: 3 + machineGroupRef: + kind: VSphereMachineConfig + name: prod-data-plane + ``` + + Further information about the values in the `eksa-cluster.yaml` can be found in the [cluster specification + reference]({{< relref "../../reference/clusterspec/vsphere.md" >}}) + +1. Set Credential Environment Variables + + Before you create a cluster, you will need to set and export these environment variables for your vSphere user + name and password. Make sure you use single quotes around the values so that your shell does not interpret the values: + + ```bash + export VSPHERE_USERNAME='billy' + export VSPHERE_PASSWORD='t0p$ecret' + ``` + +1. Create a cluster + + After you have created your `eks-cluster.yaml` and set your credential environment variables, you will be ready + to create a cluster: + ```bash + eksctl anywhere create cluster -f eksa-cluster.yaml + ``` + Example command output + ``` + Performing setup and validations + ✅ Connected to server + ✅ Authenticated to vSphere + ✅ datacenter validated + ✅ datastore validated + ✅ folder validated + ✅ resource pool validated + ✅ network validated + ✅ Template validated + ✅ validation succeeded {"validation": "vsphere Provider setup is valid"} + Creating new bootstrap cluster + Installing cluster-api providers on bootstrap cluster + Provider specific setup + Creating new workload cluster + Installing networking on workload cluster + Installing storage class on workload cluster + Installing cluster-api providers on workload cluster + Moving cluster management from bootstrap to workload cluster + Installing EKS-A custom components (CRD and controller) on workload cluster + Creating EKS-A CRDs instances on workload cluster + Installing AddonManager and GitOps Toolkit on workload cluster + GitOps field not specified, bootstrap flux skipped + Deleting bootstrap cluster + 🎉 Cluster created! + ``` + +1. Use the cluster + + Once the cluster is created you can use it with the generated `KUBECONFIG` file in your local directory + + ```bash + export KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig + kubectl get ns + ``` + Example command output + ``` + NAME STATUS AGE + capi-kubeadm-bootstrap-system Active 4m26s + capi-kubeadm-control-plane-system Active 4m19s + capi-system Active 4m36s + capi-webhook-system Active 4m46s + capv-system Active 4m4s + cert-manager Active 5m40s + default Active 12m + eksa-system Active 3m7s + kube-node-lease Active 12m + kube-public Active 12m + kube-system Active 12m + ``` + + You can now use the cluster like you would any Kubernetes cluster. + Deploy the test application with: + + ```bash + kubectl apply -f "https://anywhere.eks.amazonaws.com/manifests/hello-eks-a.yaml" + ``` + + Verify the test application in the [deploy test application section]({{< relref "../../tasks/workload/test-app" >}}). + See the [Cluster management]({{< relref "../../tasks/cluster" >}}) section with more information on common operational tasks like scaling and deleting the cluster. diff --git a/docs/content/en/docs/overview/_index.md b/docs/content/en/docs/overview/_index.md new file mode 100644 index 000000000000..6c40d2a802e6 --- /dev/null +++ b/docs/content/en/docs/overview/_index.md @@ -0,0 +1,31 @@ +--- +title: "Overview" +linkTitle: "Overview" +weight: 10 +description: > + Provides an overview of EKS Anywhere +--- + +EKS Anywhere will use the `eksctl` executable to create a Kubernetes cluster in your environment. +Currently it allows you to create and delete clusters in a vSphere environment. +You can run cluster create and delete commands from an Ubuntu or Mac administrative machine. + +To create a cluster you will need to create a specification file which includes all of your vSphere details and information about your EKS cluster. +The `eksctl anywhere create cluster` command will create a temporary bootstrap cluster on your admin machine which will be used to create a workload cluster in vSphere. +Once the workload cluster is created the cluster management resources will be moved to your workload cluster and the local bootstrap cluster will be deleted. + +Once your workload cluster is created a KUBECONFIG file will be stored on your admin machine with RBAC admin permissions for the workload cluster. +You’ll be able to use that file with `kubectl` to set up and deploy workloads. +Here’s a diagram that explains the process visually. + +![EKS-A create cluster overview](/images/eks-a_create_cluster.png) + +The delete process is similar to the create process. + +![EKS-A delete cluster overview](/images/eks-a_delete_cluster.png) + + +Next steps: +* [Getting Started](/docs/getting-started/) +* [Examples](/docs/examples/) + diff --git a/docs/content/en/docs/reference/_index.md b/docs/content/en/docs/reference/_index.md new file mode 100644 index 000000000000..94aa2c4870d8 --- /dev/null +++ b/docs/content/en/docs/reference/_index.md @@ -0,0 +1,7 @@ +--- +title: "Reference" +linkTitle: "Reference" +weight: 80 +description: > + Reference documents for EKS Anywhere configuration +--- diff --git a/docs/content/en/docs/reference/clusterspec/_index.md b/docs/content/en/docs/reference/clusterspec/_index.md new file mode 100644 index 000000000000..aba60b3d0ae5 --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/_index.md @@ -0,0 +1,7 @@ +--- +title: "Config" +linkTitle: "Config" +weight: 10 +description: > + Config reference for EKS-A clusters +--- \ No newline at end of file diff --git a/docs/content/en/docs/reference/clusterspec/etcd.md b/docs/content/en/docs/reference/clusterspec/etcd.md new file mode 100644 index 000000000000..75bdf3e07f2e --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/etcd.md @@ -0,0 +1,64 @@ +--- +title: "etcd configuration reference" +linkTitle: "etcd" +weight: 20 +description: > + EKS-A cluster yaml etcd specification reference +--- + +### Unstacked etcd topology (recommended) +There are two types of etcd topologies for configuring a Kubernetes cluster: + +* Stacked: The etcd members and control plane components are colocated (run on the same node/machines) +* Unstacked/External: With the unstacked or external etcd topology, etcd members have dedicated machines and are not colocated with control plane components + +The unstacked etcd topology is recommended for a HA cluster for the following reasons: + +* External etcd topology decouples the control plane components and etcd member. So if a control plane-only node fails, or if there is a memory leak in a component like kube-apiserver, it won't directly impact an etcd member. +* Etcd is resource intensive, so it is safer to have dedicated nodes for etcd, since it could use more disk space or higher bandwidth. Having a separate etcd cluster for these reasons could ensure a more resilient HA setup. + +EKS-A supports both topologies. In order to configure a cluster with the unstacked/external etcd topology, you need to configure your cluster by updating the configuration file before creating the cluster. This is a generic template with detailed descriptions below for reference: +```yaml +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: my-cluster-name +spec: + clusterNetwork: + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 + cni: "cilium" + controlPlaneConfiguration: + count: 1 + endpoint: + host: "" + machineGroupRef: + kind: VSphereMachineConfig + name: my-cluster-name-cp + datacenterRef: + kind: VSphereDatacenterConfig + name: my-cluster-name + # etcd configuration + externalEtcdConfiguration: + count: 3 + kubernetesVersion: "1.19" + workerNodeGroupConfigurations: + - count: 1 + machineGroupRef: + kind: VSphereMachineConfig + name: my-cluster-name +``` +#### externalEtcdConfiguration (under Cluster) +This field accepts any configuration parameters for running external etcd. + +#### count (required) +This determines the number of etcd members in the cluster. The recommended number is 3. + +**NOTE** + +* Currently the etcd machines use the same values for the VSphere machine configuration as the control plane machines. This includes all the fields you set on the VSphereMachineConfig object for control plane machines such as OS Family, memory, disk size, CPU etc. + diff --git a/docs/content/en/docs/reference/clusterspec/gitops.md b/docs/content/en/docs/reference/clusterspec/gitops.md new file mode 100644 index 000000000000..1519f5e246c1 --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/gitops.md @@ -0,0 +1,82 @@ +--- +title: "GitOpsConfig reference" +linkTitle: "GitOps" +weight: 80 +description: > + Configuration reference for GitOps cluster management. +--- + +# GitOps Support (Optional) +EKS-A can create clusters that supports GitOps configuration managment with Flux. +In order to add GitOps support, you need to configure your cluster by updating the configuration file before creating the cluster. +This is a generic template with detailed descriptions below for reference: +```yaml +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: my-cluster-name +spec: + ... + #GitOps Support + gitOpsRef: + name: my-gitops + kind: GitOpsConfig +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: GitOpsConfig +metadata: + name: my-gitops +spec: + flux: + github: + personal: true + repository: myClusterGitopsRepo + owner: myGithubUsername + fluxSystemNamespace: "" + clusterConfigPath: "" +``` + +### GitOps Configuration Spec Details +### __flux__ (required) +* __Description__: our supported gitops provider is `flux`. + This is the only supported value. +* __Type__: object + +### Flux Configuration Spec Details +### __github__ (required) +* __Description__: `github` is the only currently supported git provider. + This defines your github configuration to be used by EKS-A and flux. +* __Type__: object + +### github Configuration Spec Details +#### __repository__ (required) +* __Description__: The name of the repository where we will store your cluster configuration, and sync it to the cluster. + If the repository exists, we will clone it from the git provider; if it does not exist, we will create it for you. +* __Type__: string + +#### __owner__ (required) +* __Description__: The owner of the git repository; either a github username or github organization name. + The Personal Access Token used must belong to the `owner` if this is a `personal` repository, or have permissions over the organization if this is not a `personal` repository. +* __Type__: string + +#### __personal__ (optional) +* __Description__: Is the repository a personal or organization repository? + If personal, this value is `true`; otherwise, `false`. + If using an organizational repository (e.g. `personal` is `false`) the `owner` field will be used as the `organization` when authenticating to github.com +* __Default__: `true` +* __Type__: boolean + +#### __clusterConfigPath__ (optional) +* __Description__: The path relative to the root of the git repository where EKS-A will store the cluster configuration files. +* __Default__: `clusters/$CLUSTER_NAME` +* __Type__: string + +#### __fluxSystemNamespace__ (optional) +* __Description__: Namespace in which to install the gitops components in your cluster. +* __Default__: `flux-system`. +* __Type__: string + +#### __branch__ (optional) +* __Description__: The branch to use whe commiting the configuration. +* __Default__: `main` +* __Type__: string \ No newline at end of file diff --git a/docs/content/en/docs/reference/clusterspec/oidc.md b/docs/content/en/docs/reference/clusterspec/oidc.md new file mode 100644 index 000000000000..f8de6ee0623c --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/oidc.md @@ -0,0 +1,71 @@ +--- +title: "OIDC reference" +linkTitle: "OIDC" +weight: 30 +description: > + EKS-A cluster yaml specification OIDC reference +--- + + +## OIDC support (optional) +EKS-A can create clusters that support api server OIDC authentication. In order to add OIDC support, you need to configure your cluster by updating the configuration file before creating the cluster. This is a generic template with detailed descriptions below for reference: +```yaml +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: my-cluster-name +spec: + ... + # OIDC support + identityProviderRefs: + - kind: OIDCConfig + name: my-cluster-name +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: OIDCConfig +metadata: + name: my-cluster-name +spec: + clientId: "" + groupsClaim: "" + groupsPrefix: "" + issuerUrl: "https://x" + requiredClaims: + - claim: "" + value: "" + usernameClaim: "" + usernamePrefix: "" +``` +### identityProviderRefs (Under Cluster) +List of identity providers you want configured for the Cluster. Right now, only 1 provider of type `OIDCConfig` is supported. +This would include a reference to the `OIDCConfig` object with the configuration below. + +### clientId (required) +* Description: ClientId defines the client ID for the OpenID Connect client +* Type: string +### groupsClaim +* Description: GroupsClaim defines the name of a custom OpenID Connect claim for specifying user groups +* Type: string +### groupsPrefix +* Description: GroupsPrefix defines a string to be prefixed to all groups to prevent conflicts with other authentication strategies +* Type: string +### issuerUrl (required) +* Description: IssuerUrl defines the URL of the OpenID issuer, only HTTPS scheme will be accepted +* Type: string +### requiredClaims +List of RequiredClaim objects listed below. Only one is supported at this time. + +### requiredClaims[0] +* Description: RequiredClaim defines a key=value pair that describes a required claim in the ID Token + * claim + * type: string + * value + * type: string +* Type: object +### usernameClaim +* Description: UsernameClaim defines the OpenID claim to use as the user name. Note that claims other than the default ('sub') is not guaranteed to be unique and immutable +* Type: string +### usernamePrefix +* Description: UsernamePrefix defines a string to be prefixed to all usernames. If not provided, username claims other than 'email' are prefixed by the issuer URL to avoid clashes. To skip any prefixing, provide the value '-'. +* Type: string + diff --git a/docs/content/en/docs/reference/clusterspec/proxy.md b/docs/content/en/docs/reference/clusterspec/proxy.md new file mode 100644 index 000000000000..a5a4dbbf8590 --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/proxy.md @@ -0,0 +1,50 @@ +--- +title: "Proxy configuration reference" +linkTitle: "Proxy" +weight: 90 +description: > + EKS-A cluster yaml specification proxy configuration reference +--- + +## Proxy support (optional) +You can configure EKS-A to use a proxy to connect to the Internet. This is the +generic template with proxy configuration for your reference: +```yaml +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: my-cluster-name +spec: + ... + proxyConfiguration: + httpProxy: http-proxy-ip:port + httpsProxy: https-proxy-ip:port + noProxy: + - list of no proxy endpoints +``` +## Proxy Configuration Spec Details +### __proxyConfiguration__ (required) +* __Description__: top level key; required to use proxy. +* __Type__: object + +### __httpProxy__ (required) +* __Description__: HTTP proxy to use to connect to the internet; must be in the format IP:port +* __Type__: string +* __Example__: ```httpProxy: 192.168.0.1:3218``` + +### __httpsProxy__ (required) +* __Description__: HTTPS proxy to use to connect to the internet; must be in the format IP:port +* __Type__: string +* __Example__: ```httpsProxy: 192.168.0.1:3218``` + +### __noProxy__ (optional) +* __Description__: list of endpoints that should not be routed through the proxy; can be an IP, cidr block, or a domain name +* __Type__: list of strings +* __Example__ +```yaml + noProxy: + - localhost + - 192.168.0.1 + - 192.168.0.0/16 + - .example.com +``` diff --git a/docs/content/en/docs/reference/clusterspec/vsphere.md b/docs/content/en/docs/reference/clusterspec/vsphere.md new file mode 100644 index 000000000000..a464759425af --- /dev/null +++ b/docs/content/en/docs/reference/clusterspec/vsphere.md @@ -0,0 +1,220 @@ +--- +title: "vSphere configuration reference" +linkTitle: "vSphere" +weight: 10 +description: > + Full EKS-A configuration reference for a VMware vSphere cluster. +--- + +This is a generic template with detailed descriptions below for reference + +```yaml +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: Cluster +metadata: + name: my-cluster-name +spec: + clusterNetwork: + cni: "cilium" + pods: + cidrBlocks: + - 192.168.0.0/16 + services: + cidrBlocks: + - 10.96.0.0/12 + controlPlaneConfiguration: + count: 1 + endpoint: + host: "" + machineGroupRef: + kind: VSphereMachineConfig + name: my-cluster-machines + datacenterRef: + kind: VSphereDatacenterConfig + name: my-cluster-datacenter + externalEtcdConfiguration: + count: 3 + kubernetesVersion: "1.21" + workerNodeGroupConfigurations: + - count: 1 + machineGroupRef: + kind: VSphereMachineConfig + name: my-cluster-machines + +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereDatacenterConfig +metadata: + name: my-cluster-datacenter +spec: + datacenter: "" + server: "" + network: "" + insecure: + thumbprint: "" + +--- +apiVersion: anywhere.eks.amazonaws.com/v1alpha1 +kind: VSphereMachineConfig +metadata: + name: my-cluster-machines +spec: + diskGiB: + datastore: "" + folder: "" + numCPUs: + memoryMiB: + osFamily: "" + resourcePool: "" + storagePolicyName: "" + template: "" + users: + - name: "" + sshAuthorizedKeys: + - "" +``` + +## Cluster Fields + +The following additional optional configuration can also be included. + +* [OIDC]({{< relref "oidc.md" >}}) +* [etcd]({{< relref "etcd.md" >}}) +* [proxy]({{< relref "proxy.md" >}}) + +### name +Name of your cluster `my-cluster-name` in this example + +### clusterNetwork +Specific network configuration for your Kubernetes cluster. + +### clusterNetwork.cni +CNI plugin to be installed in the cluster. The only supported value at the moment is `cilium`. + +### clusterNetwork.pods.cidrBlocks[0] +Subnet used by pods in CIDR notation. Please note that only 1 custom pods CIDR block specification is permitted. + +### clusterNetwork.services.cidrBlocks[0] +Subnet used by services in CIDR notation. Please note that only 1 custom services CIDR block specification is permitted. + +### controlPlaneConfiguration +Specific control plane configuration for your Kubernetes cluster. + +### controlPlaneConfiguration.count +Number of control plane nodes + +### controlPlaneConfiguration.machineGroupRef +Refers to the Kubernetes object with vsphere specific configuration for your nodes. See `VSphereMachineConfig Fields` below. + +### controlPlaneConfiguration.endpoint.host +A unique IP you want to use for the control plane VM in your EKS Anywhere cluster. Choose an IP in your networks +range that does not conflict with other VMs. + +### workerNodeGroupsConfiguration +This takes in a list of node groups that you can define for your workers. Please note that at this time only 1 node group is permitted. + +### workerNodeGroupsConfiguration[0].count +Number of worker nodes + +### workerNodeGroupsConfiguration[0].machineGroupRef +Refers to the Kubernetes object with vsphere specific configuration for your nodes. See `VSphereMachineConfig Fields` below. + +### datacenterRef +Refers to the Kubernetes object with vsphere environment specific configuration. See `VSphereDatacenterConfig Fields` below. + +### kubernetesVersion +The Kubernetes version you want to use for your cluster. Supported values: `1.20`, `1.21` + +## VSphereDatacenterConfig Fields + +### datacenter +The vSphere datacenter to deploy the EKS Anywhere cluster on. For example `SDDC-Datacenter`. + +### network +The VM network to deploy your EKS Anywhere cluster on. + +### server +The vCenter server fully qualified domain name or IP address. If the server IP is used, the `thumbprint` must be set +or `insecure` must be set to true. + +### insecure +Set insecure to `true` if the vCenter server does not have a valid certificate. + +### thumbprint +The SHA1 thumbprint of the vCenter server certificate which is only required if you have a self signed certificate. + +There are several ways to obtain your vCenter thumbprint. The easiest way is if you have `govc` installed, you +can run: + +``` +govc about.cert -thumbprint -k +``` + +Another way is from the vCenter web UI, go to Administration/Certificate Management and click view details of the +machine certificate. The format of this thumbprint does not exactly match the format required though and you will +need to add `:` to separate each hexadecimal value. + +Another way to get the thumbprint is use this command with your servers certificate in a file named `ca.crt`: + +``` +openssl x509 -sha1 -fingerprint -in ca.crt -noout +``` + +If you specify the wrong thumbprint, an error message will be printed with the expected thumbprint. If no valid +certificate is being used, `insecure` must be set to true. + + +## VSphereMachineConfig Fields + +### memoryMiB +Size of RAM on virtual machines (optional) (Default: 8192) + +### numCPUs +Number of CPUs on virtual machines (optional) (Default: 2) + +### osFamily +Operating System on virtual machines (optional) (Default: ubuntu). Permitted values: ubuntu, bottlerocket + +### diskGiB +Size of disk on virtual machines if snapshots aren't included (optional) (Default: 25) + +### users +The users you want to configure to access your virtual machines. Only one is permitted at this time + +### users[0].name +The name of the user you want to configure to access your virtual machines through ssh. + +### users[0].sshAuthorizedKeys +The SSH public keys you want to configure to access your virtual machines through ssh (as described below). Only 1 is supported at this time. + +### users[0].sshAuthorizedKeys[0] +This is the SSH public key that will be placed in `authorized_keys` on all EKS Anywhere cluster VMs so you can ssh into +them. The user will be what is defined under name above. For example: + +``` +ssh -i @ +``` + +### template +The VM template to use for your EKS Anywhere cluster. This template was created when you +[imported the OVA file into vSphere](#import-an-ovaovf-template-to-vsphere). +This is a required field if you are using Bottlerocket OVAs. + +### datastore +The vSphere [datastore](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.storage.doc/GUID-3CC7078E-9C30-402C-B2E1-2542BEE67E8F.html) +to deploy your EKS Anywhere cluster on. + +### folder +The VM folder for your EKS anywhere cluster VMs. This allows you to organize your VMs. If the folder does not exist, +it will be created for you. If the folder is blank, the VMs will go in the root folder. + +### resourcePool +The vSphere [Resource pools](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.resmgmt.doc/GUID-60077B40-66FF-4625-934A-641703ED7601.html) +for your VMs in the EKS Anywhere cluster. Examples of resource pool values include: + +* If there is no resource pool: `//host//Resources` +* If there is a resource pool: `//host//Resources/` +* The wild card option `*/Resources` also often works. + +### storagePolicyName +The storage policy name associated with your vms. diff --git a/docs/content/en/docs/reference/eksctl/_index.md b/docs/content/en/docs/reference/eksctl/_index.md new file mode 100644 index 000000000000..73f64b615e25 --- /dev/null +++ b/docs/content/en/docs/reference/eksctl/_index.md @@ -0,0 +1,215 @@ +--- +title: "eksctl anywhere CLI reference" +linkTitle: "eksctl command" +weight: 12 +--- + +The `eksctl` CLI, with the EKS Anywhere plugin added, lets you create and manage EKS Anywhere clusters. +While a cluster is running, most EKS-A administration can be done using `kubectl` or other native Kubernetes tools. + +Use this page as a reference to useful `eksctl anywhere` command examples for working with EKS Anywhere clusters. +Available `eksctl anywhere` commands include: + +* `create cluster` To create an EKS-A cluster +* `delete cluster` To delete an EKS-A cluster +* `generate` [`clusterconfig` | `support-bundle` | `support-bundle-config`] To generate cluster and support configs +* `help` To get help information +* `upgrade` To upgrade a workload cluster +* `version` To get the EKS-A version + +Options used with multiple commands include: + +* `-h` or `--help` To get help for a command or subcommand +* `-v int` or `--verbosity int` To set log level verbosity from 0-9 +* `-f `filename` or `--filename filename` To identify the filename containing the cluster config +* `--force-cleanup` To force deletion of previously created bootstrap cluster +* `-w string` or `--w-config string` To identify the kubeconfig file when needed to create a support bundle or upgrade a cluster + +Other available options and arguments are listed with the command examples that follow. + +## `eksctl anywhere generate` + +With `eksctl anywhere generate`, you can output sets of cluster resources to create a new cluster +or troubleshoot an existing cluster. +Here are some examples. + +### `eksctl anywhere generate clusterconfig` + +Using `eksctl anywhere generate clusterconfig` you can generate a cluster configuration +for a specific provider (`-p` or `--provider`*provider_name*). Here are examples: + +Generate a configuration file to create an EKS-A cluster for a `vsphere` provider: + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere generate clusterconfig ${CLUSTER_NAME} -p vsphere > ${CLUSTER_NAME}.yaml +``` +Generate a configuration file to create an EKS-A cluster for a Docker provider: + +``` +export CLUSTER_NAME=docker01 +eksctl anywhere generate clusterconfig ${CLUSTER_NAME} -p docker > ${CLUSTER_NAME}.yaml +``` +Once you have generated the yaml configuration file, edit that file to add configuration information before you use the file to create your cluster. +See [local](../../getting-started/local-environment) and [production](../../getting-started/production-environment) cluster creation procedures for details. + +### `eksctl anywhere generate support-bundle-config` + +If you would like to customize your support bundle, you can generate a support bundle configuration file (`support-bundle-config`), +edit that file to choose the data you want to gather, +then gather the selected data into a support bundle (`support-bundle`). + +Generate a support bundle config file (then edit that file to select the log data you want to gather): + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere generate support-bundle-config > ${CLUSTER_NAME}_bundle_config.yaml +``` +### `eksctl anywhere generate support-bundle` + +Once you have a bundle config file, generate a support bundle from an existing EKS-A cluster. +Additional options available for this command include: + +* `--bundle-config string` To identify the bundle config file to use to generate the support bundle +* `--since string` To collect pod logs in the latest duration like 5s, 2m, or 3h. +* `--since-time string` To collect pod logs after a specific datetime(RFC3339) like 2021-06-28T15:04:05Z + +Here is an example: + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere generate support-bundle --bundle-config ${CLUSTER_NAME}_bundle_config.yaml \ + -w KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig \ + --since 2h -f ${CLUSTER_NAME}_bundle.yaml +``` + +The example just shown: + +* Uses `${CLUSTER_NAME}_bundle.yaml` as the file to hold the results +* Collects pod logs for the past two hours (2h) +* Identifies the bundle config file to use (`${CLUSTER_NAME}_bundle_config.yaml`) +* Identifies the `.kubeconfig` file to use for a workload cluster + +To change the command to generate a support bundle that gathers pod logs starting from a specific date (September 8, 2021) and time (1:27 PM): + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere generate support-bundle --bundle-config ${CLUSTER_NAME}_bundle_config.yaml \ + -w KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig \ + --since-time 2021-09-8T13:27:00Z 2h -f ${CLUSTER_NAME}_bundle.yaml +``` + +## `eksctl anywhere create cluster` + +Create an EKS-A cluster from a cluster configuration file you generated (and modified) earlier. +This example sets verbosity to most verbose (`-v 9`): + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere create cluster -v 9 -f ${CLUSTER_NAME}.yaml +``` + +See [local](../../getting-started/local-environment) and [production](../../getting-started/production-environment) cluster creation procedures for details. + +## `eksctl anywhere upgrade cluster` + +Upgrade an existing EKS-A cluster. +This example uses maximum verbosity and forces a cleanup of the previously created bootstrap cluster: + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere upgrade cluster -f ${CLUSTER_NAME}.yaml --force-cleanup -v9 \ + -w KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig +``` +For more information on this and other ways to upgrade a cluster, see [Upgrade cluster](../../tasks/cluster/cluster-upgrades). + +## `eksctl anywhere delete cluster` + +Delete an existing EKS-A cluster. +This example deletes all VMs and the forces the deletion of the previously created bootstrap cluster: + +``` +export CLUSTER_NAME=vsphere01 +eksctl anywhere delete cluster -f ${CLUSTER_NAME}.yaml \ + --force-cleanup \ + -w KUBECONFIG=${PWD}/${CLUSTER_NAME}/${CLUSTER_NAME}-eks-a-cluster.kubeconfig +``` +For more information on deleting a cluster, see [Delete cluster](../../tasks/cluster/cluster-delete). + +## `eksctl anywhere version` + +View the version of `eksctl anywhere`: + +``` +eksctl anywhere version +v0.5.0 +``` +## `eksctl anywhere help` + +Use `eksctl anywhere help` or the `-h` option to see general options or options specific to a particular set of commands. + +View general help information using `help`: + +``` +eksctl anywhere help + +Use eksctl anywhere to build your own self-managing cluster on your hardware with the best of Amazon EKS + +Usage: + eksctl anywhere [command] + +Available Commands: + create Create resources + delete Delete resources + generate Generate resources + help Help about any command + upgrade Upgrade resources + version Get the eksctl version + +Flags: + -h, --help help for eksctl + -v, --verbosity int Set the log level verbosity + +Use "eksctl [command] --help" for more information about a command. +... +``` + +Display help options for generating a support bundle: + +``` +eksctl anywhere generate support-bundle -h + +This command is used to create a support bundle to troubleshoot a cluster + +Usage: + eksctl anywhere generate support-bundle -f my-cluster.yaml [flags] + +Flags: + --bundle-config string Bundle Config file to use when generating support bundle + -f, --filename string Filename that contains EKS-A cluster configuration + -h, --help help for support-bundle + --since string Collect pod logs in the latest duration like 5s, 2m, or 3h. + --since-time string Collect pod logs after a specific datetime(RFC3339) like 2021-06-28T15:04:05Z + -w, --w-config string Kubeconfig file to use when creating support bundle for a workload cluster + +Global Flags: + -v, --verbosity int Set the log level verbosity + +``` +Display options for creating a cluster: + +``` +eksctl anywhere create cluster -h +This command is used to create workload clusters + +Usage: + eksctl anywhere create cluster [flags] + +Flags: + -f, --filename string Filename that contains EKS-A cluster configuration + --force-cleanup Force deletion of previously created bootstrap cluster + -h, --help help for cluster + +Global Flags: + -v, --verbosity int Set the log level verbosity +``` diff --git a/docs/content/en/docs/reference/faq/_index.md b/docs/content/en/docs/reference/faq/_index.md new file mode 100644 index 000000000000..4ab0ef7bfa2f --- /dev/null +++ b/docs/content/en/docs/reference/faq/_index.md @@ -0,0 +1,113 @@ +--- +title: "Frequently Asked Questions" +linkTitle: "FAQ" +weight: 10 +description: > + Frequently asked questions about EKS Anywhere +--- + +## AuthN / AuthZ authentication + +### How do my applications running on EKS-A authenticate with AWS services using IAM credentials? + +You can leverage the [IAM Role for Service Account (IRSA)](https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/) feature +and follow the [special instructions for DIY Kubernetes](https://github.com/aws/amazon-eks-pod-identity-webhook/blob/master/SELF_HOSTED_SETUP.md) +to enable AWS authentication. +This solution includes the following steps at a high level: + +1. Create a key pair for signing, and host your public key somewhere (e.g. S3). + +1. Configure your EKS Anywhere Kubernetes API server so it can issue and mount projected service account tokens in pods. + +1. Create an IAM role defining access to the target AWS services and annotate a service account with said IAM role. + +1. Finally, configure your pods by using the service account created in the previous step and assume the IAM role. + +The key pair solution above requires you to set up and maintain your key hosting (e.g. key rotation). +A solution that is currently in development will allow your IAM role credentials to be securely injected to the EKS Anywhere cluster +and assumed by the pods without any key pair. + +### Does EKS Anywhere support OIDC (including Azure AD and AD FS)? + +Yes, EKS-A can create clusters that support API server OIDC authentication. +This means you can federate authentication through AD FS locally or through Azure AD, +along with other IDPs that support the OIDC standard. +In order to add OIDC support to your EKS-A clusters, you need to configure your cluster by updating the configuration file before creating the cluster. +Please see the [OIDC reference]({{< relref "../../reference/clusterspec/oidc.md" >}}) for details. + +### Does EKS Anywhere support LDAP? +EKS-A does not support LDAP out of the box. +However, you can look into the [Dex LDAP Connector](https://dexidp.io/docs/connectors/ldap/). + +### Can I use AWS IAM for Kubernetes resource access control on EKS-A? +Yes, you can install the [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator) on your EKS-A cluster to achieve this. + + +## EKS-A add-on recommendations + +### Which add-ons are recommended with EKS-A? + +EKS Anywhere offers AWS support for certain third-party vendor components, +namely Ubuntu TLS, Cilium, and Flux. +It also provides flexibility for you to integrate with your choice of tools in other areas. +Below is a list of suggested third-party tools your consideration. + +| Feature | Suggest third-party tools | +|-------------------------------|-------------------------------------------| +| Ingress controller | [Emissary-ingress](https://www.getambassador.io/products/api-gateway/) (previously Ambassador) | +| Service type load balancer | [KubeVip](https://kube-vip.io/) / [Metal LB](https://metallb.universe.tf/) | +| Local container repository | [Harbor](https://goharbor.io/) | +| Monitoring | [Prometheus](https://sysdig.com/products/monitor/prometheus-monitoring/)+[Grafana](https://grafana.com/)+[FluentBit](https://fluentbit.io/kubernetes/) / [Datadog](https://www.datadoghq.com/blog/monitoring-kubernetes-with-datadog/) / [NewRelic](https://newrelic.com/platform/kubernetes/monitoring-guide) | +| Log analytics | [Splunk](https://www.splunk.com/en_us/blog/platform/introducing-the-splunk-operator-for-kubernetes.html) | +| Secret management | [Hashi Vault](https://www.vaultproject.io/docs/platform/k8s) | +| Policy agent | [Open Policy Agent](https://www.openpolicyagent.org/docs/latest/kubernetes-introduction/) | +| Service mesh | [Linkerd](https://linkerd.io/) or [Istio](https://istio.io/) | +| Infrastructure-as-code | [Terraform](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/getting-started) | +| Cost management | [KubeCost](https://www.kubecost.com/) | +| Etcd backup and restore | [Velero](https://velero.io/) | +| Storage | Default storage class, any compatible CSI | + +## Miscellaneous + +### Can I connect my EKS-A cluster to EKS? + +Yes, you can install EKS Connector to connect your EKS-A cluster to AWS EKS. +EKS Connector is a software agent that you can install on the EKS-A cluster that enables the cluster to communicate back to AWS. +Once connected, you can immediately see the EKS-A cluster with workload and cluster configuration information on the EKS console, +alongside your EKS clusters. + +#### How does the EKS Connector authenticate with AWS? + +During start-up, the EKS Connector generates and stores an RSA key-pair as Kubernetes secrets. +It also registers with AWS using the public key and the activation details from the cluster registration configuration file. +The EKS Connector needs AWS credentials to receive commands from AWS and to send the response back. +Whenever it requires AWS credentials, it uses its private key to sign the request and invokes AWS APIs to request the credentials. + +#### How does the EKS Connector authenticate with my Kubernetes cluster? + +The EKS Connector acts as a proxy and forwards the EKS console requests to the Kubernetes API server on your cluster. +In the initial release, the connector uses [impersonation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) with its service account secrets to interact with the API server. +Therefore, you need to associate the connector’s service account with a ClusterRole, +which gives permission to impersonate AWS IAM entities. + +#### How do I enable an AWS user account to view my connected cluster through the EKS console? + +For each AWS user or other IAM identity, you should add cluster role binding to the Kubernetes cluster with the appropriate permission for that IAM identity. +Additionally, each of these IAM entities should be associated with the [IAM policy](SOME_MANAGED_POLICY) +to invoke the EKS Connector on the cluster. + +### Can I use Amazon Controllers for Kubernetes (ACK) on EKS Anywhere? + +Yes, you can leverage AWS services from your EKS Anywhere clusters on-premises through [Amazon Controllers for Kubernetes (ACK)](https://aws.amazon.com/blogs/containers/aws-controllers-for-kubernetes-ack/). + + +### Can I deploy EKS-A on other clouds? + +EKS Anywhere can be installed on any infrastructure with the required VMware vSphere versions. +See EKS Anywhere [vSphere prerequisite]({{< relref "../vsphere" >}}) documentation. + +### Do you support multi-cluster operations? + +You can perform cluster life cycle and configuration management at scale through GitOps-based tools. +EKS Anywhere offers git-driven cluster management through the integrated Flux Controller. +See [Manage cluster with GitOps]({{< relref "../../tasks/cluster/cluster-flux.md" >}}) documentation for details. diff --git a/docs/content/en/docs/reference/security/_index.md b/docs/content/en/docs/reference/security/_index.md new file mode 100644 index 000000000000..a61557ebfacd --- /dev/null +++ b/docs/content/en/docs/reference/security/_index.md @@ -0,0 +1,177 @@ +--- +title: "Security best practices" +linkTitle: "Security best practices" +weight: 40 +description: > + Using security best practices with your EKS-A deployments +--- + +**If you discover a potential +security issue in this project, we ask that you notify AWS/Amazon Security via our +[vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). +Please do not create a public GitHub issue for security problems.** + +This guide provides advice about best practices for EKS-A specific security concerns. +For a more complete treatment of Kubernetes security generally +please refer to the official [Kubernetes documentation on Securing a Cluster](https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/) and the [Amazon EKS Best Practices Guide for Security](https://aws.github.io/aws-eks-best-practices/security/docs/index.html). + +## The Shared Responsibility Model and EKS-A +AWS Cloud Services follow the [Shared Responsibility Model,](https://aws.amazon.com/compliance/shared-responsibility-model/) +where AWS is responsible for security “of” the cloud, +while the customer is responsible for security “in” the cloud. +However, EKS-A is an open-source tool +and the distribution of responsibility differs from that of a managed cloud service like EKS. + +### AWS Responsibilities +AWS is responsible for building and delivering a secure tool. +This tool will provision an initially secure Kubernetes cluster. + +AWS is responsible for vetting and securely sourcing the services +and tools packaged with EKS-A and the cluster it creates +(such as coredns, cillium, flux, capi, and govc). + +The EKS-A build and delivery infrastructure, or supply chain, is secured to the standard of any AWS service +and AWS takes responsibility for the secure and reliable delivery of a quality product +which provisions a secure and stable Kubernetes cluster. +When the `eksctl anywhere` plugin is executed, EKS-A components are automatically downloaded from AWS. +`eksctl` will then perform checksum verification on the components to ensure their authenticity. + +AWS is responsible for the secure development and testing of the EKS-A controller and associated custom resource definitions. + +AWS is responsible for the secure development and testing of the EKS-A CLI, +and ensuring it handles sensitive data and cluster resources securely. + +### End user responsibilities +The end user is responsible for the entire EKS-A cluster after it has been provisioned. +AWS provides a mechanism to upgrade the cluster in-place, but it is the responsibility of the end user to perform that upgrade using the provided tools. +End users are responsible for operating their clusters in accordance with [Kubernetes security best practices,](https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/) +and for the ongoing security of the cluster after it has been provisioned. +This includes but is not limited to: +- creation or modification of RBAC roles and bindings +- creation or modification of namespaces +- modification of the default container network interface plugin +- configuration of network ingress and load balancing +- use and configuration of container storage interfaces +- the inclusion of add-ons and other services + +End users are also responsible for: + +* The hardware and software which make up the infrastructure layer +(such as vSphere, ESXi, physical servers, and physical network infrastructure). + +* The ongoing maintenance of the cluster nodes, +including the underlying guest operating systems. +Additionally, while EKS-A provides a streamlined process for upgrading a cluster to a new Kubernetes version, +it is the responsibility of the user to perform the upgrade as necessary. + +* Any applications which run “on” the cluster, including their secure operation, +least privilege, and use of well-known and vetted container images. + +## EKS-A Security Best Practices +This section captures EKS-A specific security best practices. +Please read this section carefully and follow any guidance +to ensure the ongoing security and reliability of your EKS-A cluster. + +### Critical Namespaces + +EKS-A creates and uses resources in several critical namespaces. +All of the EKS-A managed namespaces should be treated as sensitive +and access should be limited to only the most trusted users and processes. +Allowing additional access or modifying the existing RBAC resources +could potentially allow a subject to access the namespace and the resources that it contains. +This could lead to the exposure of secrets +or the failure of your cluster due to modification of critical resources. +Here are rules you should follow when dealing with critical namespaces: + +* Avoid creating [Roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-example) in these namespaces +or providing users access to them with [ClusterRoles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrole-example). +For more information about creating limited roles for day-to-day administration and development, +please see the official introduction to [Role Based Access Control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). + +* **Do not modify existing [Roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-example) in these namespaces, +bind existing roles to additional [subjects](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-subjects), or create new Roles in the namespace.** + +* **Do not modify existing [ClusterRoles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrole-example) +or bind them to additional subjects.** + +* **Avoid using the cluster-admin role, +as it grants permissions over all namespaces.** + +* **No subjects except for the most trusted administrators should be permitted to perform ANY action in the critical namespaces.** + +The critical namespaces include: + +* `eksa-system` +* `capv-system` +* `flux-system` +* `capi-system` +* `capi-webhook-system` +* `capi-kubeadm-control-plane-system` +* `capi-kubeadm-bootstrap-system` +* `cert-manager` +* `kube-system` (as with any Kubernetes cluster, +this namespace is critical to the functioning of your cluster and should be treated with the highest level of sensitivity.) + + +### Secrets + +EKS-A stores sensitive information, like the vSphere credentials and Github Personal Access Token, +in the cluster as native Kubernetes [secrets](https://kubernetes.io/docs/concepts/configuration/secret/). +These secret objects are namespaced, for example in the `eksa-system` and `flux-system` namespace, +and limiting access to the sensitive namespaces will ensure that these secrets will not be exposed. +Additionally, limit access to the underlying node. Access to the node could allow access to the secret content. + +EKS-A does not currently support encryption-at-rest for Kubernetes secrets. +EKS-A support for [Key Management Services (KMS)](https://kubernetes.io/docs/tasks/administer-cluster/kms-provider/) is planned. + + +### The EKS-A `kubeconfig` file + +`eksctl anywhere create cluster` creates an EKS-A-based Kubernetes cluster +and outputs a [`kubeconfig`](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) file with administrative privileges to the `$PWD/$CLUSTER_NAME` directory. + +By default, this `kubeconfig` file uses certificate-based authentication and contains the user certificate data for the administrative user. + +**The `kubeconfig` file grants administrative privileges over your cluster to the bearer and the certificate key should be treated as you would any other private key or administrative password.** + +The EKS-A-generated kubeconfig file should only be used for interacting with the cluster via `eksctl anywhere` commands, +such as `upgrade`, and for the most privileged administrative tasks. +For more information about creating limited roles for day-to-day administration and development, +please see the [official introduction to Role Based Access Control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). + +### GitOps + +GitOps enabled EKS-A clusters maintain a copy of their cluster configuration in the user provided Git repository. +This configuration acts as the source of truth for the cluster. +Changes made to this configuration will be reflected in the cluster configuration. + +AWS recommends that you gate any changes to this repository with mandatory pull request reviews. +Carefully review pull requests for changes which could impact the availability of the cluster +(such as scaling nodes to 0 and deleting the cluster object) or contain secrets. + +### Github Personal Access Token + +Treat the [GitHub PAT](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) used with EKS-A as you would any highly privileged secret, +as it could potentially be used to make changes to your cluster by modifying the contents of the cluster configuration file through the [Github.com](https://github.com/) API. + +* Never commit the PAT to a Git repository +* Never share the PAT via untrusted channels +* Never grant non-administrative subjects access to the `flux-system` namespace where the PAT is stored as a native Kubernetes secret. + +### Executing EKS-A + +Ensure that you execute `eksctl anywhere create cluster` on a trusted workstation +in order to protect the values of sensitive environment variables and the EKS-A generated kubeconfig file. + +### SSH Access to Cluster Nodes and ETCD Nodes + +EKS-A provides the option to configure an ssh authorized key for access to underlying nodes in a cluster, via `vsphereMachineConfig.Users.sshAuthorizedKeys`. +This grants the associated private key the ability to connect to the cluster +via `ssh` as the user `capv` with `sudo` permissions. +The associated private key should be treated as extremely sensitive, +as `sudo` access to the cluster and ETCD nodes can permit access to secret object data and potentially confer arbitrary control over the cluster. + +### VMWare OVAs + +Only download OVAs for cluster nodes from official sources, +and do not allow untrusted users or processes to modify the templates used by EKS-A for provisioning nodes. diff --git a/docs/content/en/docs/reference/support/_index.md b/docs/content/en/docs/reference/support/_index.md new file mode 100644 index 000000000000..5e2287fd8114 --- /dev/null +++ b/docs/content/en/docs/reference/support/_index.md @@ -0,0 +1,19 @@ +--- +title: "Support" +linkTitle: "Support" +weight: 50 +description: > + Beta support for EKS-A +--- + +EKS Anywhere support licenses are available to AWS customers who pay for +enterprise support. If you would like business support for your EKS +Anywhere clusters please contact your Technical Account Manager (TAM) for +details. + +EKS Anywhere is an open source project and it is supported by the community. +If you have a problem, open an [issue](https://github.com/aws/eks-anywhere/issues) +and someone will get back to you as soon as possible. If you discover a potential +security issue in this project, we ask that you notify AWS/Amazon Security via our +[vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). +Please do not create a public GitHub issue for security problems. diff --git a/docs/content/en/docs/reference/vsphere/_index.md b/docs/content/en/docs/reference/vsphere/_index.md new file mode 100644 index 000000000000..a819fea7823d --- /dev/null +++ b/docs/content/en/docs/reference/vsphere/_index.md @@ -0,0 +1,220 @@ +--- +title: "VMware vSphere" +linkTitle: "VMware vSphere" +weight: 15 +description: > + Specification for VMware vSphere provider +--- + + + +Deploying a production grade cluster on vSphere. + + + +# Prerequisite Checklist + +To run EKS Anywhere, you will need: + +* A vSphere 7+ environment running vCenter +* Capacity to deploy 8-10VMs +* DHCP service running in vSphere environment in the primary VM network for your workload cluster +* One network in vSphere to use for the cluster. This network must have inbound access into vCenter +* A OVA imported into vSphere and converted into template for the workload VMs +* User credentials to [create vms and attach networks, etc]({{< relref "user-permissions.md" >}}) + +A minimum workload cluster will require 6 to 10 VMs and each VM will require: + +* 2 vCPU +* 8GB RAM +* 20GB Disk + +The administrative machine and the target workload environment will need network access to: + +{{% content "domains.md" %}} + +# Default templates + +If you don't specify a template in the cluster spec file, EKS-A will use the proper default one for the Kubernetes minor version and OS family you specified in the spec file. +If the template doesn't exist, it will import the appropriate OVA into vSphere and add the necessary tags. + +The default OVA for a Kubernetes minor version + OS family will change over time, for example, when a new EKS-D version is released. In that case, new clusters will use the new OVA (EKS-A will import it automatically). + +# Import an OVA/OVF template to vSphere + +If you prefer to specify a template, you will need to import OVA files into vSphere to run EKS Anywhere. This guide was written using VMware Cloud on AWS, +but the [VMWare OVA import guide can be found here](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-17BEDA21-43F6-41F4-8FB2-E01D275FE9B4.html). + +EKS Anywhere supports the following operating system families + +* Ubuntu (default) +* Bottlerocket + +Links to OVAs based on particular operating systems and Kubernetes versions including appropriate tags: + +## Ubuntu with Kubernetes 1.21 + +* https://eks-anywhere-beta.s3.amazonaws.com/0.4.0/ova/ubuntu-v1.21.2-eks-d-1-21-4-eks-a-0.4.0-amd64.ova +* `os:ubuntu` +* `eksdRelease:kubernetes-1-21-eks-4` + +## Ubuntu with Kubernetes 1.20 + +* https://eks-anywhere-beta.s3.amazonaws.com/0.4.0/ova/ubuntu-v1.20.7-eks-d-1-20-6-eks-a-0.4.0-amd64.ova +* `os:ubuntu` +* `eksdRelease:kubernetes-1-20-eks-6` + +## Bottlerocket with Kubernetes 1.21 + +* https://eks-anywhere-beta.s3.amazonaws.com/0.4.0/ova/bottlerocket-v1.21.2-eks-d-1-21-4-eks-a-0.4.0-amd64.ova +* `os:bottlerocket` +* `eksdRelease:kubernetes-1-21-eks-4` + +## Bottlerocket with Kubernetes 1.20 + +* https://eks-anywhere-beta.s3.amazonaws.com/0.4.0/ova/bottlerocket-v1.20.7-eks-d-1-20-6-eks-a-0.4.0-amd64.ova +* `os:bottlerocket` +* `eksdRelease:kubernetes-1-20-eks-6` + + +## Using vCenter Web User Interface + +1. Right click on your Datacenter, select *Deploy OVF Template* + ![Import ova drop down](/images/ss1.jpg) +1. Select an OVF template using URL or selecting a local OVF file and click on *Next*. If you are not able to select an + OVF template using URL, download the file and use Local file option. + ![Import ova wizard](/images/ss2.jpg) +1. Select a folder where you want to deploy your OVF package (most of our OVF templates are under SDDC-Datacenter + directory) and click on *Next*. You cannot have an OVF template with the same name in one directory. For workload + VM templates, leave the Kubernetes version in the template name for reference. A workload VM template will + support at least one prior Kubernetes major versions. + ![Import ova wizard](/images/ss3.jpg) +1. Select any compute resource to run (from cluster-1, 10.2.34.5, etc..) the deployed VM and click on *Next* + ![Import ova wizard](/images/ss4.jpg) +1. Review the details and click *Next*. +1. Accept the agreement and click *Next*. +1. Select the appropriate storage (e.g. “WorkloadDatastore“) and click *Next*. +1. Select destination network (e.g. “sddc-cgw-network-1”) and click *Next*. +1. Finish. +1. Snapshot the VM. Right click on the imported VM and select Snapshots -> Take Snapshot... + (It is highly recommended that you snapshot the VM. This will reduce the time it takes to provision + machines and cluster creation will be faster. If you prefer not to take snapshot, skip to step 13) +![Import ova wizard](/images/ss6.jpg) +1. Name your template (e.g. "root") and click *Create*. +![Import ova wizard](/images/ss7.jpg) +1. Snapshots for the imported VM should now show up under the *Snapshots* tab for the VM. +![Import ova wizard](/images/ss8.jpg) +1. Right click on the imported VM and select Template and Convert to Template +![Import ova wizard](/images/ss9.jpg) + +## Steps to deploy a template using GOVC (CLI) + +To deploy a template using `govc`, you must first ensure that you have +[GOVC installed](https://github.com/vmware/govmomi/blob/master/govc/README.md). You need to set and export three +environment variables to run `govc` GOVC_USERNAME, GOVC_PASSWORD and GOVC_URL. + +Note: If you are using Bottlerocket OVA, please refer the above section and use the Web User Interface to import the OVA. + +1. Import the template to a content library in vCenter using URL or selecting a local OVA file + + Using URL: + + ``` + govc library.import -k -pull + ``` + + Using a file from the local machine: + + ``` + govc library.import + ``` + +1. Deploy the template + + ``` + govc library.deploy -pool -folder //