updated/fixed hauler directory (#354)

* added env variables for haulerDir/tempDir
* updated hauler directory for the install script
* cleanup/fixes for install script
* updated variables based on feedback
* revert "updated variables based on feedback"
  * reverts commit 54f7a4d695
* minor restructure to root flags
* updated logic to include haulerdir flag
* cleaned up/formatted new logic
* more cleanup and formatting
This commit is contained in:
Zack Brady
2024-11-14 21:37:25 -05:00
committed by GitHub
parent 38c7d1b17a
commit 1b77295438
26 changed files with 256 additions and 184 deletions

View File

@@ -1,22 +1,33 @@
package cli package cli
import ( import (
"context"
"embed"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"hauler.dev/go/hauler/internal/flags" "hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/pkg/consts"
"hauler.dev/go/hauler/pkg/cosign"
"hauler.dev/go/hauler/pkg/log" "hauler.dev/go/hauler/pkg/log"
) )
var ro = &flags.CliRootOpts{} func New(ctx context.Context, binaries embed.FS, ro *flags.CliRootOpts) *cobra.Command {
func New() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "hauler", Use: "hauler",
Short: "Airgap Swiss Army Knife", Short: "Airgap Swiss Army Knife",
Example: " View the Docs: https://docs.hauler.dev\n Environment Variables: " + consts.HaulerDir + " | " + consts.HaulerTempDir,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
l := log.FromContext(cmd.Context()) l := log.FromContext(ctx)
l.SetLevel(ro.LogLevel) l.SetLevel(ro.LogLevel)
l.Debugf("running cli command [%s]", cmd.CommandPath()) l.Debugf("running cli command [%s]", cmd.CommandPath())
// ensure cosign binary is available
if err := cosign.EnsureBinaryExists(ctx, binaries, ro); err != nil {
l.Errorf("cosign binary missing: %v", err)
return err
}
return nil return nil
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -24,14 +35,12 @@ func New() *cobra.Command {
}, },
} }
pf := cmd.PersistentFlags() flags.AddRootFlags(cmd, ro)
pf.StringVarP(&ro.LogLevel, "log-level", "l", "info", "")
// Add subcommands addLogin(cmd, ro)
addLogin(cmd) addStore(cmd, ro)
addStore(cmd) addVersion(cmd, ro)
addVersion(cmd) addCompletion(cmd, ro)
addCompletion(cmd)
return cmd return cmd
} }

View File

