cli: use apply command to start mini cluster (#2551)

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Daniel Weiße 2023-11-20 12:10:16 +01:00 committed by GitHub
parent 4c8ce55e5a
commit 35abc3c354
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 92 deletions

View File

@ -48,7 +48,7 @@ func checkForMiniCluster(fileHandler file.Handler) error {
return fmt.Errorf("reading state file: %w", err) return fmt.Errorf("reading state file: %w", err)
} }
if stateFile.Infrastructure.UID != constants.MiniConstellationUID { if stateFile.Infrastructure.Name != constants.MiniConstellationName {
return errors.New("cluster is not a MiniConstellation cluster") return errors.New("cluster is not a MiniConstellation cluster")
} }

View File

@ -7,17 +7,13 @@ SPDX-License-Identifier: AGPL-3.0-only
package cmd package cmd
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
"path/filepath"
"time" "time"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/cli/internal/featureset" "github.com/edgelesssys/constellation/v2/cli/internal/featureset"
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt" "github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
"github.com/edgelesssys/constellation/v2/cli/internal/state"
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/config"
@ -55,11 +51,6 @@ func runUp(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("creating logger: %w", err) return fmt.Errorf("creating logger: %w", err)
} }
defer log.Sync() defer log.Sync()
spinner, err := newSpinnerOrStderr(cmd)
if err != nil {
return err
}
defer spinner.Stop()
m := &miniUpCmd{ m := &miniUpCmd{
log: log, log: log,
@ -70,23 +61,10 @@ func runUp(cmd *cobra.Command, _ []string) error {
return err return err
} }
creator, cleanUp, err := cloudcmd.NewApplier( return m.up(cmd)
cmd.Context(),
spinner,
constants.TerraformWorkingDir,
filepath.Join(constants.UpgradeDir, "create"), // Not used by create
m.flags.tfLogLevel,
m.fileHandler,
)
if err != nil {
return err
}
defer cleanUp()
return m.up(cmd, creator, spinner)
} }
func (m *miniUpCmd) up(cmd *cobra.Command, creator cloudApplier, spinner spinnerInterf) error { func (m *miniUpCmd) up(cmd *cobra.Command) (retErr error) {
if err := m.checkSystemRequirements(cmd.ErrOrStderr()); err != nil { if err := m.checkSystemRequirements(cmd.ErrOrStderr()); err != nil {
return fmt.Errorf("system requirements not met: %w", err) return fmt.Errorf("system requirements not met: %w", err)
} }
@ -106,27 +84,39 @@ func (m *miniUpCmd) up(cmd *cobra.Command, creator cloudApplier, spinner spinner
return fmt.Errorf("preparing config: %w", err) return fmt.Errorf("preparing config: %w", err)
} }
// create cluster // clean up cluster resources if setup fails
spinner.Start("Creating cluster in QEMU ", false) defer func() {
err = m.createMiniCluster(cmd.Context(), creator, config) if retErr != nil {
spinner.Stop() cmd.PrintErrf("An error occurred: %s\n", retErr)
cmd.PrintErrln("Attempting to roll back.")
err = runDown(cmd, []string{})
if err != nil { if err != nil {
cmd.PrintErrf("Rollback failed: %s\n", err)
} else {
cmd.PrintErrf("Rollback succeeded.\n\n")
}
}
}()
// set flags not defined by "mini up"
cmd.Flags().StringSlice("skip-phases", []string{}, "")
cmd.Flags().Bool("yes", true, "")
cmd.Flags().Bool("skip-helm-wait", false, "")
cmd.Flags().Bool("conformance", false, "")
cmd.Flags().Duration("timeout", time.Hour, "")
// create and initialize the cluster
if err := runApply(cmd, nil); err != nil {
return fmt.Errorf("creating cluster: %w", err) return fmt.Errorf("creating cluster: %w", err)
} }
cmd.Println("Cluster successfully created.")
connectURI := config.Provider.QEMU.LibvirtURI connectURI := config.Provider.QEMU.LibvirtURI
m.log.Debugf("Using connect URI %s", connectURI)
if connectURI == "" { if connectURI == "" {
connectURI = libvirt.LibvirtTCPConnectURI connectURI = libvirt.LibvirtTCPConnectURI
} }
cmd.Println("Connect to the VMs by executing:") cmd.Println("Connect to the VMs by executing:")
cmd.Printf("\tvirsh -c %s\n\n", connectURI) cmd.Printf("\tvirsh -c %s\n\n", connectURI)
// initialize cluster
if err := m.initializeMiniCluster(cmd); err != nil {
return fmt.Errorf("initializing cluster: %w", err)
}
m.log.Debugf("Initialized cluster")
return nil return nil
} }
@ -181,54 +171,3 @@ func (m *miniUpCmd) prepareExistingConfig(cmd *cobra.Command) (*config.Config, e
} }
return conf, nil return conf, nil
} }
// createMiniCluster creates a new cluster using the given config.
func (m *miniUpCmd) createMiniCluster(ctx context.Context, creator cloudApplier, config *config.Config) error {
m.log.Debugf("Creating mini cluster")
if _, err := creator.Plan(ctx, config); err != nil {
return err
}
infraState, err := creator.Apply(ctx, config.GetProvider(), cloudcmd.WithoutRollbackOnError)
if err != nil {
return err
}
infraState.UID = constants.MiniConstellationUID // use UID "mini" to identify MiniConstellation clusters.
stateFile := state.New().
SetInfrastructure(infraState)
m.log.Debugf("Cluster state file contains %v", stateFile)
return stateFile.WriteToFile(m.fileHandler, constants.StateFilename)
}
// initializeMiniCluster initializes a QEMU cluster.
func (m *miniUpCmd) initializeMiniCluster(cmd *cobra.Command) (retErr error) {
m.log.Debugf("Initializing mini cluster")
// clean up cluster resources if initialization fails
defer func() {
if retErr != nil {
cmd.PrintErrf("An error occurred: %s\n", retErr)
cmd.PrintErrln("Attempting to roll back.")
_ = runDown(cmd, []string{})
cmd.PrintErrf("Rollback succeeded.\n\n")
}
}()
// Define flags for apply backend that are not set by mini up
cmd.Flags().StringSlice(
"skip-phases",
[]string{string(skipInfrastructurePhase), string(skipK8sPhase), string(skipImagePhase)},
"",
)
cmd.Flags().Bool("yes", false, "")
cmd.Flags().Bool("skip-helm-wait", false, "")
cmd.Flags().Bool("conformance", false, "")
cmd.Flags().Duration("timeout", time.Hour, "")
if err := runApply(cmd, nil); err != nil {
return err
}
m.log.Debugf("Initialized mini cluster")
return nil
}

