Skip to content

Commit

Permalink
More changes after review and testing
Browse files Browse the repository at this point in the history
  • Loading branch information
banjoh committed Sep 22, 2023
1 parent a9d152c commit 9ed6c4c
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 8 deletions.
14 changes: 14 additions & 0 deletions cmd/preflight/cli/oci_fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,26 @@ package cli

import (
"fmt"
"strings"

"github.com/replicatedhq/troubleshoot/pkg/logger"
"github.com/replicatedhq/troubleshoot/pkg/oci"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func OciFetchCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "oci-fetch [URI]",
Args: cobra.MinimumNArgs(1),
Short: "Fetch a preflight from an OCI registry and print it to standard out",
PreRun: func(cmd *cobra.Command, args []string) {
v := viper.GetViper()
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
v.BindPFlags(cmd.Flags())

logger.SetupLogger(v)
},
RunE: func(cmd *cobra.Command, args []string) error {
uri := args[0]
data, err := oci.PullPreflightFromOCI(uri)
Expand All @@ -22,5 +32,9 @@ func OciFetchCmd() *cobra.Command {
return nil
},
}

// Initialize klog flags
logger.InitKlogFlags(cmd)

return cmd
}
2 changes: 1 addition & 1 deletion cmd/preflight/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ that a cluster meets the requirements to run an application.`,
}

err = preflight.RunPreflights(v.GetBool("interactive"), v.GetString("output"), v.GetString("format"), args)
if v.GetBool("debug") || v.IsSet("v") {
if !v.GetBool("dry-run") && (v.GetBool("debug") || v.IsSet("v")) {
fmt.Printf("\n%s", traces.GetExporterInstance().GetSummary())
}

Expand Down
4 changes: 2 additions & 2 deletions internal/specs/specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func LoadFromCLIArgs(ctx context.Context, client kubernetes.Interface, args []st

if u.Scheme == "oci" {
// TODO: We need to also pull support-bundle images from OCI
content, err := oci.PullPreflightFromOCI(v)
content, err := oci.PullSpecsFromOCI(ctx, v)
if err != nil {
if err == oci.ErrNoRelease {
return nil, types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, errors.Errorf("no release found for %s.\nCheck the oci:// uri for errors or contact the application vendor for support.", v))
Expand All @@ -143,7 +143,7 @@ func LoadFromCLIArgs(ctx context.Context, client kubernetes.Interface, args []st
return nil, types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, err)
}

rawSpecs = append(rawSpecs, string(content))
rawSpecs = append(rawSpecs, content...)
} else {
if !util.IsURL(v) {
return nil, types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, fmt.Errorf("%s is not a URL and was not found (err %s)", v, err))
Expand Down
51 changes: 46 additions & 5 deletions pkg/oci/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/pkg/errors"
"github.com/replicatedhq/troubleshoot/internal/util"
"github.com/replicatedhq/troubleshoot/pkg/version"
"k8s.io/klog/v2"
"oras.land/oras-go/pkg/auth"
dockerauth "oras.land/oras-go/pkg/auth/docker"
"oras.land/oras-go/pkg/content"
Expand All @@ -27,14 +28,52 @@ var (
)

func PullPreflightFromOCI(uri string) ([]byte, error) {
return pullFromOCI(uri, "replicated.preflight.spec", "replicated-preflight")
return pullFromOCI(context.Background(), uri, "replicated.preflight.spec", "replicated-preflight")
}

func PullSupportBundleFromOCI(uri string) ([]byte, error) {
return pullFromOCI(uri, "replicated.supportbundle.spec", "replicated-supportbundle")
return pullFromOCI(context.Background(), uri, "replicated.supportbundle.spec", "replicated-supportbundle")
}

func pullFromOCI(uri string, mediaType string, imageName string) ([]byte, error) {
// PullSpecsFromOCI pulls both the preflight and support bundle specs from the given URI
//
// The URI is expected to be the same as the one used to install your KOTS application
// Example oci://registry.replicated.com/thanos-reloaded/unstable will endup pulling
// preflights from "registry.replicated.com/thanos-reloaded/unstable/replicated-preflight:latest"
// and support bundles from "registry.replicated.com/thanos-reloaded/unstable/replicated-supportbundle:latest"
// Both images have their own media types created when publishing KOTS OCI image.
// NOTE: This only works with replicated registries for now and for KOTS applications only
func PullSpecsFromOCI(ctx context.Context, uri string) ([]string, error) {
// TODOs (API is opinionated, but we should be able to support these):
// - Pulling from generic OCI registries (not just replicated)
// - Pulling from registries that require authentication
// - Passing in a complete URI including tags and image name

rawSpecs := []string{}

// First try to pull the preflight spec
rawPreflight, err := pullFromOCI(ctx, uri, "replicated.preflight.spec", "replicated-preflight")
if err != nil {
// Ignore "not found" error and continue fetching the support bundle spec
if !errors.Is(err, ErrNoRelease) {
return nil, err
}
} else {
rawSpecs = append(rawSpecs, string(rawPreflight))
}

// Then try to pull the support bundle spec
rawSupportBundle, err := pullFromOCI(ctx, uri, "replicated.supportbundle.spec", "replicated-supportbundle")
// If we had found a preflight spec, do not return an error
if err != nil && len(rawSpecs) == 0 {
return nil, err
}
rawSpecs = append(rawSpecs, string(rawSupportBundle))

return rawSpecs, nil
}

func pullFromOCI(ctx context.Context, uri string, mediaType string, imageName string) ([]byte, error) {
// helm credentials
helmCredentialsFile := filepath.Join(util.HomeDir(), HelmCredentialsFileBasename)
dockerauthClient, err := dockerauth.NewClientWithDockerFallback(helmCredentialsFile)
Expand Down Expand Up @@ -77,7 +116,9 @@ func pullFromOCI(uri string, mediaType string, imageName string) ([]byte, error)
return nil, errors.Wrap(err, "failed to parse reference")
}

manifest, err := oras.Copy(context.TODO(), registryStore, parsedRef.String(), memoryStore, "",
klog.V(1).Infof("Pulling spec from %q OCI uri", parsedRef.String())

manifest, err := oras.Copy(ctx, registryStore, parsedRef.String(), memoryStore, "",
oras.WithPullEmptyNameAllowed(),
oras.WithAllowedMediaTypes(allowedMediaTypes),
oras.WithLayerDescriptors(func(l []ocispec.Descriptor) {
Expand All @@ -94,7 +135,7 @@ func pullFromOCI(uri string, mediaType string, imageName string) ([]byte, error)
descriptors = append(descriptors, manifest)
descriptors = append(descriptors, layers...)

// expect 1 descriptor
// expect 2 descriptors
if len(descriptors) != 2 {
return nil, fmt.Errorf("expected 2 descriptor, got %d", len(descriptors))
}
Expand Down

0 comments on commit 9ed6c4c

Please sign in to comment.