diff --git a/cmd/composectl/cmd/check.go b/cmd/composectl/cmd/check.go index 16b41ae..b63eefa 100644 --- a/cmd/composectl/cmd/check.go +++ b/cmd/composectl/cmd/check.go @@ -13,7 +13,6 @@ import ( v1 "github.com/foundriesio/composeapp/pkg/compose/v1" "github.com/opencontainers/go-digest" "github.com/spf13/cobra" - "io/fs" "os" "path" ) @@ -50,11 +49,9 @@ type ( } appInstallCheckResult struct { - AppName string `json:"app_name"` - MissingImages []string `json:"missing_images"` - MissingComposeFiles []string `json:"missing_compose_files"` - InvalidComposeFiles []string `json:"invalid_compose_files"` - ErrorComposeFiles []string `json:"error_compose_files"` + AppName string `json:"app_name"` + MissingImages []string `json:"missing_images"` + BundleErrors compose.AppBundleErrs `json:"bundle_errors"` } InstallCheckResult map[string]*appInstallCheckResult @@ -127,25 +124,20 @@ func checkAppsCmd(cmd *cobra.Command, args []string, opts *checkOptions) { cr.print() if opts.CheckInstall { for appRef, r := range ir { - if len(r.InvalidComposeFiles) > 0 || len(r.MissingComposeFiles) > 0 || len(r.MissingImages) > 0 || len(r.ErrorComposeFiles) > 0 { + if len(r.MissingImages) > 0 || len(r.BundleErrors) > 0 { fmt.Printf("%s is not installed (%s)\n", r.AppName, appRef) - for _, issue := range []struct { - issueType string - issueValues []string - }{ - {"missing images", r.MissingImages}, - {"missing compose files", r.MissingComposeFiles}, - {"invalid compose files", r.InvalidComposeFiles}, - {"error compose files", r.ErrorComposeFiles}, - } { - if len(issue.issueValues) == 0 { - continue - } - fmt.Printf("\t%s:\n", issue.issueType) - for _, val := range issue.issueValues { + if len(r.MissingImages) > 0 { + fmt.Println("\tmissing images:") + for _, val := range r.MissingImages { fmt.Println("\t\t" + val) } } + if len(r.BundleErrors) > 0 { + fmt.Println("\tapp bundle errors:") + for f, e := range r.BundleErrors { + fmt.Printf("\t\t%s:\t%s\n", f, e) + } + } } } } @@ -313,30 +305,10 @@ func checkIfInstalled(ctx context.Context, appRefs []string, srcStorePath string if err != nil { return nil, err } - var missingComposeFiles []string - var invalidComposeFiles []string - var errComposeFiles []string - for filePath, checkErr := range errMap { - switch checkErr.(type) { - case *compose.ErrBlobDigestMismatch, *compose.ErrBlobSizeMismatch, *compose.ErrBlobSizeLimitExceed: - { - invalidComposeFiles = append(invalidComposeFiles, filePath) - } - case *fs.PathError: - { - missingComposeFiles = append(missingComposeFiles, filePath) - } - default: - errComposeFiles = append(errComposeFiles, fmt.Sprintf("%s: %s", filePath, checkErr.Error())) - } - } - checkResult[appRef] = &appInstallCheckResult{ - AppName: app.Name(), - MissingImages: missingImages, - InvalidComposeFiles: invalidComposeFiles, - MissingComposeFiles: missingComposeFiles, - ErrorComposeFiles: errComposeFiles, + AppName: app.Name(), + MissingImages: missingImages, + BundleErrors: errMap, } } return checkResult, nil diff --git a/cmd/composectl/cmd/ps.go b/cmd/composectl/cmd/ps.go index b13a323..d09e2f0 100644 --- a/cmd/composectl/cmd/ps.go +++ b/cmd/composectl/cmd/ps.go @@ -28,17 +28,18 @@ type ( Health string `json:"health,omitempty"` } App struct { - URI string `json:"uri"` - Name string `json:"name"` - State string `json:"state"` - Services []*Service `json:"services"` - InStore bool `json:"in_store"` + URI string `json:"uri"` + Name string `json:"name"` + State string `json:"state"` + Services []*Service `json:"services"` + InStore bool `json:"in_store"` + BundleErrors compose.AppBundleErrs `json:"bundle_errors,omitempty"` } ServiceStatus struct { URI string `json:"uri"` ID string `json:"id"` CfgHash string `json:"cfg-hash"` - State string `json:"state"` + State string `json:"statAe"` Status string `json:"status"` } AppStatus []ServiceStatus @@ -171,22 +172,26 @@ func getAppsStatus(ctx context.Context, appRefs []string, runningApps map[string appState = "not running" } } + + var bundleErrors compose.AppBundleErrs if appState == "running" { errMap, err := app.CheckComposeInstallation(ctx, storeBlobProvider, path.Join(config.ComposeRoot, app.Name())) if err == nil { if len(errMap) > 0 { appState = "running invalid bundle" + bundleErrors = errMap } } else { fmt.Printf("failed to check whether app bundle is installed") } } appStatuses[appRef] = &App{ - URI: appRef, - Name: app.Name(), - State: appState, - Services: appServices, - InStore: true, + URI: appRef, + Name: app.Name(), + State: appState, + Services: appServices, + InStore: true, + BundleErrors: bundleErrors, } } diff --git a/pkg/compose/app.go b/pkg/compose/app.go index ef338c1..44bd1e1 100644 --- a/pkg/compose/app.go +++ b/pkg/compose/app.go @@ -20,15 +20,16 @@ type ( Digest digest.Digest } - AppTree TreeNode - App interface { + AppBundleErrs map[string]string + AppTree TreeNode + App interface { Name() string Ref() *AppRef HasLayersMeta(arch string) bool GetBlobRuntimeSize(desc *ocispec.Descriptor, arch string, blockSize int64) int64 GetComposeRoot() *TreeNode GetCompose(ctx context.Context, provider BlobProvider) (*composetypes.Project, error) - CheckComposeInstallation(ctx context.Context, provider BlobProvider, installationRootDir string) (map[string]error, error) + CheckComposeInstallation(ctx context.Context, provider BlobProvider, installationRootDir string) (AppBundleErrs, error) } AppLoader interface { LoadAppTree(context.Context, BlobProvider, platforms.MatchComparer, string) (App, *AppTree, error) diff --git a/pkg/compose/v1/app.go b/pkg/compose/v1/app.go index 8fc2d40..61efbfb 100644 --- a/pkg/compose/v1/app.go +++ b/pkg/compose/v1/app.go @@ -246,16 +246,16 @@ func (a *appCtx) GetLayersMetadataDescriptor() (*ocispec.Descriptor, error) { return &desc, nil } -func (a *appCtx) CheckComposeInstallation(ctx context.Context, provider compose.BlobProvider, installationRootDir string) (map[string]error, error) { +func (a *appCtx) CheckComposeInstallation(ctx context.Context, provider compose.BlobProvider, installationRootDir string) (bundleErrs compose.AppBundleErrs, err error) { appIndex, err := a.getAppBundleIndex(ctx, provider) if err != nil && err != ErrAppIndexNotFound { - return nil, err + return } - errMap := map[string]error{} + bundleErrMap := compose.AppBundleErrs{} for filePath, fileDigest := range appIndex { f, err := os.Open(path.Join(installationRootDir, filePath)) if os.IsNotExist(err) { - errMap[filePath] = err + bundleErrMap[filePath] = err.Error() continue } r, err := compose.NewSecureReadCloser(f, compose.WithExpectedDigest(fileDigest), compose.WithReadLimit(AppBundleFileMaxSize)) @@ -263,10 +263,13 @@ func (a *appCtx) CheckComposeInstallation(ctx context.Context, provider compose. return nil, err } if _, err := io.ReadAll(r); err != nil { - errMap[filePath] = err + bundleErrMap[filePath] = err.Error() } } - return errMap, nil + if len(bundleErrMap) > 0 { + bundleErrs = bundleErrMap + } + return } func (a *appCtx) getAppBundleIndex(ctx context.Context, blobProvider compose.BlobProvider) (map[string]digest.Digest, error) {