mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-08-08 06:52:26 -04:00
cli: add status cmd
The new command allows checking the status of an upgrade and which versions are installed. Also remove the unused restclient. And make GetConstellationVersion a function.
This commit is contained in:
parent
93e55d2f78
commit
c8c2953d7b
19 changed files with 707 additions and 835 deletions
|
@ -3,29 +3,20 @@ load("//bazel/go:go_test.bzl", "go_test")
|
|||
|
||||
go_library(
|
||||
name = "kubectl",
|
||||
srcs = [
|
||||
"kubectl.go",
|
||||
"restclient.go",
|
||||
],
|
||||
srcs = ["kubectl.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"@io_k8s_api//core/v1:core",
|
||||
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions/v1:apiextensions",
|
||||
"@io_k8s_apiextensions_apiserver//pkg/client/clientset/clientset/typed/apiextensions/v1:apiextensions",
|
||||
"@io_k8s_apimachinery//pkg/api/meta",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:meta",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1/unstructured",
|
||||
"@io_k8s_apimachinery//pkg/runtime",
|
||||
"@io_k8s_apimachinery//pkg/runtime/schema",
|
||||
"@io_k8s_apimachinery//pkg/runtime/serializer",
|
||||
"@io_k8s_cli_runtime//pkg/resource",
|
||||
"@io_k8s_client_go//discovery",
|
||||
"@io_k8s_client_go//discovery/cached/memory",
|
||||
"@io_k8s_client_go//dynamic",
|
||||
"@io_k8s_client_go//kubernetes",
|
||||
"@io_k8s_client_go//rest",
|
||||
"@io_k8s_client_go//restmapper",
|
||||
"@io_k8s_client_go//scale/scheme",
|
||||
"@io_k8s_client_go//tools/clientcmd",
|
||||
"@io_k8s_client_go//util/retry",
|
||||
|
@ -34,16 +25,7 @@ go_library(
|
|||
|
||||
go_test(
|
||||
name = "kubectl_test",
|
||||
srcs = [
|
||||
"kubectl_test.go",
|
||||
"restclient_test.go",
|
||||
],
|
||||
srcs = ["kubectl_test.go"],
|
||||
embed = [":kubectl"],
|
||||
deps = [
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
"@io_k8s_client_go//rest",
|
||||
"@io_k8s_client_go//tools/clientcmd",
|
||||
"@io_k8s_client_go//tools/clientcmd/api",
|
||||
],
|
||||
deps = ["@com_github_stretchr_testify//assert"],
|
||||
)
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/scale/scheme"
|
||||
|
@ -35,7 +34,6 @@ type Kubectl struct {
|
|||
kubernetes.Interface
|
||||
dynamicClient dynamic.Interface
|
||||
apiextensionClient apiextensionsclientv1.ApiextensionsV1Interface
|
||||
builder *resource.Builder
|
||||
}
|
||||
|
||||
// New returns an empty Kubectl client. Need to call Initialize before usable.
|
||||
|
@ -67,12 +65,6 @@ func (k *Kubectl) Initialize(kubeconfig []byte) error {
|
|||
}
|
||||
k.apiextensionClient = apiextensionClient
|
||||
|
||||
restClientGetter, err := newRESTClientGetter(kubeconfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating k8s RESTClientGetter from kubeconfig: %w", err)
|
||||
}
|
||||
k.builder = resource.NewBuilder(restClientGetter).Unstructured()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -92,22 +84,6 @@ func (k *Kubectl) ApplyCRD(ctx context.Context, rawCRD []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// parseCRD takes a byte slice of data and tries to create a CustomResourceDefinition object from it.
|
||||
func parseCRD(crdString []byte) (*v1.CustomResourceDefinition, error) {
|
||||
sch := runtime.NewScheme()
|
||||
_ = scheme.AddToScheme(sch)
|
||||
_ = v1.AddToScheme(sch)
|
||||
obj, groupVersionKind, err := serializer.NewCodecFactory(sch).UniversalDeserializer().Decode(crdString, nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding crd: %w", err)
|
||||
}
|
||||
if groupVersionKind.Kind == "CustomResourceDefinition" {
|
||||
return obj.(*v1.CustomResourceDefinition), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("parsed []byte, but did not find a CRD")
|
||||
}
|
||||
|
||||
// GetCRDs retrieves all custom resource definitions currently installed in the cluster.
|
||||
func (k *Kubectl) GetCRDs(ctx context.Context) ([]apiextensionsv1.CustomResourceDefinition, error) {
|
||||
crds, err := k.apiextensionClient.CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
|
||||
|
@ -159,6 +135,15 @@ func (k *Kubectl) ListAllNamespaces(ctx context.Context) (*corev1.NamespaceList,
|
|||
return k.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
|
||||
}
|
||||
|
||||
// GetNodes returns all nodes in the cluster.
|
||||
func (k *Kubectl) GetNodes(ctx context.Context) ([]corev1.Node, error) {
|
||||
nodes, err := k.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing nodes: %w", err)
|
||||
}
|
||||
return nodes.Items, nil
|
||||
}
|
||||
|
||||
// AddTolerationsToDeployment adds [K8s tolerations] to the deployment, identified
|
||||
// by name and namespace.
|
||||
//
|
||||
|
@ -213,3 +198,19 @@ func (k *Kubectl) AddNodeSelectorsToDeployment(ctx context.Context, selectors ma
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseCRD takes a byte slice of data and tries to create a CustomResourceDefinition object from it.
|
||||
func parseCRD(crdString []byte) (*v1.CustomResourceDefinition, error) {
|
||||
sch := runtime.NewScheme()
|
||||
_ = scheme.AddToScheme(sch)
|
||||
_ = v1.AddToScheme(sch)
|
||||
obj, groupVersionKind, err := serializer.NewCodecFactory(sch).UniversalDeserializer().Decode(crdString, nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding crd: %w", err)
|
||||
}
|
||||
if groupVersionKind.Kind == "CustomResourceDefinition" {
|
||||
return obj.(*v1.CustomResourceDefinition), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("parsed []byte, but did not find a CRD")
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// restClientGetter implements k8s.io/cli-runtime/pkg/resource.RESTClientGetter.
|
||||
type restClientGetter struct {
|
||||
clientconfig clientcmd.ClientConfig
|
||||
}
|
||||
|
||||
// newRESTClientGetter creates a new restClientGetter using a kubeconfig.
|
||||
func newRESTClientGetter(kubeconfig []byte) (*restClientGetter, error) {
|
||||
clientconfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawconfig, err := clientconfig.RawConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientconfig = clientcmd.NewDefaultClientConfig(rawconfig, &clientcmd.ConfigOverrides{})
|
||||
|
||||
return &restClientGetter{clientconfig}, nil
|
||||
}
|
||||
|
||||
// ToRESTConfig returns k8s REST client config.
|
||||
func (r *restClientGetter) ToRESTConfig() (*rest.Config, error) {
|
||||
return r.clientconfig.ClientConfig()
|
||||
}
|
||||
|
||||
// ToDiscoveryClient creates new k8s discovery client from restClientGetter.
|
||||
func (r *restClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
||||
restconfig, err := r.clientconfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dc, err := discovery.NewDiscoveryClientForConfig(restconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return memory.NewMemCacheClient(dc), nil
|
||||
}
|
||||
|
||||
// ToRESTMapper creates new k8s RESTMapper from restClientGetter.
|
||||
func (r *restClientGetter) ToRESTMapper() (meta.RESTMapper, error) {
|
||||
dc, err := r.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return restmapper.NewDeferredDiscoveryRESTMapper(dc), nil
|
||||
}
|
||||
|
||||
// ToRawKubeConfigLoader returns the inner k8s ClientConfig.
|
||||
func (r *restClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
|
||||
return r.clientconfig
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
const testingKubeconfig = `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: ""
|
||||
server: https://192.0.2.0:6443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: kubernetes-admin
|
||||
name: kubernetes-admin@kubernetes
|
||||
current-context: kubernetes-admin@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kubernetes-admin
|
||||
user:
|
||||
client-certificate-data: ""
|
||||
client-key-data: ""
|
||||
`
|
||||
|
||||
type stubClientConfig struct {
|
||||
rawConfigConfig clientcmdapi.Config
|
||||
rawConfigErr error
|
||||
clientConfigConfig *restclient.Config
|
||||
clientConfigErr error
|
||||
namespaceString string
|
||||
namespaceOverridden bool
|
||||
namespaceErr error
|
||||
configAccessResult clientcmd.ConfigAccess
|
||||
}
|
||||
|
||||
func (s *stubClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
||||
return s.rawConfigConfig, s.rawConfigErr
|
||||
}
|
||||
|
||||
func (s *stubClientConfig) ClientConfig() (*restclient.Config, error) {
|
||||
return s.clientConfigConfig, s.clientConfigErr
|
||||
}
|
||||
|
||||
func (s *stubClientConfig) Namespace() (string, bool, error) {
|
||||
return s.namespaceString, s.namespaceOverridden, s.namespaceErr
|
||||
}
|
||||
|
||||
func (s *stubClientConfig) ConfigAccess() clientcmd.ConfigAccess {
|
||||
return s.configAccessResult
|
||||
}
|
||||
|
||||
func TestNewRESTClientGetter(t *testing.T) {
|
||||
require := require.New(t)
|
||||
result, err := newRESTClientGetter([]byte(testingKubeconfig))
|
||||
require.NoError(err)
|
||||
require.NotNil(result)
|
||||
}
|
||||
|
||||
func TestToRESTConfig(t *testing.T) {
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &stubClientConfig{
|
||||
clientConfigConfig: &restclient.Config{},
|
||||
},
|
||||
}
|
||||
result, err := getter.ToRESTConfig()
|
||||
require.NoError(err)
|
||||
require.NotNil(result)
|
||||
}
|
||||
|
||||
func TestToDiscoveryClient(t *testing.T) {
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &stubClientConfig{
|
||||
clientConfigConfig: &restclient.Config{},
|
||||
},
|
||||
}
|
||||
result, err := getter.ToDiscoveryClient()
|
||||
require.NoError(err)
|
||||
require.NotNil(result)
|
||||
}
|
||||
|
||||
func TestToDiscoveryClientFail(t *testing.T) {
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &stubClientConfig{
|
||||
clientConfigErr: errors.New("someErr"),
|
||||
},
|
||||
}
|
||||
_, err := getter.ToDiscoveryClient()
|
||||
require.Error(err)
|
||||
}
|
||||
|
||||
func TestToRESTMapper(t *testing.T) {
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &stubClientConfig{
|
||||
clientConfigConfig: &restclient.Config{},
|
||||
},
|
||||
}
|
||||
result, err := getter.ToRESTMapper()
|
||||
require.NoError(err)
|
||||
require.NotNil(result)
|
||||
}
|
||||
|
||||
func TestToRESTMapperFail(t *testing.T) {
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &stubClientConfig{
|
||||
clientConfigErr: errors.New("someErr"),
|
||||
},
|
||||
}
|
||||
_, err := getter.ToRESTMapper()
|
||||
require.Error(err)
|
||||
}
|
||||
|
||||
func TestToRawKubeConfigLoader(t *testing.T) {
|
||||
clientConfig := stubClientConfig{
|
||||
clientConfigConfig: &restclient.Config{},
|
||||
}
|
||||
require := require.New(t)
|
||||
getter := restClientGetter{
|
||||
clientconfig: &clientConfig,
|
||||
}
|
||||
result := getter.ToRawKubeConfigLoader()
|
||||
require.Equal(&clientConfig, result)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue