mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-12-11 06:02:41 -05:00
CLI: use global image version field
- Restructure config by removing CSP-specific image references - Add global image field - Download image lookup table on create - Download QEMU image on QEMU create
This commit is contained in:
parent
9222468d3b
commit
575b6e93f6
21 changed files with 1068 additions and 380 deletions
|
|
@ -8,9 +8,11 @@ package cloudcmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
)
|
||||
|
||||
type terraformClient interface {
|
||||
|
|
@ -25,3 +27,11 @@ type libvirtRunner interface {
|
|||
Start(ctx context.Context, containerName, imageName string) error
|
||||
Stop(ctx context.Context) error
|
||||
}
|
||||
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, config *config.Config) (string, error)
|
||||
}
|
||||
|
||||
type rawDownloader interface {
|
||||
Download(ctx context.Context, errWriter io.Writer, isTTY bool, source, version string) (string, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ package cloudcmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
|
||||
"go.uber.org/goleak"
|
||||
)
|
||||
|
|
@ -72,3 +74,21 @@ func (r *stubLibvirtRunner) Stop(context.Context) error {
|
|||
r.stopCalled = true
|
||||
return r.stopErr
|
||||
}
|
||||
|
||||
type stubImageFetcher struct {
|
||||
reference string
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context, _ *config.Config) (string, error) {
|
||||
return f.reference, f.fetchReferenceErr
|
||||
}
|
||||
|
||||
type stubRawDownloader struct {
|
||||
destination string
|
||||
downloadErr error
|
||||
}
|
||||
|
||||
func (d *stubRawDownloader) Download(_ context.Context, _ io.Writer, _ bool, _ string, _ string) (string, error) {
|
||||
return d.destination, d.downloadErr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,31 +22,43 @@ import (
|
|||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/image"
|
||||
)
|
||||
|
||||
// Creator creates cloud resources.
|
||||
type Creator struct {
|
||||
out io.Writer
|
||||
image imageFetcher
|
||||
newTerraformClient func(ctx context.Context) (terraformClient, error)
|
||||
newLibvirtRunner func() libvirtRunner
|
||||
newRawDownloader func() rawDownloader
|
||||
}
|
||||
|
||||
// NewCreator creates a new creator.
|
||||
func NewCreator(out io.Writer) *Creator {
|
||||
return &Creator{
|
||||
out: out,
|
||||
out: out,
|
||||
image: image.New(),
|
||||
newTerraformClient: func(ctx context.Context) (terraformClient, error) {
|
||||
return terraform.New(ctx, constants.TerraformWorkingDir)
|
||||
},
|
||||
newLibvirtRunner: func() libvirtRunner {
|
||||
return libvirt.New()
|
||||
},
|
||||
newRawDownloader: func() rawDownloader {
|
||||
return image.NewDownloader()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
) (clusterid.File, error) {
|
||||
image, err := c.image.FetchReference(ctx, config)
|
||||
if err != nil {
|
||||
return clusterid.File{}, fmt.Errorf("fetching image reference: %w", err)
|
||||
}
|
||||
|
||||
switch provider {
|
||||
case cloudprovider.AWS:
|
||||
cl, err := c.newTerraformClient(ctx)
|
||||
|
|
@ -54,21 +66,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)
|
||||
return c.createAWS(ctx, cl, config, name, 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)
|
||||
return c.createGCP(ctx, cl, config, name, 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)
|
||||
return c.createAzure(ctx, cl, config, name, 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)
|
||||
|
|
@ -79,14 +91,14 @@ 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)
|
||||
return c.createQEMU(ctx, cl, lv, name, 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,
|
||||
name, insType string, controlPlaneCount, workerCount int, image string,
|
||||
) (idFile clusterid.File, retErr error) {
|
||||
vars := terraform.AWSVariables{
|
||||
CommonVariables: terraform.CommonVariables{
|
||||
|
|
@ -99,7 +111,7 @@ func (c *Creator) createAWS(ctx context.Context, cl terraformClient, config *con
|
|||
Region: config.Provider.AWS.Region,
|
||||
Zone: config.Provider.AWS.Zone,
|
||||
InstanceType: insType,
|
||||
AMIImageID: config.Provider.AWS.Image,
|
||||
AMIImageID: image,
|
||||
IAMProfileControlPlane: config.Provider.AWS.IAMProfileControlPlane,
|
||||
IAMProfileWorkerNodes: config.Provider.AWS.IAMProfileWorkerNodes,
|
||||
Debug: config.IsDebugCluster(),
|
||||
|
|
@ -122,7 +134,7 @@ 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,
|
||||
name, insType string, controlPlaneCount, workerCount int, image string,
|
||||
) (idFile clusterid.File, retErr error) {
|
||||
vars := terraform.GCPVariables{
|
||||
CommonVariables: terraform.CommonVariables{
|
||||
|
|
@ -137,7 +149,7 @@ func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *con
|
|||
CredentialsFile: config.Provider.GCP.ServiceAccountKeyPath,
|
||||
InstanceType: insType,
|
||||
StateDiskType: config.Provider.GCP.StateDiskType,
|
||||
ImageID: config.Provider.GCP.Image,
|
||||
ImageID: image,
|
||||
Debug: config.IsDebugCluster(),
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +170,7 @@ 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,
|
||||
name, insType string, controlPlaneCount, workerCount int, image string,
|
||||
) (idFile clusterid.File, retErr error) {
|
||||
vars := terraform.AzureVariables{
|
||||
CommonVariables: terraform.CommonVariables{
|
||||
|
|
@ -172,7 +184,7 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, config *c
|
|||
UserAssignedIdentity: config.Provider.Azure.UserAssignedIdentity,
|
||||
InstanceType: insType,
|
||||
StateDiskType: config.Provider.Azure.StateDiskType,
|
||||
ImageID: config.Provider.Azure.Image,
|
||||
ImageID: image,
|
||||
ConfidentialVM: *config.Provider.Azure.ConfidentialVM,
|
||||
SecureBoot: *config.Provider.Azure.SecureBoot,
|
||||
Debug: config.IsDebugCluster(),
|
||||
|
|
@ -223,11 +235,18 @@ func normalizeAzureURIs(vars terraform.AzureVariables) terraform.AzureVariables
|
|||
}
|
||||
|
||||
func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirtRunner, name string, config *config.Config,
|
||||
controlPlaneCount, workerCount int,
|
||||
controlPlaneCount, workerCount int, source string,
|
||||
) (idFile clusterid.File, retErr error) {
|
||||
qemuRollbacker := &rollbackerQEMU{client: cl, libvirt: lv, createdWorkspace: false}
|
||||
defer rollbackOnError(context.Background(), c.out, &retErr, qemuRollbacker)
|
||||
|
||||
// TODO: render progress bar
|
||||
downloader := c.newRawDownloader()
|
||||
imagePath, err := downloader.Download(ctx, c.out, false, source, config.Image)
|
||||
if err != nil {
|
||||
return clusterid.File{}, fmt.Errorf("download raw image: %w", err)
|
||||
}
|
||||
|
||||
libvirtURI := config.Provider.QEMU.LibvirtURI
|
||||
libvirtSocketPath := "."
|
||||
|
||||
|
|
@ -273,7 +292,7 @@ func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirt
|
|||
},
|
||||
LibvirtURI: libvirtURI,
|
||||
LibvirtSocketPath: libvirtSocketPath,
|
||||
ImagePath: config.Provider.QEMU.Image,
|
||||
ImagePath: imagePath,
|
||||
ImageFormat: config.Provider.QEMU.ImageFormat,
|
||||
CPUCount: config.Provider.QEMU.VCPUs,
|
||||
MemorySizeMiB: config.Provider.QEMU.Memory,
|
||||
|
|
|
|||
|
|
@ -98,12 +98,20 @@ func TestCreator(t *testing.T) {
|
|||
|
||||
creator := &Creator{
|
||||
out: &bytes.Buffer{},
|
||||
image: &stubImageFetcher{
|
||||
reference: "some-image",
|
||||
},
|
||||
newTerraformClient: func(ctx context.Context) (terraformClient, error) {
|
||||
return tc.tfClient, tc.newTfClientErr
|
||||
},
|
||||
newLibvirtRunner: func() libvirtRunner {
|
||||
return tc.libvirt
|
||||
},
|
||||
newRawDownloader: func() rawDownloader {
|
||||
return &stubRawDownloader{
|
||||
destination: "some-destination",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
idFile, err := creator.Create(context.Background(), tc.provider, tc.config, "name", "type", 2, 3)
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -49,10 +49,10 @@ func runConfigFetchMeasurements(cmd *cobra.Command, args []string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("constructing Rekor client: %w", err)
|
||||
}
|
||||
return configFetchMeasurements(cmd, rekor, fileHandler, http.DefaultClient)
|
||||
return configFetchMeasurements(cmd, rekor, fileHandler, http.DefaultClient, image.New())
|
||||
}
|
||||
|
||||
func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHandler file.Handler, client *http.Client) error {
|
||||
func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHandler file.Handler, client *http.Client, img imageFetcher) error {
|
||||
flags, err := parseFetchMeasurementsFlags(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -63,16 +63,17 @@ func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHan
|
|||
return displayConfigValidationErrors(cmd.ErrOrStderr(), err)
|
||||
}
|
||||
|
||||
if conf.IsDebugImage() {
|
||||
if !conf.IsReleaseImage() {
|
||||
cmd.PrintErrln("Configured image doesn't look like a released production image. Double check image before deploying to production.")
|
||||
}
|
||||
|
||||
if err := flags.updateURLs(conf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
if err := flags.updateURLs(ctx, conf, img); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fetchedMeasurements measurements.M
|
||||
hash, err := fetchedMeasurements.FetchAndVerify(ctx, client, flags.measurementsURL, flags.signatureURL, []byte(constants.CosignPublicKey))
|
||||
if err != nil {
|
||||
|
|
@ -128,9 +129,15 @@ func parseFetchMeasurementsFlags(cmd *cobra.Command) (*fetchMeasurementsFlags, e
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (f *fetchMeasurementsFlags) updateURLs(conf *config.Config) error {
|
||||
func (f *fetchMeasurementsFlags) updateURLs(ctx context.Context, conf *config.Config, img imageFetcher) error {
|
||||
imageRef, err := img.FetchReference(ctx, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.measurementsURL == nil {
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(conf.Image()) + "/measurements.yaml")
|
||||
// TODO(AB#2644): resolve image version to reference
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + imageRef + "/measurements.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -138,7 +145,7 @@ func (f *fetchMeasurementsFlags) updateURLs(conf *config.Config) error {
|
|||
}
|
||||
|
||||
if f.signatureURL == nil {
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(conf.Image()) + "/measurements.yaml.sig")
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + imageRef + "/measurements.yaml.sig")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -146,3 +153,7 @@ func (f *fetchMeasurementsFlags) updateURLs(conf *config.Config) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, config *config.Config) (string, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -102,10 +103,9 @@ func TestUpdateURLs(t *testing.T) {
|
|||
}{
|
||||
"both values nil": {
|
||||
conf: &config.Config{
|
||||
Image: "someImageVersion",
|
||||
Provider: config.ProviderConfig{
|
||||
GCP: &config.GCPConfig{
|
||||
Image: "some/image/path/image-123456",
|
||||
},
|
||||
GCP: &config.GCPConfig{},
|
||||
},
|
||||
},
|
||||
flags: &fetchMeasurementsFlags{},
|
||||
|
|
@ -127,7 +127,9 @@ func TestUpdateURLs(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
err := tc.flags.updateURLs(tc.conf)
|
||||
err := tc.flags.updateURLs(context.Background(), tc.conf, &stubImageFetcher{
|
||||
reference: "some/image/path/image-123456",
|
||||
})
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantMeasurementsURL, tc.flags.measurementsURL.String())
|
||||
})
|
||||
|
|
@ -162,14 +164,14 @@ func TestConfigFetchMeasurements(t *testing.T) {
|
|||
signature := "MEUCIFdJ5dH6HDywxQWTUh9Bw77wMrq0mNCUjMQGYP+6QsVmAiEAmazj/L7rFGA4/Gz8y+kI5h5E5cDgc3brihvXBKF6qZA="
|
||||
|
||||
client := newTestClient(func(req *http.Request) *http.Response {
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/projects/constellation-images/global/images/constellation-coreos-1658216163/measurements.yaml" {
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/someImage/measurements.yaml" {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewBufferString(measurements)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/projects/constellation-images/global/images/constellation-coreos-1658216163/measurements.yaml.sig" {
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/someImage/measurements.yaml.sig" {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewBufferString(signature)),
|
||||
|
|
@ -213,12 +215,23 @@ func TestConfigFetchMeasurements(t *testing.T) {
|
|||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||
|
||||
gcpConfig := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.GCP)
|
||||
gcpConfig.Provider.GCP.Image = "projects/constellation-images/global/images/constellation-coreos-1658216163"
|
||||
gcpConfig.Image = "someImage"
|
||||
|
||||
err := fileHandler.WriteYAML(constants.ConfigFilename, gcpConfig, file.OptMkdirAll)
|
||||
require.NoError(err)
|
||||
|
||||
assert.NoError(configFetchMeasurements(cmd, tc.verifier, fileHandler, client))
|
||||
assert.NoError(configFetchMeasurements(cmd, tc.verifier, fileHandler, client, &stubImageFetcher{
|
||||
reference: "someImage",
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubImageFetcher struct {
|
||||
reference string
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context, _ *config.Config) (string, error) {
|
||||
return f.reference, f.fetchReferenceErr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler,
|
|||
}
|
||||
|
||||
var printedAWarning bool
|
||||
if conf.IsDebugImage() {
|
||||
if !conf.IsReleaseImage() {
|
||||
cmd.PrintErrln("Configured image doesn't look like a released production image. Double check image before deploying to production.")
|
||||
printedAWarning = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,8 +388,8 @@ func TestAttestation(t *testing.T) {
|
|||
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, existingIDFile, file.OptNone))
|
||||
|
||||
cfg := config.Default()
|
||||
cfg.Image = "image"
|
||||
cfg.RemoveProviderExcept(cloudprovider.QEMU)
|
||||
cfg.Provider.QEMU.Image = "some/image/location"
|
||||
cfg.Provider.QEMU.Measurements[0] = measurements.PCRWithAllBytes(0x00)
|
||||
cfg.Provider.QEMU.Measurements[1] = measurements.PCRWithAllBytes(0x11)
|
||||
cfg.Provider.QEMU.Measurements[2] = measurements.PCRWithAllBytes(0x22)
|
||||
|
|
@ -463,13 +463,14 @@ func (s *stubInitServer) Init(ctx context.Context, req *initproto.InitRequest) (
|
|||
func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, csp cloudprovider.Provider) *config.Config {
|
||||
t.Helper()
|
||||
|
||||
conf.Image = "image"
|
||||
|
||||
switch csp {
|
||||
case cloudprovider.Azure:
|
||||
conf.Provider.Azure.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
||||
conf.Provider.Azure.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
||||
conf.Provider.Azure.Location = "test-location"
|
||||
conf.Provider.Azure.UserAssignedIdentity = "test-identity"
|
||||
conf.Provider.Azure.Image = "some/image/location"
|
||||
conf.Provider.Azure.ResourceGroup = "test-resource-group"
|
||||
conf.Provider.Azure.AppClientID = "01234567-0123-0123-0123-0123456789ab"
|
||||
conf.Provider.Azure.ClientSecretValue = "test-client-secret"
|
||||
|
|
@ -479,14 +480,12 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs
|
|||
case cloudprovider.GCP:
|
||||
conf.Provider.GCP.Region = "test-region"
|
||||
conf.Provider.GCP.Project = "test-project"
|
||||
conf.Provider.GCP.Image = "some/image/location"
|
||||
conf.Provider.GCP.Zone = "test-zone"
|
||||
conf.Provider.GCP.ServiceAccountKeyPath = "test-key-path"
|
||||
conf.Provider.GCP.Measurements[4] = measurements.PCRWithAllBytes(0x44)
|
||||
conf.Provider.GCP.Measurements[9] = measurements.PCRWithAllBytes(0x11)
|
||||
conf.Provider.GCP.Measurements[12] = measurements.PCRWithAllBytes(0xcc)
|
||||
case cloudprovider.QEMU:
|
||||
conf.Provider.QEMU.Image = "some/image/location"
|
||||
conf.Provider.QEMU.Measurements[4] = measurements.PCRWithAllBytes(0x44)
|
||||
conf.Provider.QEMU.Measurements[9] = measurements.PCRWithAllBytes(0x11)
|
||||
conf.Provider.QEMU.Measurements[12] = measurements.PCRWithAllBytes(0xcc)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
@ -26,8 +25,6 @@ import (
|
|||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
|
||||
"github.com/edgelesssys/constellation/v2/internal/license"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/sys/unix"
|
||||
|
|
@ -188,23 +185,9 @@ func prepareConfig(cmd *cobra.Command, fileHandler file.Handler) (*config.Config
|
|||
}
|
||||
}
|
||||
|
||||
// download image to current directory if it doesn't exist
|
||||
const imagePath = "./constellation.raw"
|
||||
if _, err := os.Stat(imagePath); err == nil {
|
||||
cmd.Printf("Using existing image at %s\n\n", imagePath)
|
||||
} else if errors.Is(err, os.ErrNotExist) {
|
||||
cmd.Printf("Downloading image to %s\n", imagePath)
|
||||
if err := installImage(cmd.Context(), cmd.ErrOrStderr(), versions.ConstellationQEMUImageURL, imagePath); err != nil {
|
||||
return nil, fmt.Errorf("downloading image to %s: %w", imagePath, err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("checking if image exists: %w", err)
|
||||
}
|
||||
|
||||
config := config.Default()
|
||||
config.RemoveProviderExcept(cloudprovider.QEMU)
|
||||
config.StateDiskSizeGB = 8
|
||||
config.Provider.QEMU.Image = imagePath
|
||||
|
||||
return config, fileHandler.WriteYAML(constants.ConfigFilename, config, file.OptOverwrite)
|
||||
}
|
||||
|
|
@ -245,51 +228,3 @@ func initializeMiniCluster(cmd *cobra.Command, fileHandler file.Handler, spinner
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// installImage downloads the image from sourceURL to the destination.
|
||||
func installImage(ctx context.Context, errWriter io.Writer, sourceURL, destination string) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("downloading image: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("downloading image: %s", resp.Status)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(destination, os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
bar := progressbar.NewOptions64(
|
||||
resp.ContentLength,
|
||||
progressbar.OptionSetWriter(errWriter),
|
||||
progressbar.OptionShowBytes(true),
|
||||
progressbar.OptionSetPredictTime(true),
|
||||
progressbar.OptionFullWidth(),
|
||||
progressbar.OptionSetTheme(progressbar.Theme{
|
||||
Saucer: "=",
|
||||
SaucerHead: ">",
|
||||
SaucerPadding: " ",
|
||||
BarStart: "[",
|
||||
BarEnd: "]",
|
||||
}),
|
||||
progressbar.OptionClearOnFinish(),
|
||||
progressbar.OptionOnCompletion(func() { fmt.Fprintf(errWriter, "Done.\n\n") }),
|
||||
)
|
||||
defer bar.Close()
|
||||
|
||||
_, err = io.Copy(io.MultiWriter(f, bar), resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue