Skip to content

Commit

Permalink
Update flag help and add missing phases
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse committed Oct 24, 2023
1 parent 2788988 commit cb27cf7
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 61 deletions.
94 changes: 74 additions & 20 deletions cli/internal/cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,57 @@ import (
k8serrors "k8s.io/apimachinery/pkg/api/errors"
)

const (
// skipInfrastructurePhase skips the Terraform apply of the apply process.
skipInfrastructurePhase skipPhase = "infrastructure"
// skipInitPhase skips the init RPC of the apply process.
skipInitPhase skipPhase = "init"
// skipAttestationConfigPhase skips the attestation config upgrade of the apply process.
skipAttestationConfigPhase skipPhase = "attestationconfig"
// skipCertSANsPhase skips the cert SANs upgrade of the apply process.
skipCertSANsPhase skipPhase = "certsans"
// skipHelmPhase skips the helm upgrade of the apply process.
skipHelmPhase skipPhase = "helm"
// skipImagePhase skips the image upgrade of the apply process.
skipImagePhase skipPhase = "image"
// skipK8sPhase skips the Kubernetes version upgrade of the apply process.
skipK8sPhase skipPhase = "k8s"
)

// skipPhase is a phase of the upgrade process that can be skipped.
type skipPhase string

// skipPhases is a list of phases that can be skipped during the upgrade process.
type skipPhases map[skipPhase]struct{}

// contains returns true if the list of phases contains the given phase.
func (s skipPhases) contains(phase skipPhase) bool {
_, ok := s[skipPhase(strings.ToLower(string(phase)))]
return ok
}

// add a phase to the list of phases.
func (s *skipPhases) add(phases ...skipPhase) {
if *s == nil {
*s = make(skipPhases)
}
for _, phase := range phases {
(*s)[skipPhase(strings.ToLower(string(phase)))] = struct{}{}
}
}

func printAllPhases() string {
return fmt.Sprintf("{ %s }", strings.Join([]string{
string(skipInfrastructurePhase),
string(skipInitPhase),
string(skipAttestationConfigPhase),
string(skipCertSANsPhase),
string(skipHelmPhase),
string(skipImagePhase),
string(skipK8sPhase),
}, " | "))
}

// NewApplyCmd creates the apply command.
func NewApplyCmd() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -53,13 +104,12 @@ func NewApplyCmd() *cobra.Command {
cmd.Flags().Bool("conformance", false, "enable conformance mode")
cmd.Flags().Bool("skip-helm-wait", false, "install helm charts without waiting for deployments to be ready")
cmd.Flags().Bool("merge-kubeconfig", false, "merge Constellation kubeconfig file with default kubeconfig file in $HOME/.kube/config")
cmd.Flags().BoolP("yes", "y", false, "run upgrades without further confirmation\n"+
"WARNING: might delete your resources in case you are using cert-manager in your cluster. Please read the docs.\n"+
"WARNING: might unintentionally overwrite measurements in the running cluster.")
cmd.Flags().BoolP("yes", "y", false, "run command without further confirmation\n"+
"WARNING: the command might delete or update existing resources without additional checks. Please read the docs.\n")
cmd.Flags().Duration("timeout", 5*time.Minute, "change helm upgrade timeout\n"+
"Might be useful for slow connections or big clusters.")
cmd.Flags().StringSlice("skip-phases", nil, "comma-separated list of upgrade phases to skip\n"+
"one or multiple of { infrastructure | helm | image | k8s }")
fmt.Sprintf("one or multiple of %s", printAllPhases()))

must(cmd.Flags().MarkHidden("timeout"))

Expand Down Expand Up @@ -228,7 +278,7 @@ The control flow is as follows:
│ │Not up to date │
│ │(Diff from Terraform plan)│
│ └────────────┐ │
│ │ │Terraform
│ │ |Infrastructure
│ ┌────────────▼──────────┐ │Phase
│ │Apply Terraform updates│ │
│ └────────────┬──────────┘ │
Expand All @@ -254,14 +304,14 @@ The control flow is as follows:
└──────────────┬───────────────┘ │ │
│ │ │
└───────────────┐ │ ───┘
│ │
┌──────────▼──▼──────────┐
│Apply Attestation Config│
└─────────────┬──────────┘
┌──────────────▼────────────┐
│Extend API Server Cert SANs│
└──────────────┬────────────┘
│ │ ───┐
┌──────────▼──▼──────────┐ │AttestationConfig
│Apply Attestation Config│ │Phase
└─────────────┬──────────┘ ───┘
───┐
┌──────────────▼────────────┐ │CertSANs
│Extend API Server Cert SANs│ │Phase
└──────────────┬────────────┘ ───┘
│ ───┐
┌──────────▼────────┐ │Helm
│ Apply Helm Charts │ │Phase
Expand Down Expand Up @@ -303,22 +353,26 @@ func (a *applyCmd) apply(cmd *cobra.Command, configFetcher attestationconfigapi.
}

