diff --git a/README.md b/README.md index ae391f5f..cd99f965 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ podman run --rm -it \ volume to make the build artifacts available after the container completes. In this example, a directory named `_build` will be created in the image configuration directory and will persist after EIB finishes. This directory will contain subdirectories storing the respective artifacts of the different builds. +* `-validate` - If specified, the specified image definition and configuration directory will be checked to ensure + the build can proceed, however the image will not actually be built. ## Testing Images diff --git a/cmd/eib/main.go b/cmd/eib/main.go index f4f359c2..0c751a53 100644 --- a/cmd/eib/main.go +++ b/cmd/eib/main.go @@ -6,10 +6,12 @@ import ( "log" "os" "path/filepath" + "strings" "github.com/suse-edge/edge-image-builder/pkg/build" "github.com/suse-edge/edge-image-builder/pkg/combustion" "github.com/suse-edge/edge-image-builder/pkg/image" + "github.com/suse-edge/edge-image-builder/pkg/image/validation" "github.com/suse-edge/edge-image-builder/pkg/kubernetes" audit "github.com/suse-edge/edge-image-builder/pkg/log" "github.com/suse-edge/edge-image-builder/pkg/network" @@ -24,6 +26,7 @@ const ( argConfigFile = "config-file" argConfigDir = "config-dir" argBuildDir = "build-dir" + argValidate = "validate" ) func processArgs() (*image.Context, error) { @@ -31,11 +34,13 @@ func processArgs() (*image.Context, error) { configFile string configDir string rootBuildDir string + validate bool ) flag.StringVar(&configFile, argConfigFile, "", "name of the image configuration file") flag.StringVar(&configDir, argConfigDir, "", "full path to the image configuration directory") flag.StringVar(&rootBuildDir, argBuildDir, "", "full path to the directory to store build artifacts") + flag.BoolVar(&validate, argValidate, false, "if specified, the image definition will be validated but not built") flag.Parse() imageDefinition, err := parseImageDefinition(configFile, configDir) @@ -66,6 +71,37 @@ func processArgs() (*image.Context, error) { KubernetesArtefactDownloader: kubernetes.ArtefactDownloader{}, } + failedValidations := validation.ValidateDefinition(ctx) + if len(failedValidations) > 0 { + audit.Audit("Image definition validation found the following errors:") + + failuresByComponent := map[string][]validation.FailedValidation{} + logMessageBuilder := strings.Builder{} + + for _, fv := range failedValidations { + failuresByComponent[fv.Component] = append(failuresByComponent[fv.Component], fv) + + logMessageBuilder.WriteString(fv.UserMessage) + if fv.Error != nil { + logMessageBuilder.WriteString(fv.Error.Error()) + } + } + + for componentName, failures := range failuresByComponent { + audit.Audit(fmt.Sprintf(" %s", componentName)) + for _, cf := range failures { + audit.Audit(fmt.Sprintf(" %s", cf.UserMessage)) + } + } + + zap.S().Fatalf(logMessageBuilder.String()) + } + + if validate { + audit.Audit("The specified image definition is valid.") + os.Exit(0) + } + if !combustion.SkipRPMComponent(ctx) { p, err := podman.New(buildDir) if err != nil { @@ -109,11 +145,6 @@ func parseImageDefinition(configFile string, configDir string) (*image.Definitio return nil, fmt.Errorf("error parsing definition file \"%s\": %w", configFile, err) } - err = image.ValidateDefinition(imageDefinition) - if err != nil { - return nil, fmt.Errorf("error validating definition file: %w", err) - } - return imageDefinition, nil } diff --git a/pkg/image/validation/image.go b/pkg/image/validation/image.go index a0b9328e..17073423 100644 --- a/pkg/image/validation/image.go +++ b/pkg/image/validation/image.go @@ -11,7 +11,7 @@ import ( ) const ( - imageComponent = "image" + imageComponent = "Image" ) func validateImage(ctx *image.Context) []FailedValidation {