diff --git a/.github/actions/constellation_create/action.yml b/.github/actions/constellation_create/action.yml index 49bb547df..8fa6e2ab6 100644 --- a/.github/actions/constellation_create/action.yml +++ b/.github/actions/constellation_create/action.yml @@ -73,6 +73,8 @@ runs: run: | constellation config generate ${{ inputs.cloudProvider }} + yq eval -i "(.name) = \"e2e-test\"" constellation-conf.yaml + yq eval -i \ "(.provider | select(. | has(\"azure\")).azure.subscription) = \"${{ inputs.azureSubscription }}\" | (.provider | select(. | has(\"azure\")).azure.tenant) = \"${{ inputs.azureTenant }}\" | @@ -158,7 +160,7 @@ runs: echo "Creating cluster using config:" cat constellation-conf.yaml sudo sh -c 'echo "127.0.0.1 license.confidential.cloud" >> /etc/hosts' || true - constellation create -c ${{ inputs.controlNodesCount }} -w ${{ inputs.workerNodesCount }} --name e2e-test -y --force + constellation create -c ${{ inputs.controlNodesCount }} -w ${{ inputs.workerNodesCount }} -y --force - name: Cdbg deploy if: inputs.isDebugImage == 'true' diff --git a/bootstrapper/cmd/bootstrapper/test.go b/bootstrapper/cmd/bootstrapper/test.go index 6816adecd..b0996fe5e 100644 --- a/bootstrapper/cmd/bootstrapper/test.go +++ b/bootstrapper/cmd/bootstrapper/test.go @@ -21,7 +21,7 @@ type clusterFake struct{} // InitCluster fakes bootstrapping a new cluster with the current node being the master, returning the arguments required to join the cluster. func (c *clusterFake) InitCluster( - context.Context, string, string, []byte, []uint32, bool, bool, + context.Context, string, string, string, []byte, []uint32, bool, bool, []byte, bool, components.Components, *logger.Logger, ) ([]byte, error) { return []byte{}, nil diff --git a/bootstrapper/initproto/init.pb.go b/bootstrapper/initproto/init.pb.go index ac7318e7c..77bbcde19 100644 --- a/bootstrapper/initproto/init.pb.go +++ b/bootstrapper/initproto/init.pb.go @@ -41,6 +41,7 @@ type InitRequest struct { ConformanceMode bool `protobuf:"varint,14,opt,name=conformance_mode,json=conformanceMode,proto3" json:"conformance_mode,omitempty"` KubernetesComponents []*KubernetesComponent `protobuf:"bytes,15,rep,name=kubernetes_components,json=kubernetesComponents,proto3" json:"kubernetes_components,omitempty"` InitSecret []byte `protobuf:"bytes,16,opt,name=init_secret,json=initSecret,proto3" json:"init_secret,omitempty"` + ClusterName string `protobuf:"bytes,17,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"` } func (x *InitRequest) Reset() { @@ -173,6 +174,13 @@ func (x *InitRequest) GetInitSecret() []byte { return nil } +func (x *InitRequest) GetClusterName() string { + if x != nil { + return x.ClusterName + } + return "" +} + type InitResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -311,7 +319,7 @@ var File_init_proto protoreflect.FileDescriptor var file_init_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x69, 0x6e, - 0x69, 0x74, 0x22, 0xe4, 0x04, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x69, 0x74, 0x22, 0x87, 0x05, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x75, @@ -349,29 +357,31 @@ var file_init_proto_rawDesc = []byte{ 0x6e, 0x74, 0x52, 0x14, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, - 0x6e, 0x69, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x68, 0x0a, 0x0c, 0x49, 0x6e, 0x69, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6b, 0x75, 0x62, - 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6b, - 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x78, 0x0a, 0x13, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, - 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x50, - 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x32, 0x34, 0x0a, - 0x03, 0x41, 0x50, 0x49, 0x12, 0x2d, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x11, 0x2e, 0x69, - 0x6e, 0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x12, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, - 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x62, - 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x69, 0x74, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x69, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a, 0x0c, + 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x78, 0x0a, 0x13, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x32, 0x34, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x2d, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, + 0x11, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, + 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, + 0x32, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2f, 0x69, + 0x6e, 0x69, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/bootstrapper/initproto/init.proto b/bootstrapper/initproto/init.proto index e3d02865c..4cee0f118 100644 --- a/bootstrapper/initproto/init.proto +++ b/bootstrapper/initproto/init.proto @@ -25,6 +25,7 @@ message InitRequest { bool conformance_mode = 14; repeated KubernetesComponent kubernetes_components = 15; bytes init_secret = 16; + string cluster_name = 17; } message InitResponse { diff --git a/bootstrapper/internal/initserver/initserver.go b/bootstrapper/internal/initserver/initserver.go index ecbc6b786..b84edd6e8 100644 --- a/bootstrapper/internal/initserver/initserver.go +++ b/bootstrapper/internal/initserver/initserver.go @@ -161,9 +161,15 @@ func (s *Server) Init(ctx context.Context, req *initproto.InitRequest) (*initpro // Check if we are running on a CVM _, isCVM := s.issuer.(*snp.Issuer) + clusterName := req.ClusterName + if clusterName == "" { + clusterName = "constellation" + } + kubeconfig, err := s.initializer.InitCluster(ctx, req.CloudServiceAccountUri, req.KubernetesVersion, + clusterName, measurementSalt, req.EnforcedPcrs, req.EnforceIdkeydigest, @@ -237,6 +243,7 @@ type ClusterInitializer interface { ctx context.Context, cloudServiceAccountURI string, k8sVersion string, + clusterName string, measurementSalt []byte, enforcedPcrs []uint32, enforceIDKeyDigest bool, diff --git a/bootstrapper/internal/initserver/initserver_test.go b/bootstrapper/internal/initserver/initserver_test.go index 7373bc14e..2f5b3398c 100644 --- a/bootstrapper/internal/initserver/initserver_test.go +++ b/bootstrapper/internal/initserver/initserver_test.go @@ -314,7 +314,7 @@ type stubClusterInitializer struct { } func (i *stubClusterInitializer) InitCluster( - context.Context, string, string, []byte, []uint32, bool, bool, + context.Context, string, string, string, []byte, []uint32, bool, bool, []byte, bool, components.Components, *logger.Logger, ) ([]byte, error) { return i.initClusterKubeconfig, i.initClusterErr diff --git a/bootstrapper/internal/kubernetes/k8sapi/k8sutil.go b/bootstrapper/internal/kubernetes/k8sapi/k8sutil.go index 48b305c0c..5e3b4701e 100644 --- a/bootstrapper/internal/kubernetes/k8sapi/k8sutil.go +++ b/bootstrapper/internal/kubernetes/k8sapi/k8sutil.go @@ -28,6 +28,7 @@ import ( "github.com/edgelesssys/constellation/v2/internal/role" "github.com/edgelesssys/constellation/v2/internal/versions/components" corev1 "k8s.io/api/core/v1" + "k8s.io/apiserver/pkg/authentication/user" kubeconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "github.com/edgelesssys/constellation/v2/internal/crypto" @@ -87,25 +88,26 @@ func (k *KubernetesUtil) InstallComponents(ctx context.Context, kubernetesCompon } // InitCluster instruments kubeadm to initialize the K8s cluster. +// On success an admin kubeconfig file is returned. func (k *KubernetesUtil) InitCluster( - ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger, -) error { + ctx context.Context, initConfig []byte, nodeName, clusterName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger, +) ([]byte, error) { // TODO: audit policy should be user input auditPolicy, err := resources.NewDefaultAuditPolicy().Marshal() if err != nil { - return fmt.Errorf("generating default audit policy: %w", err) + return nil, fmt.Errorf("generating default audit policy: %w", err) } if err := os.WriteFile(auditPolicyPath, auditPolicy, 0o644); err != nil { - return fmt.Errorf("writing default audit policy: %w", err) + return nil, fmt.Errorf("writing default audit policy: %w", err) } initConfigFile, err := os.CreateTemp("", "kubeadm-init.*.yaml") if err != nil { - return fmt.Errorf("creating init config file %v: %w", initConfigFile.Name(), err) + return nil, fmt.Errorf("creating init config file %v: %w", initConfigFile.Name(), err) } if _, err := initConfigFile.Write(initConfig); err != nil { - return fmt.Errorf("writing kubeadm init yaml config %v: %w", initConfigFile.Name(), err) + return nil, fmt.Errorf("writing kubeadm init yaml config %v: %w", initConfigFile.Name(), err) } // preflight @@ -115,9 +117,9 @@ func (k *KubernetesUtil) InitCluster( if err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) { - return fmt.Errorf("kubeadm init phase preflight failed (code %v) with: %s", exitErr.ExitCode(), out) + return nil, fmt.Errorf("kubeadm init phase preflight failed (code %v) with: %s", exitErr.ExitCode(), out) } - return fmt.Errorf("kubeadm init: %w", err) + return nil, fmt.Errorf("kubeadm init: %w", err) } // create CA certs @@ -127,20 +129,20 @@ func (k *KubernetesUtil) InitCluster( if err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) { - return fmt.Errorf("kubeadm init phase certs all failed (code %v) with: %s", exitErr.ExitCode(), out) + return nil, fmt.Errorf("kubeadm init phase certs all failed (code %v) with: %s", exitErr.ExitCode(), out) } - return fmt.Errorf("kubeadm init: %w", err) + return nil, fmt.Errorf("kubeadm init: %w", err) } // create kubelet key and CA signed certificate for the node log.Infof("Creating signed kubelet certificate") if err := k.createSignedKubeletCert(nodeName, ips); err != nil { - return err + return nil, fmt.Errorf("creating signed kubelete certificate: %w", err) } log.Infof("Preparing node for Konnectivity") if err := k.prepareControlPlaneForKonnectivity(ctx, controlPlaneEndpoint); err != nil { - return fmt.Errorf("setup konnectivity: %w", err) + return nil, fmt.Errorf("setup konnectivity: %w", err) } // initialize the cluster @@ -155,12 +157,29 @@ func (k *KubernetesUtil) InitCluster( if err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) { - return fmt.Errorf("kubeadm init failed (code %v) with: %s", exitErr.ExitCode(), out) + return nil, fmt.Errorf("kubeadm init failed (code %v) with: %s", exitErr.ExitCode(), out) } - return fmt.Errorf("kubeadm init: %w", err) + return nil, fmt.Errorf("kubeadm init: %w", err) } log.With(zap.String("output", string(out))).Infof("kubeadm init succeeded") - return nil + + userName := clusterName + "-admin" + + log.With(zap.String("userName", userName)).Infof("Creating admin kubeconfig file") + cmd = exec.CommandContext( + ctx, constants.KubeadmPath, "kubeconfig", "user", + "--client-name", userName, "--config", initConfigFile.Name(), "--org", user.SystemPrivilegedGroup, + ) + out, err = cmd.Output() + if err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + return nil, fmt.Errorf("kubeadm kubeconfig user failed (code %v) with: %s", exitErr.ExitCode(), out) + } + return nil, fmt.Errorf("kubeadm kubeconfig user: %w", err) + } + log.Infof("kubeadm kubeconfig user succeeded") + return out, nil } func (k *KubernetesUtil) prepareControlPlaneForKonnectivity(ctx context.Context, loadBalancerEndpoint string) error { diff --git a/bootstrapper/internal/kubernetes/k8sapi/kubeadm_config.go b/bootstrapper/internal/kubernetes/k8sapi/kubeadm_config.go index ade3582af..5588b217d 100644 --- a/bootstrapper/internal/kubernetes/k8sapi/kubeadm_config.go +++ b/bootstrapper/internal/kubernetes/k8sapi/kubeadm_config.go @@ -271,6 +271,12 @@ func (k *KubeadmInitYAML) SetNodeName(nodeName string) { k.InitConfiguration.NodeRegistration.Name = nodeName } +// SetClusterName sets the name of the Kubernetes cluster. +// This name is reflected in the kubeconfig file and in the name of the default admin user. +func (k *KubeadmInitYAML) SetClusterName(clusterName string) { + k.ClusterConfiguration.ClusterName = clusterName +} + // SetCertSANs sets the SANs for the certificate. func (k *KubeadmInitYAML) SetCertSANs(certSANs []string) { for _, certSAN := range certSANs { diff --git a/bootstrapper/internal/kubernetes/k8sutil.go b/bootstrapper/internal/kubernetes/k8sutil.go index 0ed17e0da..3f2abc43c 100644 --- a/bootstrapper/internal/kubernetes/k8sutil.go +++ b/bootstrapper/internal/kubernetes/k8sutil.go @@ -19,7 +19,7 @@ import ( type clusterUtil interface { InstallComponents(ctx context.Context, kubernetesComponents components.Components) error - InitCluster(ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger) error + InitCluster(ctx context.Context, initConfig []byte, nodeName, clusterName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger) ([]byte, error) JoinCluster(ctx context.Context, joinConfig []byte, peerRole role.Role, controlPlaneEndpoint string, log *logger.Logger) error FixCilium(log *logger.Logger) StartKubelet() error diff --git a/bootstrapper/internal/kubernetes/kubeconfig.go b/bootstrapper/internal/kubernetes/kubeconfig.go deleted file mode 100644 index 4d70ba19f..000000000 --- a/bootstrapper/internal/kubernetes/kubeconfig.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package kubernetes - -import ( - "fmt" - - "github.com/spf13/afero" -) - -const kubeconfigPath = "/etc/kubernetes/admin.conf" - -// KubeconfigReader implements ConfigReader. -type KubeconfigReader struct { - fs afero.Afero -} - -// ReadKubeconfig reads the Kubeconfig from disk. -func (r KubeconfigReader) ReadKubeconfig() ([]byte, error) { - kubeconfig, err := r.fs.ReadFile(kubeconfigPath) - if err != nil { - return nil, fmt.Errorf("reading kubernetes config: %w", err) - } - return kubeconfig, nil -} diff --git a/bootstrapper/internal/kubernetes/kubeconfig_test.go b/bootstrapper/internal/kubernetes/kubeconfig_test.go deleted file mode 100644 index adae4d484..000000000 --- a/bootstrapper/internal/kubernetes/kubeconfig_test.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package kubernetes - -import ( - "testing" - - "github.com/spf13/afero" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestReadKubeconfig(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - fs := afero.Afero{ - Fs: afero.NewMemMapFs(), - } - require.NoError(fs.WriteFile(kubeconfigPath, []byte("someConfig"), 0o644)) - reader := KubeconfigReader{fs} - config, err := reader.ReadKubeconfig() - - require.NoError(err) - assert.Equal([]byte("someConfig"), config) -} - -func TestReadKubeconfigFails(t *testing.T) { - assert := assert.New(t) - fs := afero.Afero{ - Fs: afero.NewMemMapFs(), - } - reader := KubeconfigReader{fs} - _, err := reader.ReadKubeconfig() - - assert.Error(err) -} diff --git a/bootstrapper/internal/kubernetes/kubernetes.go b/bootstrapper/internal/kubernetes/kubernetes.go index 8112d15cf..ae28cc745 100644 --- a/bootstrapper/internal/kubernetes/kubernetes.go +++ b/bootstrapper/internal/kubernetes/kubernetes.go @@ -30,7 +30,6 @@ import ( "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/role" "github.com/edgelesssys/constellation/v2/internal/versions/components" - "github.com/spf13/afero" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,11 +38,6 @@ import ( var validHostnameRegex = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) -// configReader provides kubeconfig as []byte. -type configReader interface { - ReadKubeconfig() ([]byte, error) -} - // configurationProvider provides kubeadm init and join configuration. type configurationProvider interface { InitConfiguration(externalCloudProvider bool, k8sVersion string) k8sapi.KubeadmInitYAML @@ -62,7 +56,6 @@ type KubeWrapper struct { kubeAPIWaiter kubeAPIWaiter configProvider configurationProvider client k8sapi.Client - kubeconfigReader configReader providerMetadata ProviderMetadata initialMeasurements measurements.M getIPAddr func() (string, error) @@ -79,7 +72,6 @@ func New(cloudProvider string, clusterUtil clusterUtil, configProvider configura kubeAPIWaiter: kubeAPIWaiter, configProvider: configProvider, client: client, - kubeconfigReader: &KubeconfigReader{fs: afero.Afero{Fs: afero.NewOsFs()}}, providerMetadata: providerMetadata, initialMeasurements: measurements, getIPAddr: getIPAddr, @@ -88,8 +80,8 @@ func New(cloudProvider string, clusterUtil clusterUtil, configProvider configura // InitCluster initializes a new Kubernetes cluster and applies pod network provider. func (k *KubeWrapper) InitCluster( - ctx context.Context, cloudServiceAccountURI, versionString string, measurementSalt []byte, enforcedPCRs []uint32, - enforceIDKeyDigest bool, azureCVM bool, + ctx context.Context, cloudServiceAccountURI, versionString, clusterName string, + measurementSalt []byte, enforcedPCRs []uint32, enforceIDKeyDigest bool, azureCVM bool, helmReleasesRaw []byte, conformanceMode bool, kubernetesComponents components.Components, log *logger.Logger, ) ([]byte, error) { log.With(zap.String("version", versionString)).Infof("Installing Kubernetes components") @@ -139,6 +131,7 @@ func (k *KubeWrapper) InitCluster( cloudprovider.FromString(k.cloudProvider) == cloudprovider.GCP initConfig := k.configProvider.InitConfiguration(ccmSupported, versionString) initConfig.SetNodeIP(nodeIP) + initConfig.SetClusterName(clusterName) initConfig.SetCertSANs([]string{nodeIP}) initConfig.SetNodeName(nodeName) initConfig.SetProviderID(instance.ProviderID) @@ -148,13 +141,11 @@ func (k *KubeWrapper) InitCluster( return nil, fmt.Errorf("encoding kubeadm init configuration as YAML: %w", err) } log.Infof("Initializing Kubernetes cluster") - if err := k.clusterUtil.InitCluster(ctx, initConfigYAML, nodeName, validIPs, controlPlaneEndpoint, conformanceMode, log); err != nil { + kubeConfig, err := k.clusterUtil.InitCluster(ctx, initConfigYAML, nodeName, clusterName, validIPs, controlPlaneEndpoint, conformanceMode, log) + if err != nil { return nil, fmt.Errorf("kubeadm init: %w", err) } - kubeConfig, err := k.GetKubeconfig() - if err != nil { - return nil, fmt.Errorf("reading kubeconfig after cluster initialization: %w", err) - } + err = k.client.Initialize(kubeConfig) if err != nil { return nil, fmt.Errorf("initializing kubectl client: %w", err) @@ -250,7 +241,7 @@ func (k *KubeWrapper) InitCluster( k.clusterUtil.FixCilium(log) - return k.GetKubeconfig() + return kubeConfig, nil } // JoinCluster joins existing Kubernetes cluster. @@ -311,11 +302,6 @@ func (k *KubeWrapper) JoinCluster(ctx context.Context, args *kubeadm.BootstrapTo return nil } -// GetKubeconfig returns the current nodes kubeconfig of stored on disk. -func (k *KubeWrapper) GetKubeconfig() ([]byte, error) { - return k.kubeconfigReader.ReadKubeconfig() -} - // setupK8sComponentsConfigMap applies a ConfigMap (cf. server-side apply) to store the installed k8s components. // It returns the name of the ConfigMap. func (k *KubeWrapper) setupK8sComponentsConfigMap(ctx context.Context, components components.Components, clusterVersion string) (string, error) { diff --git a/bootstrapper/internal/kubernetes/kubernetes_test.go b/bootstrapper/internal/kubernetes/kubernetes_test.go index 10e6243c4..340c687cd 100644 --- a/bootstrapper/internal/kubernetes/kubernetes_test.go +++ b/bootstrapper/internal/kubernetes/kubernetes_test.go @@ -50,16 +50,12 @@ func TestInitCluster(t *testing.T) { kubectl stubKubectl kubeAPIWaiter stubKubeAPIWaiter providerMetadata ProviderMetadata - kubeconfigReader configReader wantConfig k8sapi.KubeadmInitYAML wantErr bool k8sVersion versions.ValidK8sVersion }{ "kubeadm init works with metadata and loadbalancer": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{ selfResp: metadata.InstanceMetadata{ @@ -81,6 +77,7 @@ func TestInitCluster(t *testing.T) { }, }, ClusterConfiguration: kubeadm.ClusterConfiguration{ + ClusterName: "kubernetes", ControlPlaneEndpoint: loadbalancerIP, APIServer: kubeadm.APIServer{ CertSANs: []string{privateIP}, @@ -91,10 +88,7 @@ func TestInitCluster(t *testing.T) { k8sVersion: versions.Default, }, "kubeadm init fails when annotating itself": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{ selfResp: metadata.InstanceMetadata{ @@ -110,10 +104,7 @@ func TestInitCluster(t *testing.T) { k8sVersion: versions.Default, }, "kubeadm init fails when retrieving metadata self": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{ selfErr: someErr, @@ -122,10 +113,7 @@ func TestInitCluster(t *testing.T) { k8sVersion: versions.Default, }, "kubeadm init fails when retrieving metadata loadbalancer ip": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, providerMetadata: &stubProviderMetadata{ getLoadBalancerEndpointErr: someErr, }, @@ -133,9 +121,9 @@ func TestInitCluster(t *testing.T) { k8sVersion: versions.Default, }, "kubeadm init fails when applying the init config": { - clusterUtil: stubClusterUtil{initClusterErr: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), + clusterUtil: stubClusterUtil{ + initClusterErr: someErr, + kubeconfig: []byte("someKubeconfig"), }, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, @@ -143,95 +131,67 @@ func TestInitCluster(t *testing.T) { k8sVersion: versions.Default, }, "kubeadm init fails when deploying cilium": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{ciliumError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, + helmClient: stubHelmClient{ciliumError: someErr}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when setting up constellation-services chart": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{servicesError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, + helmClient: stubHelmClient{servicesError: someErr}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when setting the cloud node manager": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{servicesError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, + helmClient: stubHelmClient{servicesError: someErr}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when setting the cluster autoscaler": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{servicesError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, + helmClient: stubHelmClient{servicesError: someErr}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when reading kubeconfig": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - readErr: someErr, - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when setting up konnectivity": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{servicesError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, + helmClient: stubHelmClient{servicesError: someErr}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when setting up verification service": { - clusterUtil: stubClusterUtil{}, - helmClient: stubHelmClient{servicesError: someErr}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, wantErr: true, k8sVersion: versions.Default, }, "kubeadm init fails when waiting for kubeAPI server": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{waitErr: someErr}, providerMetadata: &stubProviderMetadata{}, k8sVersion: versions.Default, wantErr: true, }, "unsupported k8sVersion fails cluster creation": { - clusterUtil: stubClusterUtil{}, - kubeconfigReader: &stubKubeconfigReader{ - kubeconfig: []byte("someKubeconfig"), - }, + clusterUtil: stubClusterUtil{kubeconfig: []byte("someKubeconfig")}, kubeAPIWaiter: stubKubeAPIWaiter{}, providerMetadata: &stubProviderMetadata{}, k8sVersion: "1.19", @@ -251,12 +211,11 @@ func TestInitCluster(t *testing.T) { kubeAPIWaiter: &tc.kubeAPIWaiter, configProvider: &stubConfigProvider{initConfig: k8sapi.KubeadmInitYAML{}}, client: &tc.kubectl, - kubeconfigReader: tc.kubeconfigReader, getIPAddr: func() (string, error) { return privateIP, nil }, } _, err := kube.InitCluster( - context.Background(), serviceAccountURI, string(tc.k8sVersion), + context.Background(), serviceAccountURI, string(tc.k8sVersion), "kubernetes", nil, nil, false, true, []byte("{}"), false, nil, logger.NewTest(t), ) @@ -503,6 +462,8 @@ type stubClusterUtil struct { joinClusterErr error startKubeletErr error + kubeconfig []byte + initConfigs [][]byte joinConfigs [][]byte } @@ -515,9 +476,9 @@ func (s *stubClusterUtil) InstallComponents(ctx context.Context, kubernetesCompo return s.installComponentsErr } -func (s *stubClusterUtil) InitCluster(ctx context.Context, initConfig []byte, nodeName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger) error { +func (s *stubClusterUtil) InitCluster(ctx context.Context, initConfig []byte, nodeName, clusterName string, ips []net.IP, controlPlaneEndpoint string, conformanceMode bool, log *logger.Logger) ([]byte, error) { s.initConfigs = append(s.initConfigs, initConfig) - return s.initClusterErr + return s.kubeconfig, s.initClusterErr } func (s *stubClusterUtil) SetupAutoscaling(kubectl k8sapi.Client, clusterAutoscalerConfiguration kubernetes.Marshaler, secrets kubernetes.Marshaler) error { @@ -611,15 +572,6 @@ func (s *stubKubectl) ListAllNamespaces(ctx context.Context) (*corev1.NamespaceL return s.listAllNamespacesResp, s.listAllNamespacesErr } -type stubKubeconfigReader struct { - kubeconfig []byte - readErr error -} - -func (s *stubKubeconfigReader) ReadKubeconfig() ([]byte, error) { - return s.kubeconfig, s.readErr -} - type stubHelmClient struct { ciliumError error certManagerError error diff --git a/cli/internal/cloudcmd/create.go b/cli/internal/cloudcmd/create.go index 7c51478f6..2bf483d45 100644 --- a/cli/internal/cloudcmd/create.go +++ b/cli/internal/cloudcmd/create.go @@ -53,7 +53,7 @@ func NewCreator(out io.Writer) *Creator { } // Create creates the handed amount of instances and all the needed resources. -func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, config *config.Config, name, insType string, controlPlaneCount, workerCount int, +func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, config *config.Config, insType string, controlPlaneCount, workerCount int, ) (clusterid.File, error) { image, err := c.image.FetchReference(ctx, config) if err != nil { @@ -67,21 +67,21 @@ func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, c return clusterid.File{}, err } defer cl.RemoveInstaller() - return c.createAWS(ctx, cl, config, name, insType, controlPlaneCount, workerCount, image) + return c.createAWS(ctx, cl, config, insType, controlPlaneCount, workerCount, image) case cloudprovider.GCP: cl, err := c.newTerraformClient(ctx) if err != nil { return clusterid.File{}, err } defer cl.RemoveInstaller() - return c.createGCP(ctx, cl, config, name, insType, controlPlaneCount, workerCount, image) + return c.createGCP(ctx, cl, config, insType, controlPlaneCount, workerCount, image) case cloudprovider.Azure: cl, err := c.newTerraformClient(ctx) if err != nil { return clusterid.File{}, err } defer cl.RemoveInstaller() - return c.createAzure(ctx, cl, config, name, insType, controlPlaneCount, workerCount, image) + return c.createAzure(ctx, cl, config, insType, controlPlaneCount, workerCount, image) case cloudprovider.QEMU: if runtime.GOARCH != "amd64" || runtime.GOOS != "linux" { return clusterid.File{}, fmt.Errorf("creation of a QEMU based Constellation is not supported for %s/%s", runtime.GOOS, runtime.GOARCH) @@ -92,18 +92,18 @@ func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, c } defer cl.RemoveInstaller() lv := c.newLibvirtRunner() - return c.createQEMU(ctx, cl, lv, name, config, controlPlaneCount, workerCount, image) + return c.createQEMU(ctx, cl, lv, config, controlPlaneCount, workerCount, image) default: return clusterid.File{}, fmt.Errorf("unsupported cloud provider: %s", provider) } } func (c *Creator) createAWS(ctx context.Context, cl terraformClient, config *config.Config, - name, insType string, controlPlaneCount, workerCount int, image string, + insType string, controlPlaneCount, workerCount int, image string, ) (idFile clusterid.File, retErr error) { vars := terraform.AWSClusterVariables{ CommonVariables: terraform.CommonVariables{ - Name: name, + Name: config.Name, CountControlPlanes: controlPlaneCount, CountWorkers: workerCount, StateDiskSizeGB: config.StateDiskSizeGB, @@ -137,11 +137,11 @@ func (c *Creator) createAWS(ctx context.Context, cl terraformClient, config *con } func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *config.Config, - name, insType string, controlPlaneCount, workerCount int, image string, + insType string, controlPlaneCount, workerCount int, image string, ) (idFile clusterid.File, retErr error) { vars := terraform.GCPClusterVariables{ CommonVariables: terraform.CommonVariables{ - Name: name, + Name: config.Name, CountControlPlanes: controlPlaneCount, CountWorkers: workerCount, StateDiskSizeGB: config.StateDiskSizeGB, @@ -175,11 +175,11 @@ func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *con } func (c *Creator) createAzure(ctx context.Context, cl terraformClient, config *config.Config, - name, insType string, controlPlaneCount, workerCount int, image string, + insType string, controlPlaneCount, workerCount int, image string, ) (idFile clusterid.File, retErr error) { vars := terraform.AzureClusterVariables{ CommonVariables: terraform.CommonVariables{ - Name: name, + Name: config.Name, CountControlPlanes: controlPlaneCount, CountWorkers: workerCount, StateDiskSizeGB: config.StateDiskSizeGB, @@ -241,7 +241,7 @@ func normalizeAzureURIs(vars terraform.AzureClusterVariables) terraform.AzureClu return vars } -func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirtRunner, name string, config *config.Config, +func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirtRunner, config *config.Config, controlPlaneCount, workerCount int, source string, ) (idFile clusterid.File, retErr error) { qemuRollbacker := &rollbackerQEMU{client: cl, libvirt: lv, createdWorkspace: false} @@ -260,7 +260,7 @@ func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirt switch { // if no libvirt URI is specified, start a libvirt container case libvirtURI == "": - if err := lv.Start(ctx, name, config.Provider.QEMU.LibvirtContainerImage); err != nil { + if err := lv.Start(ctx, config.Name, config.Provider.QEMU.LibvirtContainerImage); err != nil { return clusterid.File{}, err } libvirtURI = libvirt.LibvirtTCPConnectURI @@ -292,7 +292,7 @@ func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirt vars := terraform.QEMUVariables{ CommonVariables: terraform.CommonVariables{ - Name: name, + Name: config.Name, CountControlPlanes: controlPlaneCount, CountWorkers: workerCount, StateDiskSizeGB: config.StateDiskSizeGB, diff --git a/cli/internal/cloudcmd/create_test.go b/cli/internal/cloudcmd/create_test.go index c9699f4db..c6d711ca4 100644 --- a/cli/internal/cloudcmd/create_test.go +++ b/cli/internal/cloudcmd/create_test.go @@ -114,7 +114,7 @@ func TestCreator(t *testing.T) { }, } - idFile, err := creator.Create(context.Background(), tc.provider, tc.config, "name", "type", 2, 3) + idFile, err := creator.Create(context.Background(), tc.provider, tc.config, "type", 2, 3) if tc.wantErr { assert.Error(err) diff --git a/cli/internal/cmd/cloud.go b/cli/internal/cmd/cloud.go index 04f7a216e..613b76935 100644 --- a/cli/internal/cmd/cloud.go +++ b/cli/internal/cmd/cloud.go @@ -21,7 +21,7 @@ type cloudCreator interface { ctx context.Context, provider cloudprovider.Provider, config *config.Config, - name, insType string, + insType string, coordCount, nodeCount int, ) (clusterid.File, error) } diff --git a/cli/internal/cmd/cloud_test.go b/cli/internal/cmd/cloud_test.go index 7c7a25809..67c4ce95c 100644 --- a/cli/internal/cmd/cloud_test.go +++ b/cli/internal/cmd/cloud_test.go @@ -35,7 +35,7 @@ func (c *stubCloudCreator) Create( ctx context.Context, provider cloudprovider.Provider, config *config.Config, - name, insType string, + insType string, coordCount, nodeCount int, ) (clusterid.File, error) { c.createCalled = true diff --git a/cli/internal/cmd/configgenerate_test.go b/cli/internal/cmd/configgenerate_test.go index 9e018f3ad..0d29a710a 100644 --- a/cli/internal/cmd/configgenerate_test.go +++ b/cli/internal/cmd/configgenerate_test.go @@ -41,12 +41,12 @@ func TestConfigGenerateDefaultGCPSpecific(t *testing.T) { assert := assert.New(t) require := require.New(t) - wantConf := config.Default() - wantConf.RemoveProviderExcept(cloudprovider.GCP) - fileHandler := file.NewHandler(afero.NewMemMapFs()) cmd := newConfigGenerateCmd() + wantConf := config.Default() + wantConf.RemoveProviderExcept(cloudprovider.GCP) + cg := &configGenerateCmd{log: logger.NewTest(t)} require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.GCP)) diff --git a/cli/internal/cmd/create.go b/cli/internal/cmd/create.go index bed604d80..73900e9e4 100644 --- a/cli/internal/cmd/create.go +++ b/cli/internal/cmd/create.go @@ -30,7 +30,6 @@ func NewCreateCmd() *cobra.Command { Args: cobra.ExactArgs(0), RunE: runCreate, } - cmd.Flags().String("name", "constell", "create the cluster with the specified name") cmd.Flags().BoolP("yes", "y", false, "create the cluster without further confirmation") cmd.Flags().IntP("control-plane-nodes", "c", 0, "number of control-plane nodes (required)") must(cobra.MarkFlagRequired(cmd.Flags(), "control-plane-nodes")) @@ -110,9 +109,6 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler case cloudprovider.AWS: c.log.Debugf("Configuring instance type for AWS") instanceType = conf.Provider.AWS.InstanceType - if len(flags.name) > 10 { - return fmt.Errorf("cluster name on AWS must not be longer than 10 characters") - } case cloudprovider.Azure: c.log.Debugf("Configuring instance type for Azure") instanceType = conf.Provider.Azure.InstanceType @@ -142,7 +138,7 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler } spinner.Start("Creating", false) - idFile, err := creator.Create(cmd.Context(), provider, conf, flags.name, instanceType, flags.controllerCount, flags.workerCount) + idFile, err := creator.Create(cmd.Context(), provider, conf, instanceType, flags.controllerCount, flags.workerCount) c.log.Debugf("Successfully created the cloud resources for the cluster") spinner.Stop() if err != nil { @@ -177,18 +173,6 @@ func (c *createCmd) parseCreateFlags(cmd *cobra.Command) (createFlags, error) { return createFlags{}, fmt.Errorf("number of worker nodes must be at least %d", constants.MinWorkerCount) } - name, err := cmd.Flags().GetString("name") - if err != nil { - return createFlags{}, fmt.Errorf("parsing name argument: %w", err) - } - c.log.Debugf("Name flag is %q", name) - if len(name) > constants.ConstellationNameLength { - return createFlags{}, fmt.Errorf( - "name for Constellation cluster too long, maximum length is %d, got %d: %s", - constants.ConstellationNameLength, len(name), name, - ) - } - yes, err := cmd.Flags().GetBool("yes") if err != nil { return createFlags{}, fmt.Errorf("%w; Set '-yes' without a value to automatically confirm", err) @@ -210,7 +194,6 @@ func (c *createCmd) parseCreateFlags(cmd *cobra.Command) (createFlags, error) { return createFlags{ controllerCount: controllerCount, workerCount: workerCount, - name: name, configPath: configPath, force: force, yes: yes, @@ -221,7 +204,6 @@ func (c *createCmd) parseCreateFlags(cmd *cobra.Command) (createFlags, error) { type createFlags struct { controllerCount int workerCount int - name string configPath string force bool yes bool diff --git a/cli/internal/cmd/create_test.go b/cli/internal/cmd/create_test.go index 025e99f3d..9e1557c46 100644 --- a/cli/internal/cmd/create_test.go +++ b/cli/internal/cmd/create_test.go @@ -10,7 +10,6 @@ import ( "bytes" "errors" "strconv" - "strings" "testing" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" @@ -42,7 +41,6 @@ func TestCreate(t *testing.T) { controllerCountFlag *int workerCountFlag *int configFlag string - nameFlag string stdin string wantErr bool wantAbort bool @@ -81,15 +79,6 @@ func TestCreate(t *testing.T) { stdin: "foo\nfoo\nfoo\n", wantErr: true, }, - "flag name to long": { - setupFs: fsWithDefaultConfig, - creator: &stubCloudCreator{}, - provider: cloudprovider.GCP, - controllerCountFlag: intPtr(1), - workerCountFlag: intPtr(1), - nameFlag: strings.Repeat("a", constants.ConstellationNameLength+1), - wantErr: true, - }, "flag control-plane-count invalid": { setupFs: fsWithDefaultConfig, creator: &stubCloudCreator{}, @@ -200,9 +189,6 @@ func TestCreate(t *testing.T) { if tc.yesFlag { require.NoError(cmd.Flags().Set("yes", "true")) } - if tc.nameFlag != "" { - require.NoError(cmd.Flags().Set("name", tc.nameFlag)) - } if tc.configFlag != "" { require.NoError(cmd.Flags().Set("config", tc.configFlag)) } diff --git a/cli/internal/cmd/iam_test.go b/cli/internal/cmd/iam_test.go index f65505258..4fd2037dc 100644 --- a/cli/internal/cmd/iam_test.go +++ b/cli/internal/cmd/iam_test.go @@ -226,6 +226,7 @@ func TestIAMCreateAWS(t *testing.T) { cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually cmd.Flags().Bool("generate-config", false, "") // register persistent flag manually cmd.Flags().Bool("yes", false, "") // register persistent flag manually + cmd.Flags().String("name", "constell", "") // register persistent flag manually if tc.zoneFlag != "" { require.NoError(cmd.Flags().Set("zone", tc.zoneFlag)) @@ -446,7 +447,8 @@ func TestIAMCreateAzure(t *testing.T) { cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually cmd.Flags().Bool("generate-config", false, "") // register persistent flag manually - cmd.Flags().Bool("yes", false, "") // register persistent flag + cmd.Flags().Bool("yes", false, "") // register persistent flag manually + cmd.Flags().String("name", "constell", "") // register persistent flag manually if tc.regionFlag != "" { require.NoError(cmd.Flags().Set("region", tc.regionFlag)) @@ -694,7 +696,8 @@ func TestIAMCreateGCP(t *testing.T) { cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually cmd.Flags().Bool("generate-config", false, "") // register persistent flag manually - cmd.Flags().Bool("yes", false, "") // register persistent flag + cmd.Flags().Bool("yes", false, "") // register persistent flag manually + cmd.Flags().String("name", "constell", "") // register persistent flag manually if tc.zoneFlag != "" { require.NoError(cmd.Flags().Set("zone", tc.zoneFlag)) diff --git a/cli/internal/cmd/init.go b/cli/internal/cmd/init.go index 1e15229b6..c1aaa70b8 100644 --- a/cli/internal/cmd/init.go +++ b/cli/internal/cmd/init.go @@ -137,11 +137,14 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud helmLoader := helm.NewLoader(provider, k8sVersion) i.log.Debugf("Created new Helm loader") helmDeployments, err := helmLoader.Load(conf, flags.conformance, masterSecret.Key, masterSecret.Salt) - i.log.Debugf("Loaded Helm heployments") + i.log.Debugf("Loaded Helm deployments") if err != nil { return fmt.Errorf("loading Helm charts: %w", err) } + clusterName := conf.Name + "-" + idFile.UID + i.log.Debugf("Setting cluster name to %s", clusterName) + spinner.Start("Initializing cluster ", false) req := &initproto.InitRequest{ MasterSecret: masterSecret.Key, @@ -158,6 +161,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud EnforceIdkeydigest: conf.EnforcesIDKeyDigest(), ConformanceMode: flags.conformance, InitSecret: idFile.InitSecret, + ClusterName: clusterName, } i.log.Debugf("Sending initialization request") resp, err := i.initCall(cmd.Context(), newDialer(validator), idFile.IP, req) diff --git a/cli/internal/cmd/init_test.go b/cli/internal/cmd/init_test.go index 90dfce565..c6d6725ad 100644 --- a/cli/internal/cmd/init_test.go +++ b/cli/internal/cmd/init_test.go @@ -479,6 +479,7 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs t.Helper() conf.Image = constants.VersionInfo + conf.Name = "kubernetes" switch csp { case cloudprovider.Azure: diff --git a/cli/internal/cmd/miniup.go b/cli/internal/cmd/miniup.go index 4f6b458d0..0635a5cde 100644 --- a/cli/internal/cmd/miniup.go +++ b/cli/internal/cmd/miniup.go @@ -213,6 +213,7 @@ func (m *miniUpCmd) prepareConfig(cmd *cobra.Command, fileHandler file.Handler) } config := config.Default() + config.Name = constants.MiniConstellationUID config.RemoveProviderExcept(cloudprovider.QEMU) config.StateDiskSizeGB = 8 m.log.Debugf("Prepared configuration") @@ -223,7 +224,7 @@ func (m *miniUpCmd) prepareConfig(cmd *cobra.Command, fileHandler file.Handler) // createMiniCluster creates a new cluster using the given config. func (m *miniUpCmd) createMiniCluster(ctx context.Context, fileHandler file.Handler, creator cloudCreator, config *config.Config) error { m.log.Debugf("Creating mini cluster") - idFile, err := creator.Create(ctx, cloudprovider.QEMU, config, "mini", "", 1, 1) + idFile, err := creator.Create(ctx, cloudprovider.QEMU, config, "", 1, 1) if err != nil { return err } diff --git a/docs/static/img/shell-windowframe.svg b/docs/static/img/shell-windowframe.svg index e6682b061..cb12f756c 100644 --- a/docs/static/img/shell-windowframe.svg +++ b/docs/static/img/shell-windowframe.svg @@ -16,155 +16,143 @@ } :root { - --animation-duration: 28793ms; + --animation-duration: 17994ms; } @keyframes roll { 0.000%{transform:translateY(0px)} -0.549%{transform:translateY(-306px)} -2.077%{transform:translateY(-612px)} -2.278%{transform:translateY(-918px)} -2.615%{transform:translateY(-1224px)} -2.740%{transform:translateY(-1530px)} -2.914%{transform:translateY(-1836px)} -3.077%{transform:translateY(-2142px)} -3.303%{transform:translateY(-2448px)} -3.563%{transform:translateY(-2754px)} -3.751%{transform:translateY(-3060px)} -3.879%{transform:translateY(-3366px)} -4.244%{transform:translateY(-3672px)} -5.029%{transform:translateY(-3978px)} -5.217%{transform:translateY(-4284px)} -5.526%{transform:translateY(-4590px)} -5.727%{transform:translateY(-4896px)} -6.005%{transform:translateY(-5202px)} -6.189%{transform:translateY(-5508px)} -6.526%{transform:translateY(-5814px)} -7.919%{transform:translateY(-6120px)} -8.130%{transform:translateY(-6426px)} -8.547%{transform:translateY(-6732px)} -9.829%{transform:translateY(-7038px)} -10.180%{transform:translateY(-7344px)} -10.353%{transform:translateY(-7650px)} -10.843%{transform:translateY(-7956px)} -10.878%{transform:translateY(-8262px)} -13.594%{transform:translateY(-8568px)} -13.757%{transform:translateY(-8874px)} -14.069%{transform:translateY(-9180px)} -14.170%{transform:translateY(-9486px)} -14.486%{transform:translateY(-9792px)} -15.657%{transform:translateY(-10098px)} -16.056%{transform:translateY(-10404px)} -16.216%{transform:translateY(-10710px)} -16.355%{transform:translateY(-11016px)} -16.528%{transform:translateY(-11322px)} -16.681%{transform:translateY(-11628px)} -17.032%{transform:translateY(-11934px)} -18.768%{transform:translateY(-12240px)} -19.043%{transform:translateY(-12546px)} -19.769%{transform:translateY(-12852px)} -20.394%{transform:translateY(-13158px)} -20.606%{transform:translateY(-13464px)} -21.106%{transform:translateY(-13770px)} -21.432%{transform:translateY(-14076px)} -22.009%{transform:translateY(-14382px)} -23.106%{transform:translateY(-14688px)} -23.256%{transform:translateY(-14994px)} -23.909%{transform:translateY(-15300px)} -24.169%{transform:translateY(-15606px)} -24.596%{transform:translateY(-15912px)} -24.784%{transform:translateY(-16218px)} -24.968%{transform:translateY(-16524px)} -25.194%{transform:translateY(-16830px)} -25.784%{transform:translateY(-17136px)} -26.270%{transform:translateY(-17442px)} -26.520%{transform:translateY(-17748px)} -26.708%{transform:translateY(-18054px)} -27.121%{transform:translateY(-18360px)} -27.548%{transform:translateY(-18666px)} -28.694%{transform:translateY(-18972px)} -28.722%{transform:translateY(-19278px)} -31.185%{transform:translateY(-19584px)} -32.084%{transform:translateY(-19890px)} -39.030%{transform:translateY(-20196px)} -39.044%{transform:translateY(-20502px)} -42.993%{transform:translateY(-20808px)} -43.219%{transform:translateY(-21114px)} -43.570%{transform:translateY(-21420px)} -43.861%{transform:translateY(-21726px)} -44.257%{transform:translateY(-22032px)} -44.421%{transform:translateY(-22338px)} -44.757%{transform:translateY(-22644px)} -44.997%{transform:translateY(-22950px)} -45.271%{transform:translateY(-23256px)} -45.466%{transform:translateY(-23562px)} -46.543%{transform:translateY(-23868px)} -46.831%{transform:translateY(-24174px)} -47.147%{transform:translateY(-24480px)} -47.355%{transform:translateY(-24786px)} -47.571%{transform:translateY(-25092px)} -47.907%{transform:translateY(-25398px)} -48.234%{transform:translateY(-25704px)} -48.421%{transform:translateY(-26010px)} -49.595%{transform:translateY(-26316px)} -49.620%{transform:translateY(-26622px)} -56.566%{transform:translateY(-26928px)} -56.576%{transform:translateY(-27234px)} -63.522%{transform:translateY(-27540px)} -64.648%{transform:translateY(-27846px)} -64.655%{transform:translateY(-28152px)} -71.601%{transform:translateY(-28458px)} -71.924%{transform:translateY(-28764px)} -72.264%{transform:translateY(-29070px)} -72.476%{transform:translateY(-29376px)} -72.861%{transform:translateY(-29682px)} -73.278%{transform:translateY(-29988px)} -73.466%{transform:translateY(-30294px)} -73.726%{transform:translateY(-30600px)} -74.126%{transform:translateY(-30906px)} -74.313%{transform:translateY(-31212px)} -74.539%{transform:translateY(-31518px)} -74.789%{transform:translateY(-31824px)} -75.963%{transform:translateY(-32130px)} -76.401%{transform:translateY(-32436px)} -76.598%{transform:translateY(-32742px)} -76.713%{transform:translateY(-33048px)} -76.814%{transform:translateY(-33354px)} -77.206%{transform:translateY(-33660px)} -77.408%{transform:translateY(-33966px)} -77.422%{transform:translateY(-34272px)} -82.079%{transform:translateY(-34578px)} -82.464%{transform:translateY(-34884px)} -82.829%{transform:translateY(-35190px)} -82.975%{transform:translateY(-35496px)} -83.229%{transform:translateY(-35802px)} -83.378%{transform:translateY(-36108px)} -83.756%{transform:translateY(-36414px)} -84.003%{transform:translateY(-36720px)} -84.191%{transform:translateY(-37026px)} -84.354%{transform:translateY(-37332px)} -85.417%{transform:translateY(-37638px)} -85.705%{transform:translateY(-37944px)} -86.014%{transform:translateY(-38250px)} -86.167%{transform:translateY(-38556px)} -86.618%{transform:translateY(-38862px)} -86.854%{transform:translateY(-39168px)} -86.983%{transform:translateY(-39474px)} -87.278%{transform:translateY(-39780px)} -87.591%{transform:translateY(-40086px)} -87.869%{transform:translateY(-40392px)} -87.980%{transform:translateY(-40698px)} -88.167%{transform:translateY(-41004px)} -88.278%{transform:translateY(-41310px)} -89.543%{transform:translateY(-41616px)} -89.567%{transform:translateY(-41922px)} -96.513%{transform:translateY(-42228px)} -96.527%{transform:translateY(-42534px)} -100.000%{transform:translateY(-42534px)} +0.878%{transform:translateY(-306px)} +3.323%{transform:translateY(-612px)} +3.646%{transform:translateY(-918px)} +4.185%{transform:translateY(-1224px)} +4.385%{transform:translateY(-1530px)} +4.663%{transform:translateY(-1836px)} +4.924%{transform:translateY(-2142px)} +5.285%{transform:translateY(-2448px)} +5.702%{transform:translateY(-2754px)} +6.002%{transform:translateY(-3060px)} +6.208%{transform:translateY(-3366px)} +6.791%{transform:translateY(-3672px)} +8.047%{transform:translateY(-3978px)} +8.347%{transform:translateY(-4284px)} +8.842%{transform:translateY(-4590px)} +9.164%{transform:translateY(-4896px)} +9.609%{transform:translateY(-5202px)} +9.903%{transform:translateY(-5508px)} +10.442%{transform:translateY(-5814px)} +12.671%{transform:translateY(-6120px)} +13.010%{transform:translateY(-6426px)} +13.677%{transform:translateY(-6732px)} +15.727%{transform:translateY(-7038px)} +16.289%{transform:translateY(-7344px)} +16.567%{transform:translateY(-7650px)} +17.350%{transform:translateY(-7956px)} +17.406%{transform:translateY(-8262px)} +19.907%{transform:translateY(-8568px)} +20.168%{transform:translateY(-8874px)} +20.668%{transform:translateY(-9180px)} +20.829%{transform:translateY(-9486px)} +21.335%{transform:translateY(-9792px)} +23.208%{transform:translateY(-10098px)} +23.847%{transform:translateY(-10404px)} +24.108%{transform:translateY(-10710px)} +24.325%{transform:translateY(-11016px)} +24.603%{transform:translateY(-11322px)} +24.847%{transform:translateY(-11628px)} +25.408%{transform:translateY(-11934px)} +27.909%{transform:translateY(-12240px)} +28.348%{transform:translateY(-12546px)} +29.510%{transform:translateY(-12852px)} +30.505%{transform:translateY(-13158px)} +30.844%{transform:translateY(-13464px)} +31.644%{transform:translateY(-13770px)} +32.166%{transform:translateY(-14076px)} +33.089%{transform:translateY(-14382px)} +34.845%{transform:translateY(-14688px)} +37.346%{transform:translateY(-14994px)} +39.185%{transform:translateY(-15300px)} +39.224%{transform:translateY(-15606px)} +41.725%{transform:translateY(-15912px)} +43.164%{transform:translateY(-16218px)} +45.665%{transform:translateY(-16524px)} +45.687%{transform:translateY(-16830px)} +48.188%{transform:translateY(-17136px)} +48.550%{transform:translateY(-17442px)} +49.111%{transform:translateY(-17748px)} +49.572%{transform:translateY(-18054px)} +50.206%{transform:translateY(-18360px)} +50.472%{transform:translateY(-18666px)} +51.011%{transform:translateY(-18972px)} +51.389%{transform:translateY(-19278px)} +51.828%{transform:translateY(-19584px)} +52.145%{transform:translateY(-19890px)} +53.868%{transform:translateY(-20196px)} +54.329%{transform:translateY(-20502px)} +54.835%{transform:translateY(-20808px)} +55.168%{transform:translateY(-21114px)} +55.513%{transform:translateY(-21420px)} +56.052%{transform:translateY(-21726px)} +56.569%{transform:translateY(-22032px)} +56.869%{transform:translateY(-22338px)} +58.747%{transform:translateY(-22644px)} +58.786%{transform:translateY(-22950px)} +61.287%{transform:translateY(-23256px)} +61.309%{transform:translateY(-23562px)} +63.810%{transform:translateY(-23868px)} +65.611%{transform:translateY(-24174px)} +65.622%{transform:translateY(-24480px)} +68.123%{transform:translateY(-24786px)} +68.640%{transform:translateY(-25092px)} +69.184%{transform:translateY(-25398px)} +69.518%{transform:translateY(-25704px)} +70.140%{transform:translateY(-26010px)} +70.801%{transform:translateY(-26316px)} +71.101%{transform:translateY(-26622px)} +71.524%{transform:translateY(-26928px)} +72.163%{transform:translateY(-27234px)} +72.463%{transform:translateY(-27540px)} +72.819%{transform:translateY(-27846px)} +73.224%{transform:translateY(-28152px)} +75.097%{transform:translateY(-28458px)} +75.803%{transform:translateY(-28764px)} +76.120%{transform:translateY(-29070px)} +76.303%{transform:translateY(-29376px)} +76.464%{transform:translateY(-29682px)} +77.092%{transform:translateY(-29988px)} +77.415%{transform:translateY(-30294px)} +77.431%{transform:translateY(-30600px)} +79.932%{transform:translateY(-30906px)} +80.549%{transform:translateY(-31212px)} +81.133%{transform:translateY(-31518px)} +81.372%{transform:translateY(-31824px)} +81.777%{transform:translateY(-32130px)} +82.016%{transform:translateY(-32436px)} +82.616%{transform:translateY(-32742px)} +83.017%{transform:translateY(-33048px)} +83.311%{transform:translateY(-33354px)} +83.572%{transform:translateY(-33660px)} +85.278%{transform:translateY(-33966px)} +85.734%{transform:translateY(-34272px)} +86.234%{transform:translateY(-34578px)} +86.473%{transform:translateY(-34884px)} +87.196%{transform:translateY(-35190px)} +87.579%{transform:translateY(-35496px)} +87.779%{transform:translateY(-35802px)} +88.257%{transform:translateY(-36108px)} +88.757%{transform:translateY(-36414px)} +89.196%{transform:translateY(-36720px)} +89.374%{transform:translateY(-37026px)} +89.674%{transform:translateY(-37332px)} +89.858%{transform:translateY(-37638px)} +91.881%{transform:translateY(-37944px)} +91.920%{transform:translateY(-38250px)} +94.420%{transform:translateY(-38556px)} +94.443%{transform:translateY(-38862px)} +100.000%{transform:translateY(-38862px)} } #screen_view { - animation-duration: 28793ms; + animation-duration: 17994ms; animation-iteration-count:infinite; animation-name:roll; animation-timing-function: steps(1,end); @@ -200,5 +188,5 @@ - ~/constellation c co con cons const conste constel constell constella constellat constellation constellation c constellation co constellation con constellation conf constellation confi constellation config constellation config constellation config g constellation config ge constellation config generate constellation config generate g constellation config generate gc constellation config generate gcp constellation config generate gcp constellation cr constellation cre constellation crea constellation creat constellation create constellation create constellation create - constellation create -c constellation create -c constellation create -c 3 constellation create -c 3 constellation create -c 3 - constellation create -c 3 -w constellation create -c 3 -w constellation create -c 3 -w 5 constellation create -c 3 -w 5 constellation create -c 3 -w 5 - constellation create -c 3 -w 5 -- constellation create -c 3 -w 5 --n constellation create -c 3 -w 5 --na constellation create -c 3 -w 5 --nam constellation create -c 3 -w 5 --name constellation create -c 3 -w 5 --name constellation create -c 3 -w 5 --name d constellation create -c 3 -w 5 --name de constellation create -c 3 -w 5 --name dem constellation create -c 3 -w 5 --name demo constellation create -c 3 -w 5 --name demo constellation create -c 3 -w 5 --name demo The following Constellation cluster will be created:3 control-plane nodes of type n2d-standard-4 will be created.5 worker nodes of type n2d-standard-4 will be created.Do you want to create this cluster? [y/n]: Do you want to create this cluster? [y/n]: y Do you want to create this cluster? [y/n]: yYour Constellation cluster was created successfully.~/constellation took 2m23s constellati constellatio constellation constellation i constellation in constellation ini constellation init constellation initYour Constellation master secret was successfully written to ./constellation-mastersecret.jsonInitializing cluster ...Your Constellation cluster was successfully initialized.Constellation cluster identifier 7V/9WEa8P4sn7deu33UZEjmMF6SM7eiHv87QikQWGaU=Kubernetes configuration constellation-admin.confYou can now connect to your cluster by executing:export KUBECONFIG="$PWD/constellation-admin.conf"~/constellation took 4m11s export KUBECONFIG="$PWD/constellation-admin.conf" export KUBECONFIG="$PWD/constellation-admin.conf" k ku kub kube kubec kubect kubectl kubectl kubectl g kubectl ge kubectl get kubectl get kubectl get n kubectl get no kubectl get nod kubectl get node kubectl get nodes kubectl get nodesNAME STATUS ROLES AGE VERSIONdemo-control-plane-qedq4-8nzl Ready control-plane 3m34s v1.24.3demo-control-plane-qedq4-j9sl Ready control-plane 68s v1.24.3demo-control-plane-qedq4-qcmk Ready control-plane 62s v1.24.3demo-worker-qedq4-1sq7 Ready <none> 78s v1.24.3demo-worker-qedq4-7wzj Ready <none> 82s v1.24.3demo-worker-qedq4-lr11 Ready <none> 95s v1.24.3demo-worker-qedq4-nzzr Ready <none> 83s v1.24.3demo-worker-qedq4-r3zp Ready <none> 82s v1.24.3 constellation t constellation te constellation ter constellation term constellation termi constellation termin constellation termina constellation terminat constellation terminate constellation terminateTerminating ...Your Constellation cluster was terminated successfully.~/constellation took 3m50s + ~/constellation c co con cons const conste constel constell constella constellat constellation constellation c constellation co constellation con constellation conf constellation confi constellation config constellation config constellation config g constellation config ge constellation config generate constellation config generate g constellation config generate gc constellation config generate gcp constellation config generate gcp constellation cr constellation cre constellation crea constellation creat constellation create constellation create constellation create - constellation create -c constellation create -c constellation create -c 3 constellation create -c 3 constellation create -c 3 - constellation create -c 3 -w constellation create -c 3 -w constellation create -c 3 -w 5 constellation create -c 3 -w 5 constellation create -c 3 -w 5 The following Constellation cluster will be created:3 control-plane nodes of type n2d-standard-4 will be created.5 worker nodes of type n2d-standard-4 will be created.Do you want to create this cluster? [y/n]: Do you want to create this cluster? [y/n]: y Do you want to create this cluster? [y/n]: yYour Constellation cluster was created successfully.~/constellation took 2m23s constellati constellatio constellation constellation i constellation in constellation ini constellation init constellation initYour Constellation master secret was successfully written to ./constellation-mastersecret.jsonInitializing cluster ...Your Constellation cluster was successfully initialized.Constellation cluster identifier 7V/9WEa8P4sn7deu33UZEjmMF6SM7eiHv87QikQWGaU=Kubernetes configuration constellation-admin.confYou can now connect to your cluster by executing:export KUBECONFIG="$PWD/constellation-admin.conf"~/constellation took 4m11s export KUBECONFIG="$PWD/constellation-admin.conf" export KUBECONFIG="$PWD/constellation-admin.conf" k ku kub kube kubec kubect kubectl kubectl kubectl g kubectl ge kubectl get kubectl get kubectl get n kubectl get no kubectl get nod kubectl get node kubectl get nodes kubectl get nodesNAME STATUS ROLES AGE VERSIONdemo-control-plane-qedq4-8nzl Ready control-plane 3m34s v1.24.3demo-control-plane-qedq4-j9sl Ready control-plane 68s v1.24.3demo-control-plane-qedq4-qcmk Ready control-plane 62s v1.24.3demo-worker-qedq4-1sq7 Ready <none> 78s v1.24.3demo-worker-qedq4-7wzj Ready <none> 82s v1.24.3demo-worker-qedq4-lr11 Ready <none> 95s v1.24.3demo-worker-qedq4-nzzr Ready <none> 83s v1.24.3demo-worker-qedq4-r3zp Ready <none> 82s v1.24.3 constellation t constellation te constellation ter constellation term constellation termi constellation termin constellation termina constellation terminat constellation terminate constellation terminateTerminating ...Your Constellation cluster was terminated successfully.~/constellation took 3m50s \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 96d5aa5e0..93c72b1b2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -58,9 +58,12 @@ type Config struct { // Schema version of this configuration file. Version string `yaml:"version" validate:"eq=v2"` // description: | - // Machine image used to create Constellation nodes. + // Machine image version used to create Constellation nodes. Image string `yaml:"image" validate:"required,version_compatibility"` // description: | + // Name of the cluster. + Name string `yaml:"name" validate:"required,valid_name"` + // description: | // Size (in GB) of a node's disk to store the non-volatile state. StateDiskSizeGB int `yaml:"stateDiskSizeGB" validate:"min=0"` // description: | @@ -252,6 +255,7 @@ func Default() *Config { return &Config{ Version: Version2, Image: defaultImage, + Name: "constell", MicroserviceVersion: compatibility.EnsurePrefixV(constants.VersionInfo), KubernetesVersion: string(versions.Default), StateDiskSizeGB: 30, @@ -505,6 +509,13 @@ func (c *Config) Validate(force bool) error { if err := validate.RegisterTranslation("version_compatibility", trans, registerVersionCompatibilityError, translateVersionCompatibilityError); err != nil { return err } + if err := validate.RegisterTranslation("valid_name", trans, registerValidateNameError, c.translateValidateNameError); err != nil { + return err + } + + if err := validate.RegisterValidation("valid_name", c.validateName); err != nil { + return err + } if err := validate.RegisterValidation("no_placeholders", validateNoPlaceholder); err != nil { return err diff --git a/internal/config/config_doc.go b/internal/config/config_doc.go index ccb48cdd5..08228481e 100644 --- a/internal/config/config_doc.go +++ b/internal/config/config_doc.go @@ -24,7 +24,7 @@ func init() { ConfigDoc.Type = "Config" ConfigDoc.Comments[encoder.LineComment] = "Config defines configuration used by CLI." ConfigDoc.Description = "Config defines configuration used by CLI." - ConfigDoc.Fields = make([]encoder.Doc, 8) + ConfigDoc.Fields = make([]encoder.Doc, 9) ConfigDoc.Fields[0].Name = "version" ConfigDoc.Fields[0].Type = "string" ConfigDoc.Fields[0].Note = "" @@ -33,40 +33,45 @@ func init() { ConfigDoc.Fields[1].Name = "image" ConfigDoc.Fields[1].Type = "string" ConfigDoc.Fields[1].Note = "" - ConfigDoc.Fields[1].Description = "Machine image used to create Constellation nodes." - ConfigDoc.Fields[1].Comments[encoder.LineComment] = "Machine image used to create Constellation nodes." - ConfigDoc.Fields[2].Name = "stateDiskSizeGB" - ConfigDoc.Fields[2].Type = "int" + ConfigDoc.Fields[1].Description = "Machine image version used to create Constellation nodes." + ConfigDoc.Fields[1].Comments[encoder.LineComment] = "Machine image version used to create Constellation nodes." + ConfigDoc.Fields[2].Name = "name" + ConfigDoc.Fields[2].Type = "string" ConfigDoc.Fields[2].Note = "" - ConfigDoc.Fields[2].Description = "Size (in GB) of a node's disk to store the non-volatile state." - ConfigDoc.Fields[2].Comments[encoder.LineComment] = "Size (in GB) of a node's disk to store the non-volatile state." - ConfigDoc.Fields[3].Name = "kubernetesVersion" - ConfigDoc.Fields[3].Type = "string" + ConfigDoc.Fields[2].Description = "Name of the cluster." + ConfigDoc.Fields[2].Comments[encoder.LineComment] = "Name of the cluster." + ConfigDoc.Fields[3].Name = "stateDiskSizeGB" + ConfigDoc.Fields[3].Type = "int" ConfigDoc.Fields[3].Note = "" - ConfigDoc.Fields[3].Description = "Kubernetes version to be installed into the cluster." - ConfigDoc.Fields[3].Comments[encoder.LineComment] = "Kubernetes version to be installed into the cluster." - ConfigDoc.Fields[4].Name = "microserviceVersion" + ConfigDoc.Fields[3].Description = "Size (in GB) of a node's disk to store the non-volatile state." + ConfigDoc.Fields[3].Comments[encoder.LineComment] = "Size (in GB) of a node's disk to store the non-volatile state." + ConfigDoc.Fields[4].Name = "kubernetesVersion" ConfigDoc.Fields[4].Type = "string" ConfigDoc.Fields[4].Note = "" - ConfigDoc.Fields[4].Description = "Microservice version to be installed into the cluster. Setting this value is optional until v2.7. Defaults to the version of the CLI." - ConfigDoc.Fields[4].Comments[encoder.LineComment] = "Microservice version to be installed into the cluster. Setting this value is optional until v2.7. Defaults to the version of the CLI." - ConfigDoc.Fields[5].Name = "debugCluster" - ConfigDoc.Fields[5].Type = "bool" + ConfigDoc.Fields[4].Description = "Kubernetes version to be installed into the cluster." + ConfigDoc.Fields[4].Comments[encoder.LineComment] = "Kubernetes version to be installed into the cluster." + ConfigDoc.Fields[5].Name = "microserviceVersion" + ConfigDoc.Fields[5].Type = "string" ConfigDoc.Fields[5].Note = "" - ConfigDoc.Fields[5].Description = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md" - ConfigDoc.Fields[5].Comments[encoder.LineComment] = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md" - ConfigDoc.Fields[6].Name = "provider" - ConfigDoc.Fields[6].Type = "ProviderConfig" + ConfigDoc.Fields[5].Description = "Microservice version to be installed into the cluster. Setting this value is optional until v2.7. Defaults to the version of the CLI." + ConfigDoc.Fields[5].Comments[encoder.LineComment] = "Microservice version to be installed into the cluster. Setting this value is optional until v2.7. Defaults to the version of the CLI." + ConfigDoc.Fields[6].Name = "debugCluster" + ConfigDoc.Fields[6].Type = "bool" ConfigDoc.Fields[6].Note = "" - ConfigDoc.Fields[6].Description = "Supported cloud providers and their specific configurations." - ConfigDoc.Fields[6].Comments[encoder.LineComment] = "Supported cloud providers and their specific configurations." - ConfigDoc.Fields[7].Name = "upgrade" - ConfigDoc.Fields[7].Type = "UpgradeConfig" + ConfigDoc.Fields[6].Description = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md" + ConfigDoc.Fields[6].Comments[encoder.LineComment] = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md" + ConfigDoc.Fields[7].Name = "provider" + ConfigDoc.Fields[7].Type = "ProviderConfig" ConfigDoc.Fields[7].Note = "" - ConfigDoc.Fields[7].Description = "Configuration to apply during constellation upgrade." - ConfigDoc.Fields[7].Comments[encoder.LineComment] = "Configuration to apply during constellation upgrade." + ConfigDoc.Fields[7].Description = "Supported cloud providers and their specific configurations." + ConfigDoc.Fields[7].Comments[encoder.LineComment] = "Supported cloud providers and their specific configurations." + ConfigDoc.Fields[8].Name = "upgrade" + ConfigDoc.Fields[8].Type = "UpgradeConfig" + ConfigDoc.Fields[8].Note = "" + ConfigDoc.Fields[8].Description = "Configuration to apply during constellation upgrade." + ConfigDoc.Fields[8].Comments[encoder.LineComment] = "Configuration to apply during constellation upgrade." - ConfigDoc.Fields[7].AddExample("", UpgradeConfig{Image: "", Measurements: Measurements{}}) + ConfigDoc.Fields[8].AddExample("", UpgradeConfig{Image: "", Measurements: Measurements{}}) UpgradeConfigDoc.Type = "UpgradeConfig" UpgradeConfigDoc.Comments[encoder.LineComment] = "UpgradeConfig defines configuration used during constellation upgrade." diff --git a/internal/config/validation.go b/internal/config/validation.go index 8ff1c477b..1f606c717 100644 --- a/internal/config/validation.go +++ b/internal/config/validation.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "sort" + "strconv" "strings" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" @@ -366,3 +367,28 @@ func returnsTrue(fl validator.FieldLevel) bool { func validateUpgradeConfig(sl validator.StructLevel) { fmt.Printf("WARNING: the config key `upgrade` will be deprecated in an upcoming version. Please check the documentation for more information.\n") } + +func registerValidateNameError(ut ut.Translator) error { + return ut.Add("validate_name", "{0} must be no more than {1} characters long", true) +} + +func (c *Config) translateValidateNameError(ut ut.Translator, fe validator.FieldError) string { + var t string + if c.Provider.AWS != nil { + t, _ = ut.T("validate_name", fe.Field(), strconv.Itoa(constants.AWSConstellationNameLength)) + } else { + t, _ = ut.T("validate_name", fe.Field(), strconv.Itoa(constants.ConstellationNameLength)) + } + + return t +} + +// validateName makes sure the name of the constellation is not too long. +// Since this value may differ between providers, we can't simply use built-in validation. +// This also allows us to eventually add more validation rules for constellation names if necessary. +func (c *Config) validateName(fl validator.FieldLevel) bool { + if c.Provider.AWS != nil { + return len(fl.Field().String()) <= constants.AWSConstellationNameLength + } + return len(fl.Field().String()) <= constants.ConstellationNameLength +} diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 01760dc5c..ea063b817 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -21,6 +21,8 @@ const ( // ConstellationNameLength is the maximum length of a Constellation's name. ConstellationNameLength = 37 + // AWSConstellationNameLength is the maximum length of a Constellation's name on AWS. + AWSConstellationNameLength = 10 // ConstellationMasterSecretStoreName is the name for the Constellation secrets in Kubernetes. ConstellationMasterSecretStoreName = "constellation-mastersecret" // ConstellationMasterSecretKey is the name of the key for the master secret in the master secret kubernetes secret.