// From now on we can assume a valid Kubernetes admin config file exists
a.log.Debugf("Creating Kubernetes client using %s", a.flags.pathPrefixer.PrefixPrintablePath(constants.AdminConfFilename))
kubeUpgrader, err := a.newKubeUpgrader(cmd.OutOrStdout(), constants.AdminConfFilename, a.log)
if err != nil {
return err
}

// Apply Attestation Config
a.log.Debugf("Creating Kubernetes client using %s", a.flags.pathPrefixer.PrefixPrintablePath(constants.AdminConfFilename))
a.log.Debugf("Applying new attestation config to cluster")
if err := a.applyJoinConfig(cmd, kubeUpgrader, conf.GetAttestationConfig(), stateFile.ClusterValues.MeasurementSalt); err != nil {
return fmt.Errorf("applying attestation config: %w", err)
if !a.flags.skipPhases.contains(skipAttestationConfigPhase) {
a.log.Debugf("Applying new attestation config to cluster")
if err := a.applyJoinConfig(cmd, kubeUpgrader, conf.GetAttestationConfig(), stateFile.ClusterValues.MeasurementSalt); err != nil {
return fmt.Errorf("applying attestation config: %w", err)
}
}

// Extend API Server Cert SANs
sans := append([]string{stateFile.Infrastructure.ClusterEndpoint, conf.CustomEndpoint}, stateFile.Infrastructure.APIServerCertSANs...)
if err := kubeUpgrader.ExtendClusterConfigCertSANs(cmd.Context(), sans); err != nil {
return fmt.Errorf("extending cert SANs: %w", err)
if !a.flags.skipPhases.contains(skipCertSANsPhase) {
sans := append([]string{stateFile.Infrastructure.ClusterEndpoint, conf.CustomEndpoint}, stateFile.Infrastructure.APIServerCertSANs...)
if err := kubeUpgrader.ExtendClusterConfigCertSANs(cmd.Context(), sans); err != nil {
return fmt.Errorf("extending cert SANs: %w", err)
}
}

// Apply Helm Charts
Expand Down
36 changes: 0 additions & 36 deletions cli/internal/cmd/upgradeapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"context"
"fmt"
"io"
"strings"
"time"

"github.com/edgelesssys/constellation/v2/cli/internal/state"
Expand All @@ -24,22 +23,6 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)

const (
// skipInitPhase skips the init RPC of the apply process.
skipInitPhase skipPhase = "init"
// skipInfrastructurePhase skips the terraform apply of the upgrade process.
skipInfrastructurePhase skipPhase = "infrastructure"
// skipHelmPhase skips the helm upgrade of the upgrade process.
skipHelmPhase skipPhase = "helm"
// skipImagePhase skips the image upgrade of the upgrade process.
skipImagePhase skipPhase = "image"
// skipK8sPhase skips the k8s upgrade of the upgrade process.
skipK8sPhase skipPhase = "k8s"
)

// skipPhase is a phase of the upgrade process that can be skipped.
type skipPhase string

func newUpgradeApplyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "apply",
Expand Down Expand Up @@ -82,25 +65,6 @@ func diffAttestationCfg(currentAttestationCfg config.AttestationCfg, newAttestat
return diff, nil
}

// skipPhases is a list of phases that can be skipped during the upgrade process.
type skipPhases map[skipPhase]struct{}

// contains returns true if the list of phases contains the given phase.
func (s skipPhases) contains(phase skipPhase) bool {
_, ok := s[skipPhase(strings.ToLower(string(phase)))]
return ok
}

// add a phase to the list of phases.
func (s *skipPhases) add(phases ...skipPhase) {
if *s == nil {
*s = make(skipPhases)
}
for _, phase := range phases {
(*s)[skipPhase(strings.ToLower(string(phase)))] = struct{}{}
}
}

type kubernetesUpgrader interface {
UpgradeNodeVersion(ctx context.Context, conf *config.Config, force, skipImage, skipK8s bool) error
ExtendClusterConfigCertSANs(ctx context.Context, alternativeNames []string) error
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Apply a configuration to a Constellation cluster

### Synopsis

Apply an upgrade to a Constellation cluster by applying the chosen configuration.
Apply a configuration to a Constellation cluster to initialize or upgrade the cluster.

```
constellation apply [flags]
Expand All @@ -60,10 +60,10 @@ constellation apply [flags]
--merge-kubeconfig merge Constellation kubeconfig file with default kubeconfig file in $HOME/.kube/config
--skip-helm-wait install helm charts without waiting for deployments to be ready
--skip-phases strings comma-separated list of upgrade phases to skip
one or multiple of { infrastructure | helm | image | k8s }
-y, --yes run upgrades without further confirmation
WARNING: might delete your resources in case you are using cert-manager in your cluster. Please read the docs.
WARNING: might unintentionally overwrite measurements in the running cluster.
one or multiple of { infrastructure | init | attestationconfig | certsans | helm | image | k8s }
-y, --yes run command without further confirmation
WARNING: the command might delete or update existing resources without additional checks. Please read the docs.
```

### Options inherited from parent commands
Expand Down

0 comments on commit cb27cf7

Please sign in to comment.