Skip to content

Commit

Permalink
feat: Support repository path prefix for serve bundle (#810)
Browse files Browse the repository at this point in the history
This allows for specifying different repositories for a previously
built bundle, very useful when building air-gapped environments to
mimic Harbor which requires inserting a prefix for the project name.
  • Loading branch information
jimmidyson authored Nov 21, 2024
1 parent 39333cf commit 5ec2bb8
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 29 deletions.
48 changes: 43 additions & 5 deletions cmd/mindthegap/serve/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ func NewCommand(
bundleCmdName string,
) (cmd *cobra.Command, stopCh chan struct{}) {
var (
bundleFiles []string
listenAddress string
listenPort uint16
tlsCertificate string
tlsKey string
bundleFiles []string
listenAddress string
listenPort uint16
tlsCertificate string
tlsKey string
repositoriesPrefix string
)

stopCh = make(chan struct{})
Expand Down Expand Up @@ -71,6 +72,12 @@ func NewCommand(
return err
}

if repositoriesPrefix != "" {
if err := addRepositoryPrefixToImages(tempDir, repositoriesPrefix); err != nil {
return err
}
}

// Write out the merged image bundle config to the target directory for completeness.
if imagesCfg != nil {
if err := config.WriteSanitizedImagesConfig(*imagesCfg, filepath.Join(tempDir, "images.yaml")); err != nil {
Expand Down Expand Up @@ -123,6 +130,37 @@ func NewCommand(
Uint16Var(&listenPort, "listen-port", 0, "Port to listen on (0 means use any free port)")
cmd.Flags().StringVar(&tlsCertificate, "tls-cert-file", "", "TLS certificate file")
cmd.Flags().StringVar(&tlsKey, "tls-private-key-file", "", "TLS private key file")
cmd.Flags().StringVar(&repositoriesPrefix, "repositories-prefix", "",
"Prefix to prepend to all repositories in the bundle when serving")

return cmd, stopCh
}

func addRepositoryPrefixToImages(tempDir, newPrefix string) error {
originalDirRepositoriesPrefix := filepath.Join(tempDir, "docker", "registry", "v2", "repositories")
existingRepositories, err := os.ReadDir(originalDirRepositoriesPrefix)
if err != nil {
return fmt.Errorf("failed to read existing repositories: %w", err)
}

newRepositoriesDir := filepath.Join(originalDirRepositoriesPrefix, newPrefix)
err = os.MkdirAll(newRepositoriesDir, 0o755)
if err != nil {
return fmt.Errorf("failed to create repositories prefix directory: %w", err)
}

for _, existingRepository := range existingRepositories {
if existingRepository.IsDir() &&
filepath.Join(originalDirRepositoriesPrefix, existingRepository.Name()) != newRepositoriesDir {
err = os.Rename(
filepath.Join(originalDirRepositoriesPrefix, existingRepository.Name()),
filepath.Join(newRepositoriesDir, existingRepository.Name()),
)
if err != nil {
return fmt.Errorf("failed to move existing repository: %w", err)
}
}
}

return nil
}
52 changes: 28 additions & 24 deletions devbox.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
{
"packages": [
"actionlint@latest",
"coreutils@latest",
"crane@latest",
"fd@latest",
"ginkgo@latest",
"git@latest",
"gnused@latest",
"gnugrep@latest",
"go@latest",
"go-task@latest",
"gojq@latest",
"golangci-lint@latest",
"golines@latest",
"goreleaser@latest",
"gotestsum@latest",
"ko@latest",
"kubernetes-helm@latest",
"pre-commit@latest",
"shfmt@latest",
"upx@latest",
"path:./hack/flakes#go-mod-upgrade",
"path:./hack/flakes#govulncheck"
]
"packages": {
"actionlint": "latest",
"coreutils": "latest",
"crane": "latest",
"darwin.Security": {
"version": "latest",
"platforms": ["aarch64-darwin"]
},
"fd": "latest",
"ginkgo": "latest",
"git": "latest",
"gnused": "latest",
"gnugrep": "latest",
"go": "latest",
"go-task": "latest",
"gojq": "latest",
"golangci-lint": "latest",
"golines": "latest",
"goreleaser": "latest",
"gotestsum": "latest",
"ko": "latest",
"kubernetes-helm": "latest",
"pre-commit": "latest",
"shfmt": "latest",
"upx": "latest",
"path:./hack/flakes#go-mod-upgrade": "",
"path:./hack/flakes#govulncheck": ""
}
}
18 changes: 18 additions & 0 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,24 @@
}
}
},
"darwin.Security@latest": {
"last_modified": "2024-11-16T04:25:12Z",
"resolved": "github:NixOS/nixpkgs/34a626458d686f1b58139620a8b2793e9e123bba#darwin.Security",
"source": "devbox-search",
"version": "11.0",
"systems": {
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/nvzqysba0ga8w7b93y2jsfmw6bicrk35-Security-11.0",
"default": true
}
],
"store_path": "/nix/store/nvzqysba0ga8w7b93y2jsfmw6bicrk35-Security-11.0"
}
}
},
"fd@latest": {
"last_modified": "2024-11-03T14:18:04Z",
"resolved": "github:NixOS/nixpkgs/4ae2e647537bcdbb82265469442713d066675275#fd",
Expand Down
67 changes: 67 additions & 0 deletions test/e2e/imagebundle/serve_bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,73 @@ var _ = Describe("Serve Image Bundle", func() {
Eventually(done).Should(BeClosed())
})

It("With repositories prefix", func() {
ipAddr := helpers.GetFirstNonLoopbackIP(GinkgoT())

tempCertDir := GinkgoT().TempDir()
caCertFile, _, certFile, keyFile := helpers.GenerateCertificateAndKeyWithIPSAN(
GinkgoT(),
tempCertDir,
ipAddr,
)

helpers.CreateBundle(
GinkgoT(),
bundleFile,
filepath.Join("testdata", "create-success.yaml"),
"linux/"+runtime.GOARCH,
)

port, err := freeport.GetFreePort()
Expect(err).NotTo(HaveOccurred())
cmd.SetArgs([]string{
"--image-bundle", bundleFile,
"--listen-address", ipAddr.String(),
"--listen-port", strconv.Itoa(port),
"--tls-cert-file", certFile,
"--tls-private-key-file", keyFile,
"--repositories-prefix", "/some/test/prefix",
})

done := make(chan struct{})
go func() {
defer GinkgoRecover()

Expect(cmd.Execute()).To(Succeed())

close(done)
}()

helpers.WaitForTCPPort(GinkgoT(), ipAddr.String(), port)

testRoundTripper, err := httputils.TLSConfiguredRoundTripper(
remote.DefaultTransport,
net.JoinHostPort(ipAddr.String(), strconv.Itoa(port)),
false,
caCertFile,
)
Expect(err).NotTo(HaveOccurred())

helpers.ValidateImageIsAvailable(
GinkgoT(),
ipAddr.String(),
port,
"",
"some/test/prefix/stefanprodan/podinfo",
"6.2.0",
[]*v1.Platform{{
OS: "linux",
Architecture: runtime.GOARCH,
}},
false,
remote.WithTransport(testRoundTripper),
)

close(stopCh)

Eventually(done).Should(BeClosed())
})

It("Bundle does not exist", func() {
cmd.SetArgs([]string{
"--image-bundle", bundleFile,
Expand Down

0 comments on commit 5ec2bb8

Please sign in to comment.