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
|
@ -11,14 +11,15 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubecmd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
const successOutput = targetVersions + versionsOutput + nodesUpToDateOutput + attestationConfigOutput
|
||||
|
@ -47,42 +48,6 @@ const versionsOutput = `Service versions:
|
|||
|
||||
const attestationConfigOutput = `Attestation config:
|
||||
measurements:
|
||||
0:
|
||||
expected: 737f767a12f54e70eecbc8684011323ae2fe2dd9f90785577969d7a2013e8c12
|
||||
warnOnly: true
|
||||
2:
|
||||
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||
warnOnly: true
|
||||
3:
|
||||
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||
warnOnly: true
|
||||
4:
|
||||
expected: 55f7616b2c51dd7603f491c1c266373fe5c1e25e06a851d2090960172b03b27f
|
||||
warnOnly: false
|
||||
6:
|
||||
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||
warnOnly: true
|
||||
7:
|
||||
expected: fb71e5e55cefba9e2b396d17604de0fe6e1841a76758856a120833e3ad1c40a3
|
||||
warnOnly: true
|
||||
8:
|
||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
warnOnly: false
|
||||
9:
|
||||
expected: f7480d37929bef4b61c32823cb7b3771aea19f7510db2e1478719a1d88f9775d
|
||||
warnOnly: false
|
||||
11:
|
||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
warnOnly: false
|
||||
12:
|
||||
expected: b8038d11eade4cfee5fd41da04bf64e58bab15c42bfe01801e4c0f61376ba010
|
||||
warnOnly: false
|
||||
13:
|
||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
warnOnly: false
|
||||
14:
|
||||
expected: d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f
|
||||
warnOnly: true
|
||||
15:
|
||||
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
warnOnly: false
|
||||
|
@ -90,17 +55,22 @@ const attestationConfigOutput = `Attestation config:
|
|||
|
||||
// TestStatus checks that the status function produces the correct strings.
|
||||
func TestStatus(t *testing.T) {
|
||||
mustParseNodeVersion := func(nV updatev1alpha1.NodeVersion) kubecmd.NodeVersion {
|
||||
nodeVersion, err := kubecmd.NewNodeVersion(nV)
|
||||
require.NoError(t, err)
|
||||
return nodeVersion
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
kubeClient stubKubeClient
|
||||
nodeVersion updatev1alpha1.NodeVersion
|
||||
dynamicErr error
|
||||
attestVariant variant.Variant
|
||||
expectedOutput string
|
||||
wantErr bool
|
||||
}{
|
||||
"success": {
|
||||
kubeClient: stubKubeClient{
|
||||
nodes: []corev1.Node{
|
||||
{
|
||||
status: map[string]kubecmd.NodeStatus{
|
||||
"outdated": kubecmd.NewNodeStatus(corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node1",
|
||||
Annotations: map[string]string{
|
||||
|
@ -112,29 +82,35 @@ func TestStatus(t *testing.T) {
|
|||
KubeletVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
version: mustParseNodeVersion(updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
nodeVersion: updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Node version of every node is up to date",
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Node version of every node is up to date",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
attestation: &config.QEMUVTPM{
|
||||
Measurements: measurements.M{
|
||||
15: measurements.WithAllBytes(0, measurements.Enforce, measurements.PCRMeasurementLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
attestVariant: variant.QEMUVTPM{},
|
||||
expectedOutput: successOutput,
|
||||
},
|
||||
"one of two nodes not upgraded": {
|
||||
kubeClient: stubKubeClient{
|
||||
nodes: []corev1.Node{
|
||||
{
|
||||
status: map[string]kubecmd.NodeStatus{
|
||||
"outdated": kubecmd.NewNodeStatus(corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "outdated",
|
||||
Annotations: map[string]string{
|
||||
|
@ -146,8 +122,8 @@ func TestStatus(t *testing.T) {
|
|||
KubeletVersion: "v1.2.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
}),
|
||||
"uptodate": kubecmd.NewNodeStatus(corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "uptodate",
|
||||
Annotations: map[string]string{
|
||||
|
@ -159,25 +135,123 @@ func TestStatus(t *testing.T) {
|
|||
KubeletVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
version: mustParseNodeVersion(updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
nodeVersion: updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Some node versions are out of date",
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Some node versions are out of date",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
attestation: &config.QEMUVTPM{
|
||||
Measurements: measurements.M{
|
||||
15: measurements.WithAllBytes(0, measurements.Enforce, measurements.PCRMeasurementLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
attestVariant: variant.QEMUVTPM{},
|
||||
expectedOutput: inProgressOutput,
|
||||
},
|
||||
"error getting node status": {
|
||||
kubeClient: stubKubeClient{
|
||||
statusErr: assert.AnError,
|
||||
version: mustParseNodeVersion(updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Node version of every node is up to date",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
attestation: &config.QEMUVTPM{
|
||||
Measurements: measurements.M{
|
||||
15: measurements.WithAllBytes(0, measurements.Enforce, measurements.PCRMeasurementLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
attestVariant: variant.QEMUVTPM{},
|
||||
expectedOutput: successOutput,
|
||||
wantErr: true,
|
||||
},
|
||||
"error getting node version": {
|
||||
kubeClient: stubKubeClient{
|
||||
status: map[string]kubecmd.NodeStatus{
|
||||
"outdated": kubecmd.NewNodeStatus(corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node1",
|
||||
Annotations: map[string]string{
|
||||
"constellation.edgeless.systems/node-image": "v1.1.0",
|
||||
},
|
||||
},
|
||||
Status: corev1.NodeStatus{
|
||||
NodeInfo: corev1.NodeSystemInfo{
|
||||
KubeletVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
versionErr: assert.AnError,
|
||||
attestation: &config.QEMUVTPM{
|
||||
Measurements: measurements.M{
|
||||
15: measurements.WithAllBytes(0, measurements.Enforce, measurements.PCRMeasurementLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
attestVariant: variant.QEMUVTPM{},
|
||||
expectedOutput: successOutput,
|
||||
wantErr: true,
|
||||
},
|
||||
"error getting attestation config": {
|
||||
kubeClient: stubKubeClient{
|
||||
status: map[string]kubecmd.NodeStatus{
|
||||
"outdated": kubecmd.NewNodeStatus(corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node1",
|
||||
Annotations: map[string]string{
|
||||
"constellation.edgeless.systems/node-image": "v1.1.0",
|
||||
},
|
||||
},
|
||||
Status: corev1.NodeStatus{
|
||||
NodeInfo: corev1.NodeSystemInfo{
|
||||
KubeletVersion: "v1.2.3",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
version: mustParseNodeVersion(updatev1alpha1.NodeVersion{
|
||||
Spec: updatev1alpha1.NodeVersionSpec{
|
||||
ImageVersion: "v1.1.0",
|
||||
ImageReference: "v1.1.0",
|
||||
KubernetesClusterVersion: "v1.2.3",
|
||||
},
|
||||
Status: updatev1alpha1.NodeVersionStatus{
|
||||
Conditions: []metav1.Condition{
|
||||
{
|
||||
Message: "Node version of every node is up to date",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
attestationErr: assert.AnError,
|
||||
},
|
||||
attestVariant: variant.QEMUVTPM{},
|
||||
expectedOutput: successOutput,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
@ -185,16 +259,11 @@ func TestStatus(t *testing.T) {
|
|||
require := require.New(t)
|
||||
assert := assert.New(t)
|
||||
|
||||
raw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.nodeVersion)
|
||||
require.NoError(err)
|
||||
configMapper := stubConfigMapperAWSNitro{}
|
||||
variant := variant.AWSNitroTPM{}
|
||||
output, err := status(
|
||||
context.Background(),
|
||||
tc.kubeClient,
|
||||
configMapper,
|
||||
stubGetVersions(versionsOutput),
|
||||
&stubDynamicInterface{data: unstructured.Unstructured{Object: raw}, err: tc.dynamicErr},
|
||||
tc.kubeClient,
|
||||
variant,
|
||||
)
|
||||
if tc.wantErr {
|
||||
|
@ -207,36 +276,25 @@ func TestStatus(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type stubConfigMapperAWSNitro struct{}
|
||||
|
||||
func (s stubConfigMapperAWSNitro) GetConfigMap(_ context.Context, _ string) (*corev1.ConfigMap, error) {
|
||||
return &corev1.ConfigMap{
|
||||
Data: map[string]string{
|
||||
"attestationConfig": `{"measurements":{"0":{"expected":"737f767a12f54e70eecbc8684011323ae2fe2dd9f90785577969d7a2013e8c12","warnOnly":true},"11":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"12":{"expected":"b8038d11eade4cfee5fd41da04bf64e58bab15c42bfe01801e4c0f61376ba010","warnOnly":false},"13":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"14":{"expected":"d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f","warnOnly":true},"15":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"2":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"3":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"4":{"expected":"55f7616b2c51dd7603f491c1c266373fe5c1e25e06a851d2090960172b03b27f","warnOnly":false},"6":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"7":{"expected":"fb71e5e55cefba9e2b396d17604de0fe6e1841a76758856a120833e3ad1c40a3","warnOnly":true},"8":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"9":{"expected":"f7480d37929bef4b61c32823cb7b3771aea19f7510db2e1478719a1d88f9775d","warnOnly":false}}}`,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type stubKubeClient struct {
|
||||
nodes []corev1.Node
|
||||
err error
|
||||
status map[string]kubecmd.NodeStatus
|
||||
statusErr error
|
||||
version kubecmd.NodeVersion
|
||||
versionErr error
|
||||
attestation config.AttestationCfg
|
||||
attestationErr error
|
||||
}
|
||||
|
||||
func (s stubKubeClient) GetNodes(_ context.Context) ([]corev1.Node, error) {
|
||||
return s.nodes, s.err
|
||||
func (s stubKubeClient) ClusterStatus(_ context.Context) (map[string]kubecmd.NodeStatus, error) {
|
||||
return s.status, s.statusErr
|
||||
}
|
||||
|
||||
type stubDynamicInterface struct {
|
||||
data unstructured.Unstructured
|
||||
err error
|
||||
func (s stubKubeClient) GetConstellationVersion(_ context.Context) (kubecmd.NodeVersion, error) {
|
||||
return s.version, s.versionErr
|
||||
}
|
||||
|
||||
func (s *stubDynamicInterface) GetCurrent(_ context.Context, _ string) (*unstructured.Unstructured, error) {
|
||||
return &s.data, s.err
|
||||
}
|
||||
|
||||
func (s *stubDynamicInterface) Update(_ context.Context, _ *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return &s.data, s.err
|
||||
func (s stubKubeClient) GetClusterAttestationConfig(_ context.Context, _ variant.Variant) (config.AttestationCfg, error) {
|
||||
return s.attestation, s.attestationErr
|
||||
}
|
||||
|
||||
func stubGetVersions(output string) func() (fmt.Stringer, error) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue