mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-08-12 16:55:31 -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
|
@ -9,6 +9,7 @@ go_library(
|
|||
"create.go",
|
||||
"iam.go",
|
||||
"rollback.go",
|
||||
"status.go",
|
||||
"terminate.go",
|
||||
"upgrade.go",
|
||||
"validators.go",
|
||||
|
|
92
cli/internal/cloudcmd/status.go
Normal file
92
cli/internal/cloudcmd/status.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package cloudcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// TargetVersions bundles version information about the target versions of a cluster.
|
||||
type TargetVersions struct {
|
||||
// image version
|
||||
image string
|
||||
// CSP specific path to the image
|
||||
imageReference string
|
||||
// kubernetes version
|
||||
kubernetes string
|
||||
}
|
||||
|
||||
// NewTargetVersions returns the target versions for the cluster.
|
||||
func NewTargetVersions(nodeVersion updatev1alpha1.NodeVersion) (TargetVersions, error) {
|
||||
return TargetVersions{
|
||||
image: nodeVersion.Spec.ImageVersion,
|
||||
imageReference: nodeVersion.Spec.ImageReference,
|
||||
kubernetes: nodeVersion.Spec.KubernetesClusterVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Image return the image version.
|
||||
func (c *TargetVersions) Image() string {
|
||||
return c.image
|
||||
}
|
||||
|
||||
// ImagePath return the image path.
|
||||
func (c *TargetVersions) ImagePath() string {
|
||||
return c.imageReference
|
||||
}
|
||||
|
||||
// Kubernetes return the Kubernetes version.
|
||||
func (c *TargetVersions) Kubernetes() string {
|
||||
return c.kubernetes
|
||||
}
|
||||
|
||||
// ClusterStatus returns a map from node name to NodeStatus.
|
||||
func ClusterStatus(ctx context.Context, kubeclient kubeClient) (map[string]NodeStatus, error) {
|
||||
nodes, err := kubeclient.GetNodes(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting nodes: %w", err)
|
||||
}
|
||||
|
||||
clusterStatus := map[string]NodeStatus{}
|
||||
for _, node := range nodes {
|
||||
clusterStatus[node.ObjectMeta.Name] = NewNodeStatus(node)
|
||||
}
|
||||
|
||||
return clusterStatus, nil
|
||||
}
|
||||
|
||||
// NodeStatus bundles status information about a node.
|
||||
type NodeStatus struct {
|
||||
kubeletVersion string
|
||||
imageVersion string
|
||||
}
|
||||
|
||||
// NewNodeStatus returns a new NodeStatus.
|
||||
func NewNodeStatus(node corev1.Node) NodeStatus {
|
||||
return NodeStatus{
|
||||
kubeletVersion: node.Status.NodeInfo.KubeletVersion,
|
||||
imageVersion: node.ObjectMeta.Annotations["constellation.edgeless.systems/node-image"],
|
||||
}
|
||||
}
|
||||
|
||||
// KubeletVersion returns the kubelet version of the node.
|
||||
func (n *NodeStatus) KubeletVersion() string {
|
||||
return n.kubeletVersion
|
||||
}
|
||||
|
||||
// ImageVersion returns the node image of the node.
|
||||
func (n *NodeStatus) ImageVersion() string {
|
||||
return n.imageVersion
|
||||
}
|
||||
|
||||
type kubeClient interface {
|
||||
GetNodes(ctx context.Context) ([]corev1.Node, error)
|
||||
}
|
|
@ -40,10 +40,24 @@ import (
|
|||
// ErrInProgress signals that an upgrade is in progress inside the cluster.
|
||||
var ErrInProgress = errors.New("upgrade in progress")
|
||||
|
||||
// GetConstellationVersion queries the constellation-version object for a given field.
|
||||
func GetConstellationVersion(ctx context.Context, client DynamicInterface) (updatev1alpha1.NodeVersion, error) {
|
||||
raw, err := client.GetCurrent(ctx, "constellation-version")
|
||||
if err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, err
|
||||
}
|
||||
var nodeVersion updatev1alpha1.NodeVersion
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.UnstructuredContent(), &nodeVersion); err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, fmt.Errorf("converting unstructured to NodeVersion: %w", err)
|
||||
}
|
||||
|
||||
return nodeVersion, nil
|
||||
}
|
||||
|
||||
// Upgrader handles upgrading the cluster's components using the CLI.
|
||||
type Upgrader struct {
|
||||
stableInterface stableInterface
|
||||
dynamicInterface dynamicInterface
|
||||
dynamicInterface DynamicInterface
|
||||
helmClient helmInterface
|
||||
imageFetcher imageFetcher
|
||||
outWriter io.Writer
|
||||
|
@ -75,7 +89,7 @@ func NewUpgrader(outWriter io.Writer, log debugLog) (*Upgrader, error) {
|
|||
|
||||
return &Upgrader{
|
||||
stableInterface: &stableClient{client: kubeClient},
|
||||
dynamicInterface: &dynamicClient{client: unstructuredClient},
|
||||
dynamicInterface: &NodeVersionClient{client: unstructuredClient},
|
||||
helmClient: helmClient,
|
||||
imageFetcher: image.New(),
|
||||
outWriter: outWriter,
|
||||
|
@ -168,7 +182,7 @@ func (u *Upgrader) KubernetesVersion() (string, error) {
|
|||
|
||||
// CurrentImage returns the currently used image version of the cluster.
|
||||
func (u *Upgrader) CurrentImage(ctx context.Context) (string, error) {
|
||||
nodeVersion, err := u.getConstellationVersion(ctx)
|
||||
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting constellation-version: %w", err)
|
||||
}
|
||||
|
@ -177,7 +191,7 @@ func (u *Upgrader) CurrentImage(ctx context.Context) (string, error) {
|
|||
|
||||
// CurrentKubernetesVersion returns the currently used Kubernetes version.
|
||||
func (u *Upgrader) CurrentKubernetesVersion(ctx context.Context) (string, error) {
|
||||
nodeVersion, err := u.getConstellationVersion(ctx)
|
||||
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting constellation-version: %w", err)
|
||||
}
|
||||
|
@ -248,7 +262,7 @@ func (u *Upgrader) applyNodeVersion(ctx context.Context, nodeVersion updatev1alp
|
|||
}
|
||||
u.log.Debugf("Triggering NodeVersion upgrade now")
|
||||
// Send the updated NodeVersion resource
|
||||
updated, err := u.dynamicInterface.update(ctx, &unstructured.Unstructured{Object: raw})
|
||||
updated, err := u.dynamicInterface.Update(ctx, &unstructured.Unstructured{Object: raw})
|
||||
if err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, fmt.Errorf("updating NodeVersion: %w", err)
|
||||
}
|
||||
|
@ -262,7 +276,7 @@ func (u *Upgrader) applyNodeVersion(ctx context.Context, nodeVersion updatev1alp
|
|||
}
|
||||
|
||||
func (u *Upgrader) checkClusterStatus(ctx context.Context) (updatev1alpha1.NodeVersion, error) {
|
||||
nodeVersion, err := u.getConstellationVersion(ctx)
|
||||
nodeVersion, err := GetConstellationVersion(ctx, u.dynamicInterface)
|
||||
if err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, fmt.Errorf("retrieving current image: %w", err)
|
||||
}
|
||||
|
@ -306,18 +320,38 @@ func (u *Upgrader) updateK8s(nodeVersion *updatev1alpha1.NodeVersion, newCluster
|
|||
return &configMap, nil
|
||||
}
|
||||
|
||||
// getFromConstellationVersion queries the constellation-version object for a given field.
|
||||
func (u *Upgrader) getConstellationVersion(ctx context.Context) (updatev1alpha1.NodeVersion, error) {
|
||||
raw, err := u.dynamicInterface.getCurrent(ctx, "constellation-version")
|
||||
if err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, err
|
||||
}
|
||||
var nodeVersion updatev1alpha1.NodeVersion
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.UnstructuredContent(), &nodeVersion); err != nil {
|
||||
return updatev1alpha1.NodeVersion{}, fmt.Errorf("converting unstructured to NodeVersion: %w", err)
|
||||
}
|
||||
// NodeVersionClient implements the DynamicInterface interface to interact with NodeVersion objects.
|
||||
type NodeVersionClient struct {
|
||||
client dynamic.Interface
|
||||
}
|
||||
|
||||
return nodeVersion, nil
|
||||
// NewNodeVersionClient returns a new NodeVersionClient.
|
||||
func NewNodeVersionClient(client dynamic.Interface) *NodeVersionClient {
|
||||
return &NodeVersionClient{client: client}
|
||||
}
|
||||
|
||||
// GetCurrent returns the current NodeVersion object.
|
||||
func (u *NodeVersionClient) GetCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error) {
|
||||
return u.client.Resource(schema.GroupVersionResource{
|
||||
Group: "update.edgeless.systems",
|
||||
Version: "v1alpha1",
|
||||
Resource: "nodeversions",
|
||||
}).Get(ctx, name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// Update updates the NodeVersion object.
|
||||
func (u *NodeVersionClient) Update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return u.client.Resource(schema.GroupVersionResource{
|
||||
Group: "update.edgeless.systems",
|
||||
Version: "v1alpha1",
|
||||
Resource: "nodeversions",
|
||||
}).Update(ctx, obj, metav1.UpdateOptions{})
|
||||
}
|
||||
|
||||
// DynamicInterface is a general interface to query custom resources.
|
||||
type DynamicInterface interface {
|
||||
GetCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error)
|
||||
Update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
// upgradeInProgress checks if an upgrade is in progress.
|
||||
|
@ -338,11 +372,6 @@ func upgradeInProgress(nodeVersion updatev1alpha1.NodeVersion) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
type dynamicInterface interface {
|
||||
getCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error)
|
||||
update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type stableInterface interface {
|
||||
getCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
|
||||
updateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
|
||||
|
@ -350,28 +379,6 @@ type stableInterface interface {
|
|||
kubernetesVersion() (string, error)
|
||||
}
|
||||
|
||||
type dynamicClient struct {
|
||||
client dynamic.Interface
|
||||
}
|
||||
|
||||
// getCurrent returns the current image definition.
|
||||
func (u *dynamicClient) getCurrent(ctx context.Context, name string) (*unstructured.Unstructured, error) {
|
||||
return u.client.Resource(schema.GroupVersionResource{
|
||||
Group: "update.edgeless.systems",
|
||||
Version: "v1alpha1",
|
||||
Resource: "nodeversions",
|
||||
}).Get(ctx, name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// update updates the image definition.
|
||||
func (u *dynamicClient) update(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return u.client.Resource(schema.GroupVersionResource{
|
||||
Group: "update.edgeless.systems",
|
||||
Version: "v1alpha1",
|
||||
Resource: "nodeversions",
|
||||
}).Update(ctx, obj, metav1.UpdateOptions{})
|
||||
}
|
||||
|
||||
type stableClient struct {
|
||||
client kubernetes.Interface
|
||||
}
|
||||
|
|
|
@ -426,11 +426,11 @@ type stubDynamicClient struct {
|
|||
updateErr error
|
||||
}
|
||||
|
||||
func (u *stubDynamicClient) getCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
|
||||
func (u *stubDynamicClient) GetCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
|
||||
return u.object, u.getErr
|
||||
}
|
||||
|
||||
func (u *stubDynamicClient) update(_ context.Context, updatedObject *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
func (u *stubDynamicClient) Update(_ context.Context, updatedObject *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
u.updatedObject = updatedObject
|
||||
return u.updatedObject, u.updateErr
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue