diff --git a/cmd/admiralctl/admiralctl.go b/cmd/admiralctl/admiralctl.go new file mode 100755 index 00000000..3a7ef668 --- /dev/null +++ b/cmd/admiralctl/admiralctl.go @@ -0,0 +1,31 @@ +/* +Copyright 2023 The KubeAdmiral Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "k8s.io/component-base/cli" + "k8s.io/kubectl/pkg/cmd/util" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl" +) + +func main() { + cmd := admiralctl.NewDefaultAdmiralctlCommand() + if err := cli.RunNoErrOutput(cmd); err != nil { + util.CheckErr(err) + } +} diff --git a/go.mod b/go.mod index d6204f1f..74ec6896 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,9 @@ require ( require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/BurntSushi/toml v1.2.1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect @@ -42,11 +44,14 @@ require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.4.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -55,33 +60,44 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/btree v1.0.1 // indirect github.com/google/cel-go v0.12.6 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/cobra v1.6.1 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/xlab/treeprint v1.1.0 // indirect go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.etcd.io/etcd/client/v3 v3.5.7 // indirect @@ -95,6 +111,7 @@ require ( go.opentelemetry.io/otel/sdk v1.10.0 // indirect go.opentelemetry.io/otel/trace v1.10.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect @@ -113,9 +130,13 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/cli-runtime v0.26.6 // indirect k8s.io/kms v0.27.1 // indirect + k8s.io/kubectl v0.26.6 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.12.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 0f44eab9..040eda70 100644 --- a/go.sum +++ b/go.sum @@ -35,14 +35,20 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -54,6 +60,7 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -69,6 +76,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -87,6 +96,7 @@ github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -94,6 +104,7 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -102,11 +113,14 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= @@ -114,6 +128,8 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNy github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -181,6 +197,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.12.6 h1:kjeKudqV0OygrAqA9fX6J55S8gj+Jre2tckIm5RoG4M= github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= @@ -214,12 +231,17 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -264,6 +286,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= @@ -271,6 +295,12 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -278,6 +308,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -293,6 +325,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -327,6 +361,7 @@ github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -337,6 +372,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= @@ -361,6 +397,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -402,6 +440,8 @@ go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/A go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= @@ -519,6 +559,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -545,6 +586,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -581,6 +623,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -736,6 +779,7 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -751,6 +795,8 @@ k8s.io/apimachinery v0.26.6 h1:OT04J9US8G+AqfqvcJZZ8s3WUQkWbc3t6ePPWieDN6I= k8s.io/apimachinery v0.26.6/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0= k8s.io/apiserver v0.26.6 h1:gM6Ai7L4Kv+4iYeJhEd8VgP8KrdMjJNGrH9iEcnqB4c= k8s.io/apiserver v0.26.6/go.mod h1:Lfs3EMXwKERf8PUa3a+jpb23lJAFtJPDj/xKDxYktFo= +k8s.io/cli-runtime v0.26.6 h1:535Ult64Zp1583D1mewL1LdThwAcuYc4MwM69l3p2VU= +k8s.io/cli-runtime v0.26.6/go.mod h1:m/5RF2eCPVh0fhdBXgSJIyTiZuPOG0BOvkIVZtc1NqE= k8s.io/client-go v0.26.6 h1:CtC0wOxkAwjYyG2URGzdEKo0nLILopSDYn5AmzOkdi4= k8s.io/client-go v0.26.6/go.mod h1:HDjbQGY7XzFYFUWOPAfAsIYhvFXyc9l6Ne0pO0bOQ7o= k8s.io/component-base v0.26.6 h1:/Tm16Z8l/ruLFcw1XbFKTRSuxD6gQULQxxYgmar8PI0= @@ -761,6 +807,8 @@ k8s.io/kms v0.26.6 h1:cDT0gJJcDzLoV7sdZoWR5nUxlHpQI7+AWoeJyhkdtbg= k8s.io/kms v0.26.6/go.mod h1:AYuV9ZebRhr6cb1eT9L6kZVxvgIUxmE1Fe6kPhqYvuc= k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kubectl v0.26.6 h1:8w/13HZ+kb7tKFoZ55Ci96L3RvjTFFuLPBEYYSOP0rA= +k8s.io/kubectl v0.26.6/go.mod h1:q9wFF+QoE0tOQnJvPbxCXnjKuot/0v/eFXNBjheEsgY= k8s.io/metrics v0.26.6 h1:gfSNDEYws2A3d1DRsHYXyAKpxE93Fn9aLUKpQI7GoEI= k8s.io/metrics v0.26.6/go.mod h1:EvxYwtVrZ7GzZ34kNjivvSCnZXdLM/uV8leXG3OIJ3U= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= @@ -778,7 +826,11 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.17.0 h1:CScmGz/wX66puA06Gj8OZb76Wmk7JIjgWf5JDvY7msM= sigs.k8s.io/kind v0.17.0/go.mod h1:Qqp8AiwOlMZmJWs37Hgs31xcbiYXjtXlRBSftcnZXQk= +sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= +sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= \ No newline at end of file diff --git a/pkg/admiralctl/admiralctl.go b/pkg/admiralctl/admiralctl.go new file mode 100644 index 00000000..f4f6b07d --- /dev/null +++ b/pkg/admiralctl/admiralctl.go @@ -0,0 +1,80 @@ +package admiralctl + +import ( + "flag" + "fmt" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/join" + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/unjoin" + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/util" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "k8s.io/cli-runtime/pkg/genericclioptions" + apiserverflag "k8s.io/component-base/cli/flag" + "k8s.io/klog/v2" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + cliName = "admiralctl" + rootCmdShort = "%s controls the Kubernetes cluster federation manager." + // defaultConfigFlags It composes the set of values necessary for obtaining a REST client config with default values set. + defaultConfigFlags = genericclioptions.NewConfigFlags(true). + WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) +) + +// NewDefaultAdmiralctlCommand creates the `admiralctl` command. +func NewDefaultAdmiralctlCommand() *cobra.Command { + rootCmd := &cobra.Command{ + Use: cliName, + Short: fmt.Sprintf(rootCmdShort, cliName), + RunE: runHelp, + } + + // Init log flags + klog.InitFlags(flag.CommandLine) + + // Add the command line flags from other dependencies (e.g., klog), but do not + // warn if they contain underscores. + pflag.CommandLine.SetNormalizeFunc(apiserverflag.WordSepNormalizeFunc) + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + flags := rootCmd.PersistentFlags() + flags.AddFlagSet(pflag.CommandLine) + addKubeConfigFlags(flags) + + // From this point and forward we get warnings on flags that contain "_" separators + // when adding them with hyphen instead of the original name. + rootCmd.SetGlobalNormalizationFunc(apiserverflag.WarnWordSepNormalizeFunc) + + // Prevent klog errors about logging before parsing. + _ = flag.CommandLine.Parse(nil) + f := util.NewFactory(defaultConfigFlags) + + // ioStreams := genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr} + groups := templates.CommandGroups{ + { + Message: "Resource Management Commands:", + Commands: []*cobra.Command{ + join.NewCmdJoin(f, cliName), + unjoin.NewCmdJoin(f, cliName), + }, + }, + } + groups.Add(rootCmd) + filters := []string{""} + templates.ActsAsRootCommand(rootCmd, filters, groups...) + + return rootCmd +} + +// addKubeConfigFlags adds flags to the specified FlagSet. +func addKubeConfigFlags(flags *pflag.FlagSet) { + flags.StringVar(defaultConfigFlags.KubeConfig, "kubeconfig", *defaultConfigFlags.KubeConfig, + "Path to the kubeconfig file to use for CLI requests.") + flags.StringVar(defaultConfigFlags.Context, "kubeadmiral-context", *defaultConfigFlags.Context, + "The name of the kubeconfig context to use") +} + +func runHelp(cmd *cobra.Command, _ []string) error { + return cmd.Help() +} diff --git a/pkg/admiralctl/join/join.go b/pkg/admiralctl/join/join.go new file mode 100644 index 00000000..1a7ea31f --- /dev/null +++ b/pkg/admiralctl/join/join.go @@ -0,0 +1,304 @@ +package join + +import ( + "context" + "fmt" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/util" + fedcorev1a1 "github.com/kubewharf/kubeadmiral/pkg/apis/core/v1alpha1" + fedclient "github.com/kubewharf/kubeadmiral/pkg/client/clientset/versioned" + "github.com/kubewharf/kubeadmiral/pkg/controllers/common" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + applycorev1 "k8s.io/client-go/applyconfigurations/core/v1" + applymetav1 "k8s.io/client-go/applyconfigurations/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + joinLongDesc = templates.LongDesc(` + Join a member cluster to Kubeadmiral control plane. + + If the control plane of the member cluster is not ready or has already joined, this command will do nothing. + `) + + joinExample = templates.Examples(` + # Join cluster1 to Kubeadmiral by kubeconfig + %[1]s join cluster1 --cluster-kubeconfig= + + # Support to use '--api-endpoint' to overwrite the member cluster's api-endpoint + %[1]s join cluster1 --cluster-kubeconfig= --api-endpoint= + + # Support to use '--use-service-account' to determine whether create a new ServiceAccount when join + %[1]s join cluster1 --cluster-kubeconfig= --use-service-account=false + + # Support to use '--cluster-context' to specify the context of member cluster + %[1]s join cluster1 --cluster-kubeconfig= --cluster-context= + + `) +) + +// CommandJoinOption holds all command options for join +type CommandJoinOption struct { + // Cluster is the name of member cluster + Cluster string + + // Namespace is the kube-admiral-system namespace, corresponding to common.DefaultFedSystemNamespace + Namespace string + + // ClusterContext is context name of member cluster in kubeconfig + ClusterContext string + + // ClusterKubeConfig is the member cluster's kubeconfig path + ClusterKubeConfig string + + // Host is the api-endpoint of the member cluster + Host string + + // CAData is the CA of the member cluster + CAData []byte + + // CertData is the cert of the member cluster + CertData []byte + + // KeyData is the cert-key of the member cluster + KeyData []byte + + // BearerToken is the the client authentication specified by user + BearerToken string + + // UseServiceAccount is a flag to choose whether create a new ServiceAccount when join, corresponding to FederatedCluster.spec.useServiceAccount + UseServiceAccount bool + + ClusterK8sClientSet *kubernetes.Clientset + FedK8sClientSet *kubernetes.Clientset + FedClientSet *fedclient.Clientset +} + +// AddFlags adds command line flags to the given cobra.Command. +func (o *CommandJoinOption) AddFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + flags.StringVar(&o.ClusterKubeConfig, "cluster-kubeconfig", "", "Path of the member cluster's kubeconfig.") + cmd.MarkFlagRequired("cluster-kubeconfig") + flags.StringVar(&o.ClusterContext, "cluster-context", "", "Context name of member cluster in kubeconfig.") + flags.StringVar(&o.Host, "api-endpoint", "", "api-endpoint of the member cluster.") + flags.BoolVar(&o.UseServiceAccount, "use-service-account", true, + "Whether creates a new ServiceAccount when join, corresponding to FederatedCluster.spec.useServiceAccount. "+ + "If you set 'false', BearerToken should be in the kubeconfig.") +} + +func NewCmdJoin(f util.Factory, parentCommand string) *cobra.Command { + o := CommandJoinOption{} + + cmd := &cobra.Command{ + Use: "join --cluster-kubeconfig ", + Short: "join clusters to Kubeadmiral control plane", + Long: joinLongDesc, + Example: fmt.Sprintf(joinExample, parentCommand), + SilenceUsage: true, + DisableFlagsInUseLine: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := o.ToOptions(f, args); err != nil { + return err + } + if err := o.Validate(); err != nil { + return err + } + if err := o.Join(); err != nil { + return err + } + return nil + }, + } + + o.AddFlags(cmd) + + return cmd +} + +// ToOptions converts from CLI inputs to runtime options +func (o *CommandJoinOption) ToOptions(f util.Factory, args []string) error { + var err error = nil + + if len(args) != 1 { + return fmt.Errorf("command line input format error") + } + + o.Cluster = args[0] + + o.Namespace = common.DefaultFedSystemNamespace + + clusterFactory, err := util.NewClusterFactoryByKubeConfig(o.ClusterKubeConfig, o.ClusterContext) + if err != nil { + return err + } + + clusterRESTConfig, err := clusterFactory.ToRESTConfig() + if err != nil { + return err + } + o.ClusterK8sClientSet = kubernetes.NewForConfigOrDie(clusterRESTConfig) + + fedRESTConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.FedK8sClientSet = kubernetes.NewForConfigOrDie(fedRESTConfig) + o.FedClientSet = fedclient.NewForConfigOrDie(fedRESTConfig) + + if len(o.Host) == 0 { + o.Host = clusterRESTConfig.Host + } + o.CAData = clusterRESTConfig.CAData + o.CertData = clusterRESTConfig.CertData + o.KeyData = clusterRESTConfig.KeyData + o.BearerToken = clusterRESTConfig.BearerToken + + return nil +} + +// Validate verifies whether the options are valid and whether the joining is valid. +func (o *CommandJoinOption) Validate() error { + if !o.UseServiceAccount { + if len(o.BearerToken) == 0 { + return fmt.Errorf("if --use-service-account sets false, BearerToken should be in the kubeconfig") + } + } else if len(o.CertData) == 0 || len(o.KeyData) == 0 { + return fmt.Errorf("if --use-service-account sets true, certificate and key should be in the kubeconfig") + } + + if err := o.checkClusterReady(); err != nil { + return err + } + + if err := o.checkClusterJoined(); err != nil { + return err + } + + return nil +} + +// check whether the member cluster's control plane nodes are ready +func (o *CommandJoinOption) checkClusterReady() error { + nodes, err := o.ClusterK8sClientSet.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return err + } + + for _, node := range nodes.Items { + if isControlPlane(&node) { + for _, condition := range node.Status.Conditions { + if condition.Type == corev1.NodeReady && condition.Status != corev1.ConditionTrue { + return fmt.Errorf("control plane %s is not ready", node.Name) + } + } + } + } + + return nil +} + +func isControlPlane(node *corev1.Node) bool { + labels := node.Labels + if labels != nil { + _, hasControlPlaneLabel := labels["node-role.kubernetes.io/control-plane"] + return hasControlPlaneLabel + } + return false +} + +// check whether the member cluster has already joined a kubeadmiral federation +func (o *CommandJoinOption) checkClusterJoined() error { + namespace, err := o.ClusterK8sClientSet.CoreV1().Namespaces().Get(context.TODO(), o.Namespace, metav1.GetOptions{}) + if err == nil { + for key, value := range namespace.GetAnnotations() { + if key == "kubeadmiral.io/federated-cluster-uid" { + fedClusters, err := o.FedClientSet.CoreV1alpha1().FederatedClusters().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return err + } + + for _, fedCluster := range fedClusters.Items { + if fedCluster.UID == types.UID(value) { + return fmt.Errorf("the cluster has already joined your kubeadmiral federation (federated-cluster-uid: %v)", value) + } + } + return fmt.Errorf("the cluster has joined another kubeadmiral federation (federated-cluster-uid: %v)", value) + } + } + } + + return nil +} + +func (o *CommandJoinOption) Join() error { + if err := o.applySecret(); err != nil { + return err + } + + if err := o.createFederatedCluster(); err != nil { + return err + } + + fmt.Printf("Cluster: %s joined\n", o.Cluster) + return nil +} + +// apply the Secret +func (o *CommandJoinOption) applySecret() error { + kindString := "Secret" + APIVersionString := "v1" + secret := &applycorev1.SecretApplyConfiguration{ + TypeMetaApplyConfiguration: applymetav1.TypeMetaApplyConfiguration{ + Kind: &kindString, + APIVersion: &APIVersionString, + }, + ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{ + Name: &o.Cluster, + Namespace: &o.Namespace, + }, + Data: map[string][]byte{ + common.ClusterCertificateAuthorityKey: o.CAData, + common.ClusterClientCertificateKey: o.CertData, + common.ClusterClientKeyKey: o.KeyData, + common.ClusterBootstrapTokenKey: []byte(o.BearerToken), + }, + } + + _, err := o.FedK8sClientSet.CoreV1().Secrets(o.Namespace).Apply(context.TODO(), secret, metav1.ApplyOptions{FieldManager: "kubectl-client-side-apply"}) + if err != nil { + return err + } + + fmt.Printf("Secret: %s/%s created\n", o.Namespace, o.Cluster) + return nil +} + +// create the FederatedCluster +func (o *CommandJoinOption) createFederatedCluster() error { + federatedCluster := &fedcorev1a1.FederatedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: o.Cluster, + Namespace: o.Namespace, + }, + Spec: fedcorev1a1.FederatedClusterSpec{ + APIEndpoint: o.Host, + UseServiceAccountToken: o.UseServiceAccount, + SecretRef: fedcorev1a1.LocalSecretReference{ + Name: o.Cluster, + }, + }, + } + + _, err := o.FedClientSet.CoreV1alpha1().FederatedClusters().Create(context.TODO(), federatedCluster, metav1.CreateOptions{}) + if err != nil { + return err + } + + fmt.Printf("FederatedCluster: %s created\n", o.Cluster) + return nil +} diff --git a/pkg/admiralctl/join/join_test.go b/pkg/admiralctl/join/join_test.go new file mode 100644 index 00000000..a7ea2c25 --- /dev/null +++ b/pkg/admiralctl/join/join_test.go @@ -0,0 +1,126 @@ +package join + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/util" + utilpointer "k8s.io/utils/pointer" +) + +func TestCommandJoinOption_ToOptions(t *testing.T) { + testCases := []struct { + name string + option CommandJoinOption + args []string + expectedErr error + }{ + // error test + { + name: "no fcluster name", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/config", + ClusterContext: "", + UseServiceAccount: true, + }, + args: []string{}, + expectedErr: fmt.Errorf("command line input format error"), + }, + } + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.KubeConfig = utilpointer.String("/home/jzd/.kube/kubeadmiral/kubeadmiral.config") + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + assert := assert.New(t) + err := testCase.option.ToOptions(util.NewFactory(defaultConfigFlags), testCase.args) + assert.Equal(testCase.expectedErr, err) + }) + } +} + +func TestCommandJoinOption_Validate(t *testing.T) { + testCases := []struct { + name string + option CommandJoinOption + args []string + expectedErr error + }{ + // normal test + { + name: "normal test, UseServiceAccount=true", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/config", + ClusterContext: "", + UseServiceAccount: true, + }, + args: []string{"cluster"}, + expectedErr: nil, + }, + { + name: "normal test, UseServiceAccount=false", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/config", + ClusterContext: "token-context", + UseServiceAccount: false, + }, + args: []string{"cluster"}, + expectedErr: nil, + }, + // error test + { + name: "UseServiceAccount=false, but no BearerToken", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/config", + ClusterContext: "", + UseServiceAccount: false, + }, + args: []string{"cluster"}, + expectedErr: fmt.Errorf("if --use-service-account sets false, BearerToken should be in the kubeconfig"), + }, + { + name: "UseServiceAccount=true, but no cert and key", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/config", + ClusterContext: "no-cert-context", + UseServiceAccount: true, + }, + args: []string{"cluster"}, + expectedErr: fmt.Errorf("if --use-service-account sets true, certificate and key should be in the kubeconfig"), + }, + { + name: "cluster's control plane not ready", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/kubeadmiral/member-test-notready.config", + ClusterContext: "", + UseServiceAccount: true, + }, + args: []string{"cluster"}, + expectedErr: fmt.Errorf("control plane %s is not ready", "kubeadmiral-member-test-notready-control-plane"), + }, + { + name: "cluster already joined the federation", + option: CommandJoinOption{ + ClusterKubeConfig: "/home/jzd/.kube/kubeadmiral/member-1.config", + ClusterContext: "", + UseServiceAccount: true, + }, + args: []string{"cluster"}, + expectedErr: fmt.Errorf("the cluster has already joined your kubeadmiral federation (federated-cluster-uid: %v)", "e9e8be6f-5d61-4f97-bc67-f1fadf17542a"), + }, + } + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.KubeConfig = utilpointer.String("/home/jzd/.kube/kubeadmiral/kubeadmiral.config") + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + assert := assert.New(t) + _ = testCase.option.ToOptions(util.NewFactory(defaultConfigFlags), testCase.args) + err := testCase.option.Validate() + assert.Equal(testCase.expectedErr, err) + }) + } +} diff --git a/pkg/admiralctl/unjoin/unjoin.go b/pkg/admiralctl/unjoin/unjoin.go new file mode 100644 index 00000000..2be35b64 --- /dev/null +++ b/pkg/admiralctl/unjoin/unjoin.go @@ -0,0 +1,144 @@ +package unjoin + +import ( + "context" + "fmt" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/util" + fedclient "github.com/kubewharf/kubeadmiral/pkg/client/clientset/versioned" + "github.com/kubewharf/kubeadmiral/pkg/controllers/common" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/kubectl/pkg/util/templates" +) + +var ( + unjoinLongDesc = templates.LongDesc(` + Unjoin a FederatedCluster from Kubeadmiral federation. + + If the the federated cluster has not joined the federation, this command will do nothing. + `) + + unjoinExample = templates.Examples(` + # Unjoin cluster1 from Kubeadmiral federation + %[1]s unjoin cluster1 + `) +) + +// CommandUnjoinOption holds all command options for unjoin +type CommandUnjoinOption struct { + // Cluster is the name of member cluster + Cluster string + + // Namespace is the kube-admiral-system namespace, corresponding to common.DefaultFedSystemNamespace + Namespace string + + FedK8sClientSet *kubernetes.Clientset + FedClientSet *fedclient.Clientset +} + +func NewCmdJoin(f util.Factory, parentCommand string) *cobra.Command { + o := CommandUnjoinOption{} + + cmd := &cobra.Command{ + Use: "unjoin ", + Short: "unjoin the FederatedCluster from Kubeadmiral federation", + Long: unjoinLongDesc, + Example: fmt.Sprintf(unjoinExample, parentCommand), + SilenceUsage: true, + DisableFlagsInUseLine: true, + RunE: func(cmd *cobra.Command, args []string) error { + if err := o.ToOptions(f, args); err != nil { + return err + } + if err := o.Validate(); err != nil { + return err + } + if err := o.Unjoin(); err != nil { + return err + } + return nil + }, + } + + return cmd +} + +// ToOptions converts from CLI inputs to runtime options +func (o *CommandUnjoinOption) ToOptions(f util.Factory, args []string) error { + if len(args) != 1 { + return fmt.Errorf("command line input format error") + } + + o.Cluster = args[0] + + o.Namespace = common.DefaultFedSystemNamespace + + fedRESTConfig, err := f.ToRESTConfig() + if err != nil { + return err + } + o.FedK8sClientSet = kubernetes.NewForConfigOrDie(fedRESTConfig) + o.FedClientSet = fedclient.NewForConfigOrDie(fedRESTConfig) + + return nil +} + +// Validate verifies whether the options are valid and whether the unjoining is valid. +func (o *CommandUnjoinOption) Validate() error { + if err := o.checkClusterJoined(); err != nil { + return err + } + + if err := o.checkSecretExists(); err != nil { + return err + } + + return nil +} + +// check whether the cluster has joined kubeadmiral federation +func (o *CommandUnjoinOption) checkClusterJoined() error { + fedClusters, err := o.FedClientSet.CoreV1alpha1().FederatedClusters().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return err + } + + for _, fedCluster := range fedClusters.Items { + if fedCluster.Name == o.Cluster { + return nil + } + } + + return fmt.Errorf("cluster: %s has not joined kubeadmiral federation", o.Cluster) +} + +// check whether the secret exists +func (o *CommandUnjoinOption) checkSecretExists() error { + _, err := o.FedK8sClientSet.CoreV1().Secrets(o.Namespace).Get(context.TODO(), o.Cluster, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("secret: %s/%s does not exist", o.Namespace, o.Cluster) + } + + return nil +} + +func (o *CommandUnjoinOption) Unjoin() error { + if err := o.deleteFederatedCluster(); err != nil { + return err + } + + fmt.Printf("Cluster: %s unjoined\n", o.Cluster) + return nil +} + +// delete the FederatedCluster +func (o *CommandUnjoinOption) deleteFederatedCluster() error { + if err := o.FedClientSet.CoreV1alpha1().FederatedClusters().Delete(context.TODO(), o.Cluster, metav1.DeleteOptions{}); err != nil { + return err + } + + fmt.Printf("FederatedCluster: %s deleted\n", o.Cluster) + return nil +} diff --git a/pkg/admiralctl/unjoin/unjoin_test.go b/pkg/admiralctl/unjoin/unjoin_test.go new file mode 100644 index 00000000..107c8d0b --- /dev/null +++ b/pkg/admiralctl/unjoin/unjoin_test.go @@ -0,0 +1,79 @@ +package unjoin + +import ( + "fmt" + "testing" + + "github.com/kubewharf/kubeadmiral/pkg/admiralctl/util" + "github.com/stretchr/testify/assert" + "k8s.io/cli-runtime/pkg/genericclioptions" + utilpointer "k8s.io/utils/pointer" +) + +func TestCommandJoinOption_ToOptions(t *testing.T) { + testCases := []struct { + name string + option CommandUnjoinOption + args []string + expectedErr error + }{ + // error test + { + name: "no fcluster name", + option: CommandUnjoinOption{}, + args: []string{}, + expectedErr: fmt.Errorf("command line input format error"), + }, + } + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.KubeConfig = utilpointer.String("/home/jzd/.kube/kubeadmiral/kubeadmiral.config") + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + assert := assert.New(t) + err := testCase.option.ToOptions(util.NewFactory(defaultConfigFlags), testCase.args) + assert.Equal(testCase.expectedErr, err) + }) + } +} + +func TestCommandJoinOption_Validate(t *testing.T) { + testCases := []struct { + name string + option CommandUnjoinOption + args []string + expectedErr error + }{ + // normal test + { + name: "normal test", + option: CommandUnjoinOption{}, + args: []string{"cluster-test-healthy"}, + expectedErr: nil, + }, + // error test + { + name: "cluster has not joined kubeadmiral federation", + option: CommandUnjoinOption{}, + args: []string{"member-test-notjoined"}, + expectedErr: fmt.Errorf("cluster: %s has not joined kubeadmiral federation", "member-test-notjoined"), + }, + { + name: "cluster has joined, but secret does not exist", + option: CommandUnjoinOption{}, + args: []string{"member-test-no-secret"}, + expectedErr: fmt.Errorf("secret: %s/%s does not exist", "kube-admiral-system", "member-test-no-secret"), + }, + } + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.KubeConfig = utilpointer.String("/home/jzd/.kube/kubeadmiral/kubeadmiral.config") + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + assert := assert.New(t) + _ = testCase.option.ToOptions(util.NewFactory(defaultConfigFlags), testCase.args) + err := testCase.option.Validate() + assert.Equal(testCase.expectedErr, err) + }) + } +} diff --git a/pkg/admiralctl/util/factory.go b/pkg/admiralctl/util/factory.go new file mode 100644 index 00000000..7f4a4f07 --- /dev/null +++ b/pkg/admiralctl/util/factory.go @@ -0,0 +1,90 @@ +package util + +import ( + "context" + + fedclient "github.com/kubewharf/kubeadmiral/pkg/client/clientset/versioned" + "github.com/kubewharf/kubeadmiral/pkg/controllers/common" + clusterutil "github.com/kubewharf/kubeadmiral/pkg/util/cluster" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/kubernetes" + cmdutil "k8s.io/kubectl/pkg/cmd/util" +) + +type Factory interface { + cmdutil.Factory + + NewClusterFactoryByClusterName(clusterName string) (cmdutil.Factory, error) +} + +var _ Factory = &factoryImpl{} + +// factoryImpl is the implementation of Factory +type factoryImpl struct { + cmdutil.Factory + + // kubeConfigFlags holds all the flags specified by user. + // These flags will be inherited by the member cluster's client. + kubeConfigFlags *genericclioptions.ConfigFlags +} + +// NewClusterFactoryByClusterName create a new ClusterFactory by ClusterName +func (f *factoryImpl) NewClusterFactoryByClusterName(clusterName string) (cmdutil.Factory, error) { + restConfig, err := f.ToRESTConfig() + if err != nil { + return nil, err + } + + fedClientset, err := fedclient.NewForConfig(restConfig) + if err != nil { + return nil, err + } + + cluster, err := fedClientset.CoreV1alpha1().FederatedClusters().Get( + context.TODO(), + clusterName, + metav1.GetOptions{}, + ) + if err != nil { + return nil, err + } + + kubeClientset, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return nil, err + } + + config, err := clusterutil.BuildClusterConfig(cluster, kubeClientset, restConfig, common.DefaultFedSystemNamespace) + if err != nil { + return nil, err + } + + kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag() + kubeConfigFlags.APIServer = &config.Host + kubeConfigFlags.BearerToken = &config.BearerToken + kubeConfigFlags.KeyFile = &config.KeyFile + kubeConfigFlags.CAFile = &config.TLSClientConfig.CAFile + kubeConfigFlags.CertFile = &config.TLSClientConfig.CertFile + kubeConfigFlags.Insecure = &config.Insecure + + return cmdutil.NewFactory(kubeConfigFlags), nil +} + +// NewFactory creates a new factory +func NewFactory(kubeConfigFlags *genericclioptions.ConfigFlags) Factory { + matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) + f := &factoryImpl{ + kubeConfigFlags: kubeConfigFlags, + Factory: cmdutil.NewFactory(matchVersionKubeConfigFlags), + } + return f +} + +// NewClusterFactoryByKubeConfig create a new ClusterFactory by KubeConfig +func NewClusterFactoryByKubeConfig(clusterKubeConfig, clusterContext string) (cmdutil.Factory, error) { + configFlags := genericclioptions.NewConfigFlags(true) + configFlags.KubeConfig = &clusterKubeConfig + configFlags.Context = &clusterContext + return cmdutil.NewFactory(configFlags), nil +}