Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retry logic / Auth Flag Fix / Sync Cleanup #140

Merged
merged 3 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/hauler/cli/store/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image) error {
}

err = cosign.SaveImage(ctx, s, r.Name())
//desc, err := s.AddOCI(ctx, img, r.Name())
// sync with local index
s.CopyAll(ctx, s.OCI, nil)
if err != nil {
return err
}
Expand Down
7 changes: 7 additions & 0 deletions cmd/hauler/cli/store/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func CopyCmd(ctx context.Context, o *CopyOpts, s *store.Layout, targetRef string
Insecure: o.Insecure,
PlainHTTP: o.PlainHTTP,
}

if ropts.Username != "" {
err := cosign.RegistryLogin(ctx, s, components[1], ropts)
if err != nil {
return err
}
}

err := cosign.LoadImage(ctx, s, components[1], ropts)
if err != nil {
Expand Down
6 changes: 0 additions & 6 deletions cmd/hauler/cli/store/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ func (o *SyncOpts) AddFlags(cmd *cobra.Command) {
func SyncCmd(ctx context.Context, o *SyncOpts, s *store.Layout) error {
l := log.FromContext(ctx)

// Start from an empty store (contents are cached elsewhere)
l.Debugf("flushing content store")
if err := s.Flush(ctx); err != nil {
return err
}

// if passed products, check for a remote manifest to retrieve and use.
for _, product := range o.Products {
l.Infof("processing content file for product: '%s'", product)
Expand Down
132 changes: 89 additions & 43 deletions pkg/cosign/cosign.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"context"
"strings"
"encoding/json"
"time"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/pkg/content"
Expand All @@ -24,77 +25,122 @@ import (
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
)

const maxRetries = 3
const retryDelay = time.Second * 5

// VerifyFileSignature verifies the digital signature of a file using Sigstore/Cosign.
func VerifySignature(ctx context.Context, s *store.Layout, keyPath string, ref string) error {
operation := func() error {
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

// Ensure that the cosign binary is installed or download it if needed
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

// Command to verify the signature using Cosign.
cmd := exec.Command(cosignBinaryPath, "verify", "--insecure-ignore-tlog", "--key", keyPath, ref)
cmd := exec.Command(cosignBinaryPath, "verify", "--insecure-ignore-tlog", "--key", keyPath, ref)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error verifying signature: %v, output: %s", err, output)
}

// Run the command and capture its output.
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error verifying signature: %v, output: %s", err, output)
return nil
}

return nil
return RetryOperation(ctx, operation)
}

// SaveImage saves image and any signatures/attestations to the store.
func SaveImage(ctx context.Context, s *store.Layout, ref string) error {
operation := func() error {
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

// Ensure that the cosign binary is installed or download it if needed
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

// Command to save/download an image using Cosign.
cmd := exec.Command(cosignBinaryPath, "save", ref, "--dir", s.Root)
cmd := exec.Command(cosignBinaryPath, "save", ref, "--dir", s.Root)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error adding image to store: %v, output: %s", err, output)
}

// Run the command and capture its output.
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error adding image to store: %v, output: %s", err, output)
return nil
}

return nil
return RetryOperation(ctx, operation)
}

// LoadImage loads store to a remote registry.
func LoadImage(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions) error {
operation := func() error {
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

//Ensure that the cosign binary is installed or download it if needed
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}
cmd := exec.Command(cosignBinaryPath, "load", "--registry", registry, "--dir", s.Root)

// Conditionally add extra registry flags.
if ropts.Insecure {
cmd.Args = append(cmd.Args, "--allow-insecure-registry=true")
}
if ropts.PlainHTTP {
cmd.Args = append(cmd.Args, "--allow-http-registry=true")
}

// Command to upload index to a remote registry using Cosign.
cmd := exec.Command(cosignBinaryPath, "load", "--registry", registry, "--dir", s.Root)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error copying store: %v, output: %s", err, output)
}

// Conditionally add extra registry flags.
if ropts.Insecure {
cmd.Args = append(cmd.Args, "--allow-insecure-registry=true")
return nil
}
if ropts.PlainHTTP {
cmd.Args = append(cmd.Args, "--allow-http-registry=true")

return RetryOperation(ctx, operation)
}

// RegistryLogin - performs cosign login
func RegistryLogin(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions) error {
operation := func() error {
cosignBinaryPath, err := ensureCosignBinary(ctx, s)
if err != nil {
return err
}

cmd := exec.Command(cosignBinaryPath, "login", registry, "-u", ropts.Username, "-p", ropts.Password)

output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error logging into registry: %v, output: %s", err, output)
}

return nil
}

// Run the command and capture its output.
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error adding image to store: %v, output: %s", err, output)
return RetryOperation(ctx, operation)
}

func RetryOperation(ctx context.Context, operation func() error) error {
l := log.FromContext(ctx)
for attempt := 1; attempt <= maxRetries; attempt++ {
err := operation()
if err == nil {
// If the operation succeeds, return nil (no error).
return nil
}

// Log the error for the current attempt.
l.Errorf("Error (attempt %d/%d): %v", attempt, maxRetries, err)

// If this is not the last attempt, wait before retrying.
if attempt < maxRetries {
time.Sleep(retryDelay)
}
}

return nil
// If all attempts fail, return an error.
return fmt.Errorf("operation failed after %d attempts", maxRetries)
}


// ensureCosignBinary checks if the cosign binary exists in the specified directory and installs it if not.
func ensureCosignBinary(ctx context.Context, s *store.Layout) (string, error) {
l := log.FromContext(ctx)
Expand Down
Loading