diff --git a/cmd/hauler/cli/store.go b/cmd/hauler/cli/store.go index 86a6466..4d1a969 100644 --- a/cmd/hauler/cli/store.go +++ b/cmd/hauler/cli/store.go @@ -108,12 +108,28 @@ func addStoreLoad() *cobra.Command { } func addStoreServe() *cobra.Command { - o := &store.ServeOpts{RootOpts: rootStoreOpts} - cmd := &cobra.Command{ Use: "serve", - Short: "Expose the content of a local store through an OCI compliant server", + Short: "Expose the content of a local store through an OCI compliant registry or file server", RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, + } + cmd.AddCommand( + addStoreServeRegistry(), + addStoreServeFiles(), + ) + + return cmd +} + +// RegistryCmd serves the embedded registry +func addStoreServeRegistry() *cobra.Command { + o := &store.ServeRegistryOpts{RootOpts: rootStoreOpts} + cmd := &cobra.Command{ + Use: "registry", + Short: "Serve the embedded registry", + RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() s, err := o.Store(ctx) @@ -121,12 +137,36 @@ func addStoreServe() *cobra.Command { return err } - return store.ServeCmd(ctx, o, s) - }, - } - o.AddFlags(cmd) + return store.ServeRegistryCmd(ctx, o, s) + }, + } - return cmd + o.AddFlags(cmd) + + return cmd +} + +// FileServerCmd serves the file server +func addStoreServeFiles() *cobra.Command { + o := &store.ServeFilesOpts{RootOpts: rootStoreOpts} + cmd := &cobra.Command{ + Use: "fileserver", + Short: "Serve the file server", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + + s, err := o.Store(ctx) + if err != nil { + return err + } + + return store.ServeFilesCmd(ctx, o, s) + }, + } + + o.AddFlags(cmd) + + return cmd } func addStoreSave() *cobra.Command { diff --git a/cmd/hauler/cli/store/serve.go b/cmd/hauler/cli/store/serve.go index 83586ce..5046393 100644 --- a/cmd/hauler/cli/store/serve.go +++ b/cmd/hauler/cli/store/serve.go @@ -17,30 +17,29 @@ import ( "github.com/rancherfederal/hauler/pkg/store" "github.com/rancherfederal/hauler/internal/server" + "github.com/rancherfederal/hauler/pkg/log" ) -type ServeOpts struct { +type ServeRegistryOpts struct { *RootOpts Port int RootDir string ConfigFile string - Daemon bool storedir string } -func (o *ServeOpts) AddFlags(cmd *cobra.Command) { +func (o *ServeRegistryOpts) AddFlags(cmd *cobra.Command) { f := cmd.Flags() - f.IntVarP(&o.Port, "port", "p", 5000, "Port to listen on") - f.StringVar(&o.RootDir, "directory", "registry", "Directory to use for registry backend (defaults to '$PWD/registry')") + f.IntVarP(&o.Port, "port", "p", 5000, "Port to listen on.") + f.StringVar(&o.RootDir, "directory", "registry", "Directory to use for backend. Defaults to $PWD/registry") f.StringVarP(&o.ConfigFile, "config", "c", "", "Path to a config file, will override all other configs") - f.BoolVarP(&o.Daemon, "daemon", "d", false, "Toggle serving as a daemon") } -// ServeCmd serves the embedded registry almost identically to how distribution/v3 does it -func ServeCmd(ctx context.Context, o *ServeOpts, s *store.Layout) error { +func ServeRegistryCmd(ctx context.Context, o *ServeRegistryOpts, s *store.Layout) error { + l := log.FromContext(ctx) ctx = dcontext.WithVersion(ctx, version.Version) tr := server.NewTempRegistry(ctx, o.RootDir) @@ -55,7 +54,7 @@ func ServeCmd(ctx context.Context, o *ServeOpts, s *store.Layout) error { tr.Close() - cfg := o.defaultConfig() + cfg := o.defaultRegistryConfig() if o.ConfigFile != "" { ucfg, err := loadConfig(o.ConfigFile) if err != nil { @@ -64,14 +63,59 @@ func ServeCmd(ctx context.Context, o *ServeOpts, s *store.Layout) error { cfg = ucfg } + l.Infof("starting registry on port [%d]", o.Port) r, err := server.NewRegistry(ctx, cfg) if err != nil { return err } - + if err = r.ListenAndServe(); err != nil { return err } + + return nil +} + +type ServeFilesOpts struct { + *RootOpts + + Port int + RootDir string + + storedir string +} + +func (o *ServeFilesOpts) AddFlags(cmd *cobra.Command) { + f := cmd.Flags() + + f.IntVarP(&o.Port, "port", "p", 8080, "Port to listen on.") + f.StringVar(&o.RootDir, "directory", "store-files", "Directory to use for backend. Defaults to $PWD/store-files") +} + +func ServeFilesCmd(ctx context.Context, o *ServeFilesOpts, s *store.Layout) error { + l := log.FromContext(ctx) + ctx = dcontext.WithVersion(ctx, version.Version) + + opts := &CopyOpts{} + if err := CopyCmd(ctx, opts, s, "dir://"+o.RootDir); err != nil { + return err + } + + cfg := server.FileConfig{ + Root: o.RootDir, + Port: o.Port, + } + + f, err := server.NewFile(ctx, cfg) + if err != nil { + return err + } + + l.Infof("starting file server on port [%d]", o.Port) + if err := f.ListenAndServe(); err != nil { + return err + } + return nil } @@ -84,7 +128,7 @@ func loadConfig(filename string) (*configuration.Configuration, error) { return configuration.Parse(f) } -func (o *ServeOpts) defaultConfig() *configuration.Configuration { +func (o *ServeRegistryOpts) defaultRegistryConfig() *configuration.Configuration { cfg := &configuration.Configuration{ Version: "0.1", Storage: configuration.Storage{ diff --git a/internal/server/file.go b/internal/server/file.go index 74a4ad2..55a6515 100644 --- a/internal/server/file.go +++ b/internal/server/file.go @@ -21,8 +21,7 @@ type FileConfig struct { // TODO: Better configs func NewFile(ctx context.Context, cfg FileConfig) (Server, error) { r := mux.NewRouter() - r.Handle("/", handlers.LoggingHandler(os.Stdout, http.FileServer(http.Dir(cfg.Root)))) - + r.PathPrefix("/").Handler(handlers.LoggingHandler(os.Stdout, http.StripPrefix("/", http.FileServer(http.Dir(cfg.Root))))) if cfg.Root == "" { cfg.Root = "." }