View File

@ -16,7 +16,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@ -76,9 +75,8 @@ func (r *Runner) Start(ctx context.Context, name, imageName string) error {
// check if it is using the correct image and if it is running // check if it is using the correct image and if it is running
if len(containers) == 1 { if len(containers) == 1 {
// make sure the container we listed is using the correct image // make sure the container we listed is using the correct image
imageBase := strings.Split(imageName, ":")[0] if containers[0].Image != imageName {
if containers[0].Image != imageBase { return fmt.Errorf("existing libvirt container %q is using a different image: expected %q, got %q", containerName, imageName, containers[0].Image)
return fmt.Errorf("existing libvirt container %q is using a different image: expected %q, got %q", containerName, imageBase, containers[0].Image)
} }
// container already exists, check if its running // container already exists, check if its running

View File

@ -159,6 +159,8 @@ const (
EnvVarNoSpinner = EnvVarPrefix + "NO_SPINNER" EnvVarNoSpinner = EnvVarPrefix + "NO_SPINNER"
// MiniConstellationUID is a sentinel value for the UID of a mini constellation. // MiniConstellationUID is a sentinel value for the UID of a mini constellation.
MiniConstellationUID = "mini" MiniConstellationUID = "mini"
// MiniConstellationName is a sentinel value for the name of a mini constellation.
MiniConstellationName = MiniConstellationUID + "-qemu"
// TerraformLogFile is the file name of the Terraform log file. // TerraformLogFile is the file name of the Terraform log file.
TerraformLogFile = "terraform.log" TerraformLogFile = "terraform.log"
// TerraformUpgradeWorkingDir is the directory name for the Terraform workspace being used in an upgrade. // TerraformUpgradeWorkingDir is the directory name for the Terraform workspace being used in an upgrade.