@@ -5,25 +5,26 @@ import (
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"hauler.dev/go/hauler/internal/flags"
) )
func addCompletion(parent *cobra.Command) { func addCompletion(parent *cobra.Command, ro *flags.CliRootOpts) {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "completion", Use: "completion",
Short: "Generate auto-completion scripts for various shells", Short: "Generate auto-completion scripts for various shells",
} }
cmd.AddCommand( cmd.AddCommand(
addCompletionZsh(), addCompletionZsh(ro),
addCompletionBash(), addCompletionBash(ro),
addCompletionFish(), addCompletionFish(ro),
addCompletionPowershell(), addCompletionPowershell(ro),
) )
parent.AddCommand(cmd) parent.AddCommand(cmd)
} }
func addCompletionZsh() *cobra.Command { func addCompletionZsh(ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "zsh", Use: "zsh",
Short: "Generates auto-completion scripts for zsh", Short: "Generates auto-completion scripts for zsh",
@@ -52,7 +53,7 @@ func addCompletionZsh() *cobra.Command {
return cmd return cmd
} }
func addCompletionBash() *cobra.Command { func addCompletionBash(ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "bash", Use: "bash",
Short: "Generates auto-completion scripts for bash", Short: "Generates auto-completion scripts for bash",
@@ -71,7 +72,7 @@ func addCompletionBash() *cobra.Command {
return cmd return cmd
} }
func addCompletionFish() *cobra.Command { func addCompletionFish(ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "fish", Use: "fish",
Short: "Generates auto-completion scripts for fish", Short: "Generates auto-completion scripts for fish",
@@ -87,7 +88,7 @@ func addCompletionFish() *cobra.Command {
return cmd return cmd
} }
func addCompletionPowershell() *cobra.Command { func addCompletionPowershell(ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "powershell", Use: "powershell",
Short: "Generates auto-completion scripts for powershell", Short: "Generates auto-completion scripts for powershell",

View File

@@ -14,7 +14,7 @@ import (
"hauler.dev/go/hauler/pkg/cosign" "hauler.dev/go/hauler/pkg/cosign"
) )
func addLogin(parent *cobra.Command) { func addLogin(parent *cobra.Command, ro *flags.CliRootOpts) {
o := &flags.LoginOpts{} o := &flags.LoginOpts{}
cmd := &cobra.Command{ cmd := &cobra.Command{
@@ -39,7 +39,7 @@ func addLogin(parent *cobra.Command) {
return fmt.Errorf("username and password required") return fmt.Errorf("username and password required")
} }
return login(ctx, o, arg[0]) return login(ctx, o, arg[0], ro)
}, },
} }
o.AddFlags(cmd) o.AddFlags(cmd)
@@ -47,13 +47,13 @@ func addLogin(parent *cobra.Command) {
parent.AddCommand(cmd) parent.AddCommand(cmd)
} }
func login(ctx context.Context, o *flags.LoginOpts, registry string) error { func login(ctx context.Context, o *flags.LoginOpts, registry string, ro *flags.CliRootOpts) error {
ropts := content.RegistryOptions{ ropts := content.RegistryOptions{
Username: o.Username, Username: o.Username,
Password: o.Password, Password: o.Password,
} }
err := cosign.RegistryLogin(ctx, nil, registry, ropts) err := cosign.RegistryLogin(ctx, nil, registry, ropts, ro)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -10,9 +10,9 @@ import (
"hauler.dev/go/hauler/internal/flags" "hauler.dev/go/hauler/internal/flags"
) )
var rootStoreOpts = &flags.StoreRootOpts{} func addStore(parent *cobra.Command, ro *flags.CliRootOpts) {
rso := &flags.StoreRootOpts{}
func addStore(parent *cobra.Command) {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "store", Use: "store",
Aliases: []string{"s"}, Aliases: []string{"s"},
@@ -21,24 +21,24 @@ func addStore(parent *cobra.Command) {
return cmd.Help() return cmd.Help()
}, },
} }
rootStoreOpts.AddFlags(cmd) rso.AddFlags(cmd)
cmd.AddCommand( cmd.AddCommand(
addStoreSync(), addStoreSync(rso, ro),
addStoreExtract(), addStoreExtract(rso, ro),
addStoreLoad(), addStoreLoad(rso, ro),
addStoreSave(), addStoreSave(rso, ro),
addStoreServe(), addStoreServe(rso, ro),
addStoreInfo(), addStoreInfo(rso, ro),
addStoreCopy(), addStoreCopy(rso, ro),
addStoreAdd(), addStoreAdd(rso, ro),
) )
parent.AddCommand(cmd) parent.AddCommand(cmd)
} }
func addStoreExtract() *cobra.Command { func addStoreExtract(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.ExtractOpts{StoreRootOpts: rootStoreOpts} o := &flags.ExtractOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "extract", Use: "extract",
@@ -61,8 +61,8 @@ func addStoreExtract() *cobra.Command {
return cmd return cmd
} }
func addStoreSync() *cobra.Command { func addStoreSync(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.SyncOpts{StoreRootOpts: rootStoreOpts} o := &flags.SyncOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "sync", Use: "sync",
@@ -75,7 +75,7 @@ func addStoreSync() *cobra.Command {
return err return err
} }
return store.SyncCmd(ctx, o, s) return store.SyncCmd(ctx, o, s, ro)
}, },
} }
o.AddFlags(cmd) o.AddFlags(cmd)
@@ -83,8 +83,8 @@ func addStoreSync() *cobra.Command {
return cmd return cmd
} }
func addStoreLoad() *cobra.Command { func addStoreLoad(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.LoadOpts{StoreRootOpts: rootStoreOpts} o := &flags.LoadOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "load", Use: "load",
@@ -107,7 +107,7 @@ func addStoreLoad() *cobra.Command {
return cmd return cmd
} }
func addStoreServe() *cobra.Command { func addStoreServe(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "serve", Use: "serve",
Short: "Serve the content store via an OCI Compliant Registry or Fileserver", Short: "Serve the content store via an OCI Compliant Registry or Fileserver",
@@ -116,16 +116,17 @@ func addStoreServe() *cobra.Command {
}, },
} }
cmd.AddCommand( cmd.AddCommand(
addStoreServeRegistry(), addStoreServeRegistry(rso, ro),
addStoreServeFiles(), addStoreServeFiles(rso, ro),
) )
return cmd return cmd
} }
// RegistryCmd serves the registry // RegistryCmd serves the registry
func addStoreServeRegistry() *cobra.Command { func addStoreServeRegistry(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.ServeRegistryOpts{StoreRootOpts: rootStoreOpts} o := &flags.ServeRegistryOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "registry", Use: "registry",
Short: "Serve the OCI Compliant Registry", Short: "Serve the OCI Compliant Registry",
@@ -137,7 +138,7 @@ func addStoreServeRegistry() *cobra.Command {
return err return err
} }
return store.ServeRegistryCmd(ctx, o, s) return store.ServeRegistryCmd(ctx, o, s, ro)
}, },
} }
@@ -147,8 +148,9 @@ func addStoreServeRegistry() *cobra.Command {
} }
// FileServerCmd serves the file server // FileServerCmd serves the file server
func addStoreServeFiles() *cobra.Command { func addStoreServeFiles(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.ServeFilesOpts{StoreRootOpts: rootStoreOpts} o := &flags.ServeFilesOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "fileserver", Use: "fileserver",
Short: "Serve the Fileserver", Short: "Serve the Fileserver",
@@ -160,7 +162,7 @@ func addStoreServeFiles() *cobra.Command {
return err return err
} }
return store.ServeFilesCmd(ctx, o, s) return store.ServeFilesCmd(ctx, o, s, ro)
}, },
} }
@@ -169,8 +171,8 @@ func addStoreServeFiles() *cobra.Command {
return cmd return cmd
} }
func addStoreSave() *cobra.Command { func addStoreSave(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.SaveOpts{StoreRootOpts: rootStoreOpts} o := &flags.SaveOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "save", Use: "save",
@@ -193,8 +195,8 @@ func addStoreSave() *cobra.Command {
return cmd return cmd
} }
func addStoreInfo() *cobra.Command { func addStoreInfo(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.InfoOpts{StoreRootOpts: rootStoreOpts} o := &flags.InfoOpts{StoreRootOpts: rso}
var allowedValues = []string{"image", "chart", "file", "sigs", "atts", "sbom", "all"} var allowedValues = []string{"image", "chart", "file", "sigs", "atts", "sbom", "all"}
@@ -224,8 +226,8 @@ func addStoreInfo() *cobra.Command {
return cmd return cmd
} }
func addStoreCopy() *cobra.Command { func addStoreCopy(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.CopyOpts{StoreRootOpts: rootStoreOpts} o := &flags.CopyOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "copy", Use: "copy",
@@ -239,7 +241,7 @@ func addStoreCopy() *cobra.Command {
return err return err
} }
return store.CopyCmd(ctx, o, s, args[0]) return store.CopyCmd(ctx, o, s, args[0], ro)
}, },
} }
o.AddFlags(cmd) o.AddFlags(cmd)
@@ -247,7 +249,7 @@ func addStoreCopy() *cobra.Command {
return cmd return cmd
} }
func addStoreAdd() *cobra.Command { func addStoreAdd(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "add", Use: "add",
Short: "Add content to the store", Short: "Add content to the store",
@@ -257,16 +259,16 @@ func addStoreAdd() *cobra.Command {
} }
cmd.AddCommand( cmd.AddCommand(
addStoreAddFile(), addStoreAddFile(rso, ro),
addStoreAddImage(), addStoreAddImage(rso, ro),
addStoreAddChart(), addStoreAddChart(rso, ro),
) )
return cmd return cmd
} }
func addStoreAddFile() *cobra.Command { func addStoreAddFile(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.AddFileOpts{StoreRootOpts: rootStoreOpts} o := &flags.AddFileOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "file", Use: "file",
@@ -296,8 +298,8 @@ hauler store add file https://get.hauler.dev --name hauler-install.sh`,
return cmd return cmd
} }
func addStoreAddImage() *cobra.Command { func addStoreAddImage(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.AddImageOpts{StoreRootOpts: rootStoreOpts} o := &flags.AddImageOpts{StoreRootOpts: rso}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "image", Use: "image",
@@ -325,7 +327,7 @@ hauler store add image rgcrprod.azurecr.us/hauler/rke2-manifest.yaml:v1.28.12-rk
return err return err
} }
return store.AddImageCmd(ctx, o, s, args[0]) return store.AddImageCmd(ctx, o, s, args[0], ro)
}, },
} }
o.AddFlags(cmd) o.AddFlags(cmd)
@@ -333,11 +335,8 @@ hauler store add image rgcrprod.azurecr.us/hauler/rke2-manifest.yaml:v1.28.12-rk
return cmd return cmd
} }
func addStoreAddChart() *cobra.Command { func addStoreAddChart(rso *flags.StoreRootOpts, ro *flags.CliRootOpts) *cobra.Command {
o := &flags.AddChartOpts{ o := &flags.AddChartOpts{StoreRootOpts: rso, ChartOpts: &action.ChartPathOptions{}}
StoreRootOpts: rootStoreOpts,
ChartOpts: &action.ChartPathOptions{},
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "chart", Use: "chart",

View File

@@ -52,8 +52,9 @@ func storeFile(ctx context.Context, s *store.Layout, fi v1alpha1.File) error {
return nil return nil
} }
func AddImageCmd(ctx context.Context, o *flags.AddImageOpts, s *store.Layout, reference string) error { func AddImageCmd(ctx context.Context, o *flags.AddImageOpts, s *store.Layout, reference string, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
cfg := v1alpha1.Image{ cfg := v1alpha1.Image{
Name: reference, Name: reference,
} }
@@ -61,18 +62,19 @@ func AddImageCmd(ctx context.Context, o *flags.AddImageOpts, s *store.Layout, re
// Check if the user provided a key. // Check if the user provided a key.
if o.Key != "" { if o.Key != "" {
// verify signature using the provided key. // verify signature using the provided key.
err := cosign.VerifySignature(ctx, s, o.Key, cfg.Name) err := cosign.VerifySignature(ctx, s, o.Key, cfg.Name, ro)
if err != nil { if err != nil {
return err return err
} }
l.Infof("signature verified for image [%s]", cfg.Name) l.Infof("signature verified for image [%s]", cfg.Name)
} }
return storeImage(ctx, s, cfg, o.Platform) return storeImage(ctx, s, cfg, o.Platform, ro)
} }
func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image, platform string) error { func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image, platform string, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
l.Infof("adding 'image' [%s] to the store", i.Name) l.Infof("adding 'image' [%s] to the store", i.Name)
r, err := name.ParseReference(i.Name) r, err := name.ParseReference(i.Name)
@@ -81,7 +83,7 @@ func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image, platform
return nil return nil
} }
err = cosign.SaveImage(ctx, s, r.Name(), platform) err = cosign.SaveImage(ctx, s, r.Name(), platform, ro)
if err != nil { if err != nil {
l.Warnf("unable to add 'image' [%s] to store. skipping...", r.Name()) l.Warnf("unable to add 'image' [%s] to store. skipping...", r.Name())
return nil return nil
@@ -104,6 +106,7 @@ func AddChartCmd(ctx context.Context, o *flags.AddChartOpts, s *store.Layout, ch
func storeChart(ctx context.Context, s *store.Layout, cfg v1alpha1.Chart, opts *action.ChartPathOptions) error { func storeChart(ctx context.Context, s *store.Layout, cfg v1alpha1.Chart, opts *action.ChartPathOptions) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
l.Infof("adding 'chart' [%s] to the store", cfg.Name) l.Infof("adding 'chart' [%s] to the store", cfg.Name)
// TODO: This shouldn't be necessary // TODO: This shouldn't be necessary

View File

@@ -13,7 +13,7 @@ import (
"hauler.dev/go/hauler/pkg/store" "hauler.dev/go/hauler/pkg/store"
) )
func CopyCmd(ctx context.Context, o *flags.CopyOpts, s *store.Layout, targetRef string) error { func CopyCmd(ctx context.Context, o *flags.CopyOpts, s *store.Layout, targetRef string, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
components := strings.SplitN(targetRef, "://", 2) components := strings.SplitN(targetRef, "://", 2)
@@ -38,13 +38,13 @@ func CopyCmd(ctx context.Context, o *flags.CopyOpts, s *store.Layout, targetRef
} }
if ropts.Username != "" { if ropts.Username != "" {
err := cosign.RegistryLogin(ctx, s, components[1], ropts) err := cosign.RegistryLogin(ctx, s, components[1], ropts, ro)
if err != nil { if err != nil {
return err return err
} }
} }
err := cosign.LoadImages(ctx, s, components[1], ropts) err := cosign.LoadImages(ctx, s, components[1], ropts, ro)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -7,6 +7,7 @@ import (
"github.com/mholt/archiver/v3" "github.com/mholt/archiver/v3"
"hauler.dev/go/hauler/internal/flags" "hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/pkg/consts"
"hauler.dev/go/hauler/pkg/content" "hauler.dev/go/hauler/pkg/content"
"hauler.dev/go/hauler/pkg/log" "hauler.dev/go/hauler/pkg/log"
"hauler.dev/go/hauler/pkg/store" "hauler.dev/go/hauler/pkg/store"
@@ -30,17 +31,25 @@ func LoadCmd(ctx context.Context, o *flags.LoadOpts, archiveRefs ...string) erro
// unarchiveLayoutTo accepts an archived oci layout and extracts the contents to an existing oci layout, preserving the index // unarchiveLayoutTo accepts an archived oci layout and extracts the contents to an existing oci layout, preserving the index
func unarchiveLayoutTo(ctx context.Context, archivePath string, dest string, tempOverride string) error { func unarchiveLayoutTo(ctx context.Context, archivePath string, dest string, tempOverride string) error {
tmpdir, err := os.MkdirTemp(tempOverride, "hauler") l := log.FromContext(ctx)
if tempOverride == "" {
tempOverride = os.Getenv(consts.HaulerTempDir)
}
tempDir, err := os.MkdirTemp(tempOverride, consts.DefaultHaulerTempDirName)
if err != nil { if err != nil {
return err return err
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tempDir)
if err := archiver.Unarchive(archivePath, tmpdir); err != nil { l.Debugf("using temporary directory at %s", tempDir)
if err := archiver.Unarchive(archivePath, tempDir); err != nil {
return err return err
} }
s, err := store.NewLayout(tmpdir) s, err := store.NewLayout(tempDir)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -161,7 +161,7 @@ func writeExportsManifest(ctx context.Context, dir string, platformStr string) e
return err return err
} }
return oci.WriteFile("manifest.json", buf.Bytes(), 0666) return oci.WriteFile(consts.OCIImageManifestFile, buf.Bytes(), 0666)
} }
func (x *exports) describe() tarball.Manifest { func (x *exports) describe() tarball.Manifest {

View File

@@ -17,7 +17,7 @@ import (
"hauler.dev/go/hauler/pkg/store" "hauler.dev/go/hauler/pkg/store"
) )
func ServeRegistryCmd(ctx context.Context, o *flags.ServeRegistryOpts, s *store.Layout) error { func ServeRegistryCmd(ctx context.Context, o *flags.ServeRegistryOpts, s *store.Layout, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
ctx = dcontext.WithVersion(ctx, version.Version) ctx = dcontext.WithVersion(ctx, version.Version)
@@ -27,7 +27,7 @@ func ServeRegistryCmd(ctx context.Context, o *flags.ServeRegistryOpts, s *store.
} }
opts := &flags.CopyOpts{} opts := &flags.CopyOpts{}
if err := CopyCmd(ctx, opts, s, "registry://"+tr.Registry()); err != nil { if err := CopyCmd(ctx, opts, s, "registry://"+tr.Registry(), ro); err != nil {
return err return err
} }
@@ -55,12 +55,12 @@ func ServeRegistryCmd(ctx context.Context, o *flags.ServeRegistryOpts, s *store.
return nil return nil
} }
func ServeFilesCmd(ctx context.Context, o *flags.ServeFilesOpts, s *store.Layout) error { func ServeFilesCmd(ctx context.Context, o *flags.ServeFilesOpts, s *store.Layout, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
ctx = dcontext.WithVersion(ctx, version.Version) ctx = dcontext.WithVersion(ctx, version.Version)
opts := &flags.CopyOpts{} opts := &flags.CopyOpts{}
if err := CopyCmd(ctx, opts, s, "dir://"+o.RootDir); err != nil { if err := CopyCmd(ctx, opts, s, "dir://"+o.RootDir, ro); err != nil {
return err return err
} }

View File

@@ -24,7 +24,7 @@ import (
"hauler.dev/go/hauler/pkg/store" "hauler.dev/go/hauler/pkg/store"
) )
func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout) error { func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
// if passed products, check for a remote manifest to retrieve and use. // if passed products, check for a remote manifest to retrieve and use.
@@ -44,7 +44,7 @@ func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout) error {
img := v1alpha1.Image{ img := v1alpha1.Image{
Name: manifestLoc, Name: manifestLoc,
} }
err := storeImage(ctx, s, img, o.Platform) err := storeImage(ctx, s, img, o.Platform, ro)
if err != nil { if err != nil {
return err return err
} }
@@ -58,7 +58,7 @@ func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout) error {
if err != nil { if err != nil {
return err return err
} }
err = processContent(ctx, fi, o, s) err = processContent(ctx, fi, o, s, ro)
if err != nil { if err != nil {
return err return err
} }
@@ -71,7 +71,7 @@ func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout) error {
if err != nil { if err != nil {
return err return err
} }
err = processContent(ctx, fi, o, s) err = processContent(ctx, fi, o, s, ro)
if err != nil { if err != nil {
return err return err
} }
@@ -80,7 +80,7 @@ func SyncCmd(ctx context.Context, o *flags.SyncOpts, s *store.Layout) error {
return nil return nil
} }
func processContent(ctx context.Context, fi *os.File, o *flags.SyncOpts, s *store.Layout) error { func processContent(ctx context.Context, fi *os.File, o *flags.SyncOpts, s *store.Layout, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
reader := yaml.NewYAMLReader(bufio.NewReader(fi)) reader := yaml.NewYAMLReader(bufio.NewReader(fi))
@@ -169,7 +169,7 @@ func processContent(ctx context.Context, fi *os.File, o *flags.SyncOpts, s *stor
l.Debugf("key for image [%s]", key) l.Debugf("key for image [%s]", key)
// verify signature using the provided key. // verify signature using the provided key.
err := cosign.VerifySignature(ctx, s, key, i.Name) err := cosign.VerifySignature(ctx, s, key, i.Name, ro)
if err != nil { if err != nil {
l.Errorf("signature verification failed for image [%s]. ** hauler will skip adding this image to the store **:\n%v", i.Name, err) l.Errorf("signature verification failed for image [%s]. ** hauler will skip adding this image to the store **:\n%v", i.Name, err)
continue continue
@@ -188,7 +188,7 @@ func processContent(ctx context.Context, fi *os.File, o *flags.SyncOpts, s *stor
platform = i.Platform platform = i.Platform
} }
err = storeImage(ctx, s, i, platform) err = storeImage(ctx, s, i, platform, ro)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -5,10 +5,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/internal/version" "hauler.dev/go/hauler/internal/version"
) )
func addVersion(parent *cobra.Command) { func addVersion(parent *cobra.Command, ro *flags.CliRootOpts) {
var json bool var json bool
cmd := &cobra.Command{ cmd := &cobra.Command{

View File

@@ -6,7 +6,7 @@ import (
"os" "os"
"hauler.dev/go/hauler/cmd/hauler/cli" "hauler.dev/go/hauler/cmd/hauler/cli"
"hauler.dev/go/hauler/pkg/cosign" "hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/pkg/log" "hauler.dev/go/hauler/pkg/log"
) )
@@ -20,13 +20,8 @@ func main() {
logger := log.NewLogger(os.Stdout) logger := log.NewLogger(os.Stdout)
ctx = logger.WithContext(ctx) ctx = logger.WithContext(ctx)
// ensure cosign binary is available // pass the embedded binaries to the cli package
if err := cosign.EnsureBinaryExists(ctx, binaries); err != nil { if err := cli.New(ctx, binaries, &flags.CliRootOpts{}).ExecuteContext(ctx); err != nil {
logger.Errorf("%v", err)
os.Exit(1)
}
if err := cli.New().ExecuteContext(ctx); err != nil {
logger.Errorf("%v", err) logger.Errorf("%v", err)
cancel() cancel()
os.Exit(1) os.Exit(1)

View File

@@ -17,6 +17,10 @@
# - curl -sfL https://get.hauler.dev | HAULER_INSTALL_DIR=/usr/local/bin bash # - curl -sfL https://get.hauler.dev | HAULER_INSTALL_DIR=/usr/local/bin bash
# - HAULER_INSTALL_DIR=/usr/local/bin ./install.sh # - HAULER_INSTALL_DIR=/usr/local/bin ./install.sh
# #
# Set Hauler Directory
# - curl -sfL https://get.hauler.dev | HAULER_DIR=$HOME/.hauler bash
# - HAULER_DIR=$HOME/.hauler ./install.sh
#
# Debug Usage: # Debug Usage:
# - curl -sfL https://get.hauler.dev | HAULER_DEBUG=true bash # - curl -sfL https://get.hauler.dev | HAULER_DEBUG=true bash
# - HAULER_DEBUG=true ./install.sh # - HAULER_DEBUG=true ./install.sh
@@ -65,7 +69,7 @@ done
# set install directory from argument or environment variable # set install directory from argument or environment variable
HAULER_INSTALL_DIR=${HAULER_INSTALL_DIR:-/usr/local/bin} HAULER_INSTALL_DIR=${HAULER_INSTALL_DIR:-/usr/local/bin}
# ensure install directory exists # ensure install directory exists and/or create it
if [ ! -d "${HAULER_INSTALL_DIR}" ]; then if [ ! -d "${HAULER_INSTALL_DIR}" ]; then
mkdir -p "${HAULER_INSTALL_DIR}" || fatal "Failed to Create Install Directory: ${HAULER_INSTALL_DIR}" mkdir -p "${HAULER_INSTALL_DIR}" || fatal "Failed to Create Install Directory: ${HAULER_INSTALL_DIR}"
fi fi
@@ -82,8 +86,8 @@ if [ "${HAULER_UNINSTALL}" = "true" ]; then
# remove the hauler binary # remove the hauler binary
rm -rf "${HAULER_INSTALL_DIR}/hauler" || fatal "Failed to Remove Hauler from ${HAULER_INSTALL_DIR}" rm -rf "${HAULER_INSTALL_DIR}/hauler" || fatal "Failed to Remove Hauler from ${HAULER_INSTALL_DIR}"
# remove the working directory # remove the hauler directory
rm -rf "$HOME/.hauler" || fatal "Failed to Remove Hauler Directory: $HOME/.hauler" rm -rf "${HAULER_DIR}" || fatal "Failed to Remove Hauler Directory: ${HAULER_DIR}"
info "Successfully Uninstalled Hauler" && echo info "Successfully Uninstalled Hauler" && echo
exit 0 exit 0
@@ -110,7 +114,7 @@ case $PLATFORM in
PLATFORM="darwin" PLATFORM="darwin"
;; ;;
*) *)
fatal "Unsupported Platform: $PLATFORM" fatal "Unsupported Platform: ${PLATFORM}"
;; ;;
esac esac
@@ -124,29 +128,33 @@ case $ARCH in
ARCH="arm64" ARCH="arm64"
;; ;;
*) *)
fatal "Unsupported Architecture: $ARCH" fatal "Unsupported Architecture: ${ARCH}"
;; ;;
esac esac
# set hauler directory from argument or environment variable
HAULER_DIR=${HAULER_DIR:-$HOME/.hauler}
# start hauler installation # start hauler installation
info "Starting Installation..." info "Starting Installation..."
# display the version, platform, and architecture # display the version, platform, and architecture
verbose "- Version: v${HAULER_VERSION}" verbose "- Version: v${HAULER_VERSION}"
verbose "- Platform: $PLATFORM" verbose "- Platform: ${PLATFORM}"
verbose "- Architecture: $ARCH" verbose "- Architecture: ${ARCH}"
verbose "- Install Directory: ${HAULER_INSTALL_DIR}" verbose "- Install Directory: ${HAULER_INSTALL_DIR}"
verbose "- Hauler Directory: ${HAULER_DIR}"
# check working directory and/or create it # ensure hauler directory exists and/or create it
if [ ! -d "$HOME/.hauler" ]; then if [ ! -d "${HAULER_DIR}" ]; then
mkdir -p "$HOME/.hauler" || fatal "Failed to Create Directory: $HOME/.hauler" mkdir -p "${HAULER_DIR}" || fatal "Failed to Create Hauler Directory: ${HAULER_DIR}"
fi fi
# update permissions of working directory # ensure hauler directory is writable (by user or root privileges)
chmod -R 777 "$HOME/.hauler" || fatal "Failed to Update Permissions of Directory: $HOME/.hauler" chmod -R 777 "${HAULER_DIR}" || fatal "Failed to Update Permissions of Hauler Directory: ${HAULER_DIR}"
# change to working directory # change to hauler directory
cd "$HOME/.hauler" || fatal "Failed to Change Directory: $HOME/.hauler" cd "${HAULER_DIR}" || fatal "Failed to Change Directory to Hauler Directory: ${HAULER_DIR}"
# start hauler artifacts download # start hauler artifacts download
info "Starting Download..." info "Starting Download..."

View File

@@ -1,5 +1,15 @@
package flags package flags
import "github.com/spf13/cobra"
type CliRootOpts struct { type CliRootOpts struct {
LogLevel string LogLevel string
HaulerDir string
}
func AddRootFlags(cmd *cobra.Command, ro *CliRootOpts) {
pf := cmd.PersistentFlags()
pf.StringVarP(&ro.LogLevel, "log-level", "l", "info", "Set the logging level (i.e. info, debug, warn)")
pf.StringVarP(&ro.HaulerDir, "haulerdir", "d", "", "Set the location of the hauler directory (default $HOME/.hauler)")
} }

View File

@@ -1,6 +1,9 @@
package flags package flags
import "github.com/spf13/cobra" import (
"github.com/spf13/cobra"
"hauler.dev/go/hauler/pkg/consts"
)
type SaveOpts struct { type SaveOpts struct {
*StoreRootOpts *StoreRootOpts
@@ -11,6 +14,6 @@ type SaveOpts struct {
func (o *SaveOpts) AddFlags(cmd *cobra.Command) { func (o *SaveOpts) AddFlags(cmd *cobra.Command) {
f := cmd.Flags() f := cmd.Flags()
f.StringVarP(&o.FileName, "filename", "f", "haul.tar.zst", "(Optional) Specify the name of outputted archive") f.StringVarP(&o.FileName, "filename", "f", consts.DefaultHaulArchiveName, "(Optional) Specify the name of outputted archive")
f.StringVarP(&o.Platform, "platform", "p", "", "(Optional) Specify the platform for runtime imports... i.e. linux/amd64 (unspecified implies all)") f.StringVarP(&o.Platform, "platform", "p", "", "(Optional) Specify the platform for runtime imports... i.e. linux/amd64 (unspecified implies all)")
} }

View File

@@ -6,6 +6,7 @@ import (
"github.com/distribution/distribution/v3/configuration" "github.com/distribution/distribution/v3/configuration"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"hauler.dev/go/hauler/pkg/consts"
) )
type ServeRegistryOpts struct { type ServeRegistryOpts struct {
@@ -23,8 +24,8 @@ type ServeRegistryOpts struct {
func (o *ServeRegistryOpts) AddFlags(cmd *cobra.Command) { func (o *ServeRegistryOpts) AddFlags(cmd *cobra.Command) {
f := cmd.Flags() f := cmd.Flags()
f.IntVarP(&o.Port, "port", "p", 5000, "(Optional) Specify the port to use for incoming connections") f.IntVarP(&o.Port, "port", "p", consts.DefaultRegistryPort, "(Optional) Specify the port to use for incoming connections")
f.StringVar(&o.RootDir, "directory", "registry", "(Optional) Directory to use for backend. Defaults to $PWD/registry") f.StringVar(&o.RootDir, "directory", consts.DefaultRegistryRootDir, "(Optional) Directory to use for backend. Defaults to $PWD/registry")
f.StringVarP(&o.ConfigFile, "config", "c", "", "(Optional) Location of config file (overrides all flags)") f.StringVarP(&o.ConfigFile, "config", "c", "", "(Optional) Location of config file (overrides all flags)")
f.BoolVar(&o.ReadOnly, "readonly", true, "(Optional) Run the registry as readonly") f.BoolVar(&o.ReadOnly, "readonly", true, "(Optional) Run the registry as readonly")
@@ -76,9 +77,9 @@ type ServeFilesOpts struct {
func (o *ServeFilesOpts) AddFlags(cmd *cobra.Command) { func (o *ServeFilesOpts) AddFlags(cmd *cobra.Command) {
f := cmd.Flags() f := cmd.Flags()
f.IntVarP(&o.Port, "port", "p", 8080, "(Optional) Specify the port to use for incoming connections") f.IntVarP(&o.Port, "port", "p", consts.DefaultFileserverPort, "(Optional) Specify the port to use for incoming connections")
f.IntVarP(&o.Timeout, "timeout", "t", 60, "(Optional) Timeout duration for HTTP Requests in seconds for both reads/writes") f.IntVarP(&o.Timeout, "timeout", "t", consts.DefaultFileserverTimeout, "(Optional) Timeout duration for HTTP Requests in seconds for both reads/writes")
f.StringVar(&o.RootDir, "directory", "fileserver", "(Optional) Directory to use for backend. Defaults to $PWD/fileserver") f.StringVar(&o.RootDir, "directory", consts.DefaultFileserverRootDir, "(Optional) Directory to use for backend. Defaults to $PWD/fileserver")
f.StringVar(&o.TLSCert, "tls-cert", "", "(Optional) Location of the TLS Certificate to use for server authenication") f.StringVar(&o.TLSCert, "tls-cert", "", "(Optional) Location of the TLS Certificate to use for server authenication")
f.StringVar(&o.TLSKey, "tls-key", "", "(Optional) Location of the TLS Key to use for server authenication") f.StringVar(&o.TLSKey, "tls-key", "", "(Optional) Location of the TLS Key to use for server authenication")

View File

@@ -23,14 +23,16 @@ func (o *StoreRootOpts) AddFlags(cmd *cobra.Command) {
func (o *StoreRootOpts) Store(ctx context.Context) (*store.Layout, error) { func (o *StoreRootOpts) Store(ctx context.Context) (*store.Layout, error) {
l := log.FromContext(ctx) l := log.FromContext(ctx)
dir := o.StoreDir
abs, err := filepath.Abs(dir) storeDir := o.StoreDir
abs, err := filepath.Abs(storeDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
l.Debugf("using store at %s", abs) l.Debugf("using store at %s", abs)
if _, err := os.Stat(abs); errors.Is(err, os.ErrNotExist) { if _, err := os.Stat(abs); errors.Is(err, os.ErrNotExist) {
err := os.Mkdir(abs, os.ModePerm) err := os.Mkdir(abs, os.ModePerm)
if err != nil { if err != nil {

View File

@@ -36,7 +36,7 @@ func Images() map[string]Fn {
m := make(map[string]Fn) m := make(map[string]Fn)
manifestMapperFn := Fn(func(desc ocispec.Descriptor) (string, error) { manifestMapperFn := Fn(func(desc ocispec.Descriptor) (string, error) {
return "manifest.json", nil return consts.OCIImageManifestFile, nil
}) })
for _, l := range []string{consts.DockerManifestSchema2, consts.DockerManifestListSchema2, consts.OCIManifestSchema1} { for _, l := range []string{consts.DockerManifestSchema2, consts.DockerManifestListSchema2, consts.OCIManifestSchema1} {
@@ -52,7 +52,7 @@ func Images() map[string]Fn {
} }
configMapperFn := Fn(func(desc ocispec.Descriptor) (string, error) { configMapperFn := Fn(func(desc ocispec.Descriptor) (string, error) {
return "config.json", nil return consts.OCIImageConfigFile, nil
}) })
for _, l := range []string{consts.DockerConfigJSON} { for _, l := range []string{consts.DockerConfigJSON} {

View File

@@ -10,6 +10,7 @@ import (
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"hauler.dev/go/hauler/internal/flags" "hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/pkg/consts"
) )
// NewFile returns a fileserver // NewFile returns a fileserver
@@ -22,11 +23,11 @@ func NewFile(ctx context.Context, cfg flags.ServeFilesOpts) (Server, error) {
} }
if cfg.Port == 0 { if cfg.Port == 0 {
cfg.Port = 8080 cfg.Port = consts.DefaultFileserverPort
} }
if cfg.Timeout == 0 { if cfg.Timeout == 0 {
cfg.Timeout = 60 cfg.Timeout = consts.DefaultFileserverTimeout
} }
srv := &http.Server{ srv := &http.Server{

View File

@@ -61,13 +61,32 @@ const (
ContentGroup = "content.hauler.cattle.io" ContentGroup = "content.hauler.cattle.io"
CollectionGroup = "collection.hauler.cattle.io" CollectionGroup = "collection.hauler.cattle.io"
// environment variables
HaulerDir = "HAULER_DIR"
HaulerTempDir = "HAULER_TEMP_DIR"
// container files and directories
OCIImageIndexFile = "index.json"
OCIImageManifestFile = "manifest.json"
OCIImageConfigFile = "config.json"
OCIImageLayoutFile = "oci-layout"
OCIImageBlobsDir = "blobs"
// other constraints // other constraints
CarbideRegistry = "rgcrprod.azurecr.us" CarbideRegistry = "rgcrprod.azurecr.us"
APIVersion = "v1alpha1" APIVersion = "v1alpha1"
DefaultNamespace = "hauler" DefaultNamespace = "hauler"
DefaultTag = "latest" DefaultTag = "latest"
DefaultStoreName = "store" DefaultStoreName = "store"
DefaultRetries = 3 DefaultHaulerDirName = ".hauler"
RetriesInterval = 5 DefaultHaulerTempDirName = "hauler"
OCIImageIndexFile = "index.json" DefaultRegistryRootDir = "registry"
DefaultRegistryPort = 5000
DefaultFileserverRootDir = "fileserver"
DefaultFileserverPort = 8080
DefaultFileserverTimeout = 60
DefaultHaulArchiveName = "haul.tar.zst"
DefaultRetries = 3
RetriesInterval = 5
CustomTimeFormat = "2006-01-02 15:04:05"
) )

View File

@@ -14,11 +14,11 @@ import (
) )
func TestNewChart(t *testing.T) { func TestNewChart(t *testing.T) {
tmpdir, err := os.MkdirTemp("", "hauler") tempDir, err := os.MkdirTemp("", "hauler")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tempDir)
type args struct { type args struct {
name string name string
@@ -53,7 +53,7 @@ func TestNewChart(t *testing.T) {
// { // {
// name: "should create from a chart directory", // name: "should create from a chart directory",
// args: args{ // args: args{
// path: filepath.Join(tmpdir, "podinfo"), // path: filepath.Join(tempDir, "podinfo"),
// }, // },
// want: want, // want: want,
// wantErr: false, // wantErr: false,

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/google/go-containerregistry/pkg/name"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@@ -12,6 +11,8 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/google/go-containerregistry/pkg/name"
ccontent "github.com/containerd/containerd/content" ccontent "github.com/containerd/containerd/content"
"github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes"
"github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go"
@@ -258,7 +259,7 @@ func (o *OCI) blobWriterAt(desc ocispec.Descriptor) (*os.File, error) {
} }
func (o *OCI) ensureBlob(alg string, hex string) (string, error) { func (o *OCI) ensureBlob(alg string, hex string) (string, error) {
dir := o.path("blobs", alg) dir := o.path(consts.OCIImageBlobsDir, alg)
if err := os.MkdirAll(dir, os.ModePerm); err != nil && !os.IsExist(err) { if err := os.MkdirAll(dir, os.ModePerm); err != nil && !os.IsExist(err) {
return "", err return "", err
} }

View File

@@ -15,6 +15,7 @@ import (
"oras.land/oras-go/pkg/content" "oras.land/oras-go/pkg/content"
"hauler.dev/go/hauler/internal/flags"
"hauler.dev/go/hauler/pkg/artifacts/image" "hauler.dev/go/hauler/pkg/artifacts/image"
"hauler.dev/go/hauler/pkg/consts" "hauler.dev/go/hauler/pkg/consts"
"hauler.dev/go/hauler/pkg/log" "hauler.dev/go/hauler/pkg/log"
@@ -22,9 +23,9 @@ import (
) )
// VerifyFileSignature verifies the digital signature of a file using Sigstore/Cosign. // VerifyFileSignature verifies the digital signature of a file using Sigstore/Cosign.
func VerifySignature(ctx context.Context, s *store.Layout, keyPath string, ref string) error { func VerifySignature(ctx context.Context, s *store.Layout, keyPath string, ref string, ro *flags.CliRootOpts) error {
operation := func() error { operation := func() error {
cosignBinaryPath, err := getCosignPath() cosignBinaryPath, err := getCosignPath(ro.HaulerDir)
if err != nil { if err != nil {
return err return err
} }
@@ -42,10 +43,11 @@ func VerifySignature(ctx context.Context, s *store.Layout, keyPath string, ref s
} }
// SaveImage saves image and any signatures/attestations to the store. // SaveImage saves image and any signatures/attestations to the store.
func SaveImage(ctx context.Context, s *store.Layout, ref string, platform string) error { func SaveImage(ctx context.Context, s *store.Layout, ref string, platform string, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
operation := func() error { operation := func() error {
cosignBinaryPath, err := getCosignPath() cosignBinaryPath, err := getCosignPath(ro.HaulerDir)
if err != nil { if err != nil {
return err return err
} }
@@ -110,10 +112,10 @@ func SaveImage(ctx context.Context, s *store.Layout, ref string, platform string
} }
// LoadImage loads store to a remote registry. // LoadImage loads store to a remote registry.
func LoadImages(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions) error { func LoadImages(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions, ro *flags.CliRootOpts) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
cosignBinaryPath, err := getCosignPath() cosignBinaryPath, err := getCosignPath(ro.HaulerDir)
if err != nil { if err != nil {
return err return err
} }
@@ -171,9 +173,9 @@ func LoadImages(ctx context.Context, s *store.Layout, registry string, ropts con
} }
// RegistryLogin - performs cosign login // RegistryLogin - performs cosign login
func RegistryLogin(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions) error { func RegistryLogin(ctx context.Context, s *store.Layout, registry string, ropts content.RegistryOptions, ro *flags.CliRootOpts) error {
log := log.FromContext(ctx) log := log.FromContext(ctx)
cosignBinaryPath, err := getCosignPath() cosignBinaryPath, err := getCosignPath(ro.HaulerDir)
if err != nil { if err != nil {
return err return err
} }
@@ -190,6 +192,7 @@ func RegistryLogin(ctx context.Context, s *store.Layout, registry string, ropts
func RetryOperation(ctx context.Context, operation func() error) error { func RetryOperation(ctx context.Context, operation func() error) error {
l := log.FromContext(ctx) l := log.FromContext(ctx)
for attempt := 1; attempt <= consts.DefaultRetries; attempt++ { for attempt := 1; attempt <= consts.DefaultRetries; attempt++ {
err := operation() err := operation()
if err == nil { if err == nil {
@@ -210,14 +213,18 @@ func RetryOperation(ctx context.Context, operation func() error) error {
return fmt.Errorf("operation failed after %d attempts", consts.DefaultRetries) return fmt.Errorf("operation failed after %d attempts", consts.DefaultRetries)
} }
func EnsureBinaryExists(ctx context.Context, bin embed.FS) error { func EnsureBinaryExists(ctx context.Context, bin embed.FS, ro *flags.CliRootOpts) error {
// Set up a path for the binary to be copied. l := log.FromContext(ctx)
binaryPath, err := getCosignPath()
// Set up a path for the binary to be copied
binaryPath, err := getCosignPath(ro.HaulerDir)
if err != nil { if err != nil {
return fmt.Errorf("error: %v", err) return fmt.Errorf("error: %v", err)
} }
// Determine the architecture so that we pull the correct embedded binary. l.Debugf("using hauler directory at %s", filepath.Dir(binaryPath))
// Determine the architecture so that we pull the correct embedded binary
arch := runtime.GOARCH arch := runtime.GOARCH
rOS := runtime.GOOS rOS := runtime.GOOS
binaryName := "cosign" binaryName := "cosign"
@@ -243,35 +250,38 @@ func EnsureBinaryExists(ctx context.Context, bin embed.FS) error {
} }
// getCosignPath returns the binary path // getCosignPath returns the binary path
func getCosignPath() (string, error) { func getCosignPath(haulerDir string) (string, error) {
// Get the current user's information if haulerDir == "" {
currentUser, err := user.Current() haulerDir = os.Getenv(consts.HaulerDir)
if err != nil {
return "", fmt.Errorf("error: %v", err)
} }
// Get the user's home directory if haulerDir == "" {
homeDir := currentUser.HomeDir // Get the current user's information
currentUser, err := user.Current()
if err != nil {
return "", fmt.Errorf("error retrieving user information: %v", err)
}
// Construct the path to the .hauler directory // Get the current user's home directory
haulerDir := filepath.Join(homeDir, ".hauler") homeDir := currentUser.HomeDir
haulerDir = filepath.Join(homeDir, consts.DefaultHaulerDirName)
}
// Create the .hauler directory if it doesn't exist // Create the .hauler directory (if it doesn't exist)
if _, err := os.Stat(haulerDir); os.IsNotExist(err) { if _, err := os.Stat(haulerDir); os.IsNotExist(err) {
// .hauler directory does not exist, create it
if err := os.MkdirAll(haulerDir, 0755); err != nil { if err := os.MkdirAll(haulerDir, 0755); err != nil {
return "", fmt.Errorf("error creating .hauler directory: %v", err) return "", fmt.Errorf("error creating %s directory: %v", consts.DefaultHaulerDirName, err)
} }
} }
// Determine the binary name. // Determine the binary name
rOS := runtime.GOOS rOS := runtime.GOOS
binaryName := "cosign" binaryName := "cosign"
if rOS == "windows" { if rOS == "windows" {
binaryName = "cosign.exe" binaryName = "cosign.exe"
} }
// construct path to binary // Construct the path to the binary
binaryPath := filepath.Join(haulerDir, binaryName) binaryPath := filepath.Join(haulerDir, binaryName)
return binaryPath, nil return binaryPath, nil

View File

@@ -7,6 +7,7 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"hauler.dev/go/hauler/pkg/consts"
) )
// Logger provides an interface for all used logger features regardless of logging backend // Logger provides an interface for all used logger features regardless of logging backend
@@ -30,9 +31,8 @@ type Fields map[string]string
// NewLogger returns a new Logger // NewLogger returns a new Logger
func NewLogger(out io.Writer) Logger { func NewLogger(out io.Writer) Logger {
customTimeFormat := "2006-01-02 15:04:05" zerolog.TimeFieldFormat = consts.CustomTimeFormat
zerolog.TimeFieldFormat = customTimeFormat output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: consts.CustomTimeFormat}
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: customTimeFormat}
l := log.Output(output) l := log.Output(output)
return &logger{ return &logger{
zl: l.With().Timestamp().Logger(), zl: l.With().Timestamp().Logger(),

View File

@@ -151,17 +151,17 @@ func (l *Layout) AddOCICollection(ctx context.Context, collection artifacts.OCIC
// This can be a highly destructive operation if the store's directory happens to be inline with other non-store contents // This can be a highly destructive operation if the store's directory happens to be inline with other non-store contents
// To reduce the blast radius and likelihood of deleting things we don't own, Flush explicitly deletes oci-layout content only // To reduce the blast radius and likelihood of deleting things we don't own, Flush explicitly deletes oci-layout content only
func (l *Layout) Flush(ctx context.Context) error { func (l *Layout) Flush(ctx context.Context) error {
blobs := filepath.Join(l.Root, "blobs") blobs := filepath.Join(l.Root, consts.OCIImageBlobsDir)
if err := os.RemoveAll(blobs); err != nil { if err := os.RemoveAll(blobs); err != nil {
return err return err
} }
index := filepath.Join(l.Root, "index.json") index := filepath.Join(l.Root, consts.OCIImageIndexFile)
if err := os.RemoveAll(index); err != nil { if err := os.RemoveAll(index); err != nil {
return err return err
} }
layout := filepath.Join(l.Root, "oci-layout") layout := filepath.Join(l.Root, consts.OCIImageLayoutFile)
if err := os.RemoveAll(layout); err != nil { if err := os.RemoveAll(layout); err != nil {
return err return err
} }
@@ -240,7 +240,7 @@ func (l *Layout) writeLayer(layer v1.Layer) error {
return err return err
} }
dir := filepath.Join(l.Root, "blobs", d.Algorithm) dir := filepath.Join(l.Root, consts.OCIImageBlobsDir, d.Algorithm)
if err := os.MkdirAll(dir, os.ModePerm); err != nil && !os.IsExist(err) { if err := os.MkdirAll(dir, os.ModePerm); err != nil && !os.IsExist(err) {
return err return err
} }

View File

@@ -63,16 +63,16 @@ func TestLayout_AddOCI(t *testing.T) {
} }
func setup(t *testing.T) func() error { func setup(t *testing.T) func() error {
tmpdir, err := os.MkdirTemp("", "hauler") tempDir, err := os.MkdirTemp("", "hauler")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
root = tmpdir root = tempDir
ctx = context.Background() ctx = context.Background()
return func() error { return func() error {
os.RemoveAll(tmpdir) os.RemoveAll(tempDir)
return nil return nil
} }
} }