mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-02 06:16:08 -04:00
cli: refactor kubernetes package (#2232)
* Clean up CLI kubernetes package * Rename CLI kubernetes pkg to kubecmd * Unify kubernetes clients * Refactor attestation config upgrade * Update CODEOWNERS file * Remove outdated GetMeasurementSalt --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
3bf316e28f
commit
afa7fd0edb
24 changed files with 1024 additions and 1160 deletions
|
@ -13,20 +13,16 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
||||
"github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// NewStatusCmd returns a new cobra.Command for the statuus command.
|
||||
|
@ -50,38 +46,17 @@ func runStatus(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
defer log.Sync()
|
||||
|
||||
kubeClient := kubectl.New()
|
||||
|
||||
flags, err := parseStatusFlags(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing flags: %w", err)
|
||||
}
|
||||
|
||||
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||
kubeConfig, err := fileHandler.Read(constants.AdminConfFilename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading admin.conf: %w", err)
|
||||
}
|
||||
|
||||
// need kubectl client to fetch nodes.
|
||||
if err := kubeClient.Initialize(kubeConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating k8s client config from kubeconfig: %w", err)
|
||||
}
|
||||
// need unstructed client to fetch NodeVersion CRD.
|
||||
unstructuredClient, err := dynamic.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up custom resource client: %w", err)
|
||||
}
|
||||
|
||||
// need helm client to fetch service versions.
|
||||
// The client used here, doesn't need to know the current workspace.
|
||||
// It may be refactored in the future for easier usage.
|
||||
helmClient, err := helm.NewUpgradeClient(kubectl.New(), constants.UpgradeDir, constants.AdminConfFilename, constants.HelmNamespace, log)
|
||||
helmClient, err := helm.NewUpgradeClient(kubectl.NewUninitialized(), constants.UpgradeDir, constants.AdminConfFilename, constants.HelmNamespace, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up helm client: %w", err)
|
||||
}
|
||||
|
@ -97,11 +72,12 @@ func runStatus(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
variant := conf.GetAttestationConfig().GetVariant()
|
||||
|
||||
stableClient, err := kubernetes.NewStableClient(constants.AdminConfFilename)
|
||||
kubeClient, err := kubecmd.New(cmd.OutOrStdout(), constants.AdminConfFilename, log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up stable client: %w", err)
|
||||
return fmt.Errorf("setting up kubernetes client: %w", err)
|
||||
}
|
||||
output, err := status(cmd.Context(), kubeClient, stableClient, helmVersionGetter, kubernetes.NewNodeVersionClient(unstructuredClient), variant)
|
||||
|
||||
output, err := status(cmd.Context(), helmVersionGetter, kubeClient, variant)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting status: %w", err)
|
||||
}
|
||||
|
@ -111,19 +87,14 @@ func runStatus(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
// status queries the cluster for the relevant status information and returns the output string.
|
||||
func status(
|
||||
ctx context.Context, kubeClient kubeClient, cmClient configMapClient, getHelmVersions func() (fmt.Stringer, error),
|
||||
dynamicInterface kubernetes.DynamicInterface, attestVariant variant.Variant,
|
||||
func status(ctx context.Context, getHelmVersions func() (fmt.Stringer, error), kubeClient kubeCmd, attestVariant variant.Variant,
|
||||
) (string, error) {
|
||||
nodeVersion, err := kubernetes.GetConstellationVersion(ctx, dynamicInterface)
|
||||
nodeVersion, err := kubeClient.GetConstellationVersion(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting constellation version: %w", err)
|
||||
}
|
||||
if len(nodeVersion.Status.Conditions) != 1 {
|
||||
return "", fmt.Errorf("expected exactly one condition, got %d", len(nodeVersion.Status.Conditions))
|
||||
}
|
||||
|
||||
attestationConfig, err := getAttestationConfig(ctx, cmClient, attestVariant)
|
||||
attestationConfig, err := kubeClient.GetClusterAttestationConfig(ctx, attestVariant)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting attestation config: %w", err)
|
||||
}
|
||||
|
@ -132,51 +103,30 @@ func status(
|
|||
return "", fmt.Errorf("marshalling attestation config: %w", err)
|
||||
}
|
||||
|
||||
targetVersions, err := kubernetes.NewTargetVersions(nodeVersion)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting configured versions: %w", err)
|
||||
}
|
||||
|
||||
serviceVersions, err := getHelmVersions()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting service versions: %w", err)
|
||||
}
|
||||
|
||||
status, err := kubernetes.ClusterStatus(ctx, kubeClient)
|
||||
status, err := kubeClient.ClusterStatus(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting cluster status: %w", err)
|
||||
}
|
||||
|
||||
return statusOutput(targetVersions, serviceVersions, status, nodeVersion, string(prettyYAML)), nil
|
||||
}
|
||||
|
||||
func getAttestationConfig(ctx context.Context, cmClient configMapClient, attestVariant variant.Variant) (config.AttestationCfg, error) {
|
||||
joinConfig, err := cmClient.GetConfigMap(ctx, constants.JoinConfigMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting current config map: %w", err)
|
||||
}
|
||||
rawAttestationConfig, ok := joinConfig.Data[constants.AttestationConfigFilename]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("attestationConfig not found in %s", constants.JoinConfigMap)
|
||||
}
|
||||
attestationConfig, err := config.UnmarshalAttestationConfig([]byte(rawAttestationConfig), attestVariant)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshalling attestation config: %w", err)
|
||||
}
|
||||
return attestationConfig, nil
|
||||
return statusOutput(nodeVersion, serviceVersions, status, string(prettyYAML)), nil
|
||||
}
|
||||
|
||||
// statusOutput creates the status cmd output string by formatting the received information.
|
||||
func statusOutput(
|
||||
targetVersions kubernetes.TargetVersions, serviceVersions fmt.Stringer,
|
||||
status map[string]kubernetes.NodeStatus, nodeVersion v1alpha1.NodeVersion, rawAttestationConfig string,
|
||||
nodeVersion kubecmd.NodeVersion, serviceVersions fmt.Stringer,
|
||||
status map[string]kubecmd.NodeStatus, rawAttestationConfig string,
|
||||
) string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
builder.WriteString(targetVersionsString(targetVersions))
|
||||
builder.WriteString(targetVersionsString(nodeVersion))
|
||||
builder.WriteString(serviceVersions.String())
|
||||
builder.WriteString(fmt.Sprintf("Cluster status: %s\n", nodeVersion.Status.Conditions[0].Message))
|
||||
builder.WriteString(nodeStatusString(status, targetVersions))
|
||||
builder.WriteString(fmt.Sprintf("Cluster status: %s\n", nodeVersion.ClusterStatus()))
|
||||
builder.WriteString(nodeStatusString(status, nodeVersion))
|
||||
builder.WriteString(fmt.Sprintf("Attestation config:\n%s", indentEntireStringWithTab(rawAttestationConfig)))
|
||||
return builder.String()
|
||||
}
|
||||
|
@ -190,14 +140,14 @@ func indentEntireStringWithTab(input string) string {
|
|||
}
|
||||
|
||||
// nodeStatusString creates the node status part of the output string.
|
||||
func nodeStatusString(status map[string]kubernetes.NodeStatus, targetVersions kubernetes.TargetVersions) string {
|
||||
func nodeStatusString(status map[string]kubecmd.NodeStatus, targetVersions kubecmd.NodeVersion) string {
|
||||
var upToDateImages int
|
||||
var upToDateK8s int
|
||||
for _, node := range status {
|
||||
if node.KubeletVersion() == targetVersions.Kubernetes() {
|
||||
if node.KubeletVersion() == targetVersions.KubernetesVersion() {
|
||||
upToDateK8s++
|
||||
}
|
||||
if node.ImageVersion() == targetVersions.ImagePath() {
|
||||
if node.ImageVersion() == targetVersions.ImageReference() {
|
||||
upToDateImages++
|
||||
}
|
||||
}
|
||||
|
@ -212,11 +162,11 @@ func nodeStatusString(status map[string]kubernetes.NodeStatus, targetVersions ku
|
|||
}
|
||||
|
||||
// targetVersionsString creates the target versions part of the output string.
|
||||
func targetVersionsString(target kubernetes.TargetVersions) string {
|
||||
func targetVersionsString(target kubecmd.NodeVersion) string {
|
||||
builder := strings.Builder{}
|
||||
builder.WriteString("Target versions:\n")
|
||||
builder.WriteString(fmt.Sprintf("\tImage: %s\n", target.Image()))
|
||||
builder.WriteString(fmt.Sprintf("\tKubernetes: %s\n", target.Kubernetes()))
|
||||
builder.WriteString(fmt.Sprintf("\tImage: %s\n", target.ImageVersion()))
|
||||
builder.WriteString(fmt.Sprintf("\tKubernetes: %s\n", target.KubernetesVersion()))
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
@ -241,10 +191,8 @@ func parseStatusFlags(cmd *cobra.Command) (statusFlags, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
type kubeClient interface {
|
||||
GetNodes(ctx context.Context) ([]corev1.Node, error)
|
||||
}
|
||||
|
||||
type configMapClient interface {
|
||||
GetConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
|
||||
type kubeCmd interface {
|
||||
ClusterStatus(ctx context.Context) (map[string]kubecmd.NodeStatus, error)
|
||||
GetConstellationVersion(ctx context.Context) (kubecmd.NodeVersion, error)
|
||||
GetClusterAttestationConfig(ctx context.Context, variant variant.Variant) (config.AttestationCfg, error)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue