mirror of
https://github.com/hauler-dev/hauler.git
synced 2026-02-22 13:53:57 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f64914097 | ||
|
|
6a74668e2c | ||
|
|
0c5cf20e87 | ||
|
|
513719bc9e | ||
|
|
047b7a7003 | ||
|
|
a4685169c6 | ||
|
|
47549615c4 | ||
|
|
2d725026dc | ||
|
|
60667b7116 | ||
|
|
7d62a1c98e | ||
|
|
894ffb1533 | ||
|
|
78b3442d23 | ||
|
|
cd46febb6b | ||
|
|
0957a930dd | ||
|
|
a6bc6308d9 | ||
|
|
1304cf6c76 | ||
|
|
f2e02c80c0 | ||
|
|
25806e993e | ||
|
|
05e67bc750 | ||
|
|
b43ed0503a | ||
|
|
27e2fc9de0 | ||
|
|
d32d75b93e | ||
|
|
ceb77601d0 | ||
|
|
d90545a9e4 | ||
|
|
bef141ab67 | ||
|
|
385d767c2a | ||
|
|
22edc77506 | ||
|
|
9058797bbc | ||
|
|
35e2f655da | ||
|
|
f5c0f6f0ae | ||
|
|
0ec77b4168 | ||
|
|
7a7906b8ea | ||
|
|
f4774445f6 | ||
|
|
d59b29bfce | ||
|
|
fd702202ac | ||
|
|
9e9565717b | ||
|
|
bfe47ae141 | ||
|
|
ebab7f38a0 | ||
|
|
f0cba3c2c6 | ||
|
|
286120da50 | ||
|
|
dcdeb93518 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a report to help us improve!
|
||||
about: Submit a bug report to help us improve!
|
||||
title: '[BUG]'
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Submit a request for us to improve!
|
||||
title: '[RFE]'
|
||||
about: Submit a feature request for us to improve!
|
||||
title: '[feature]'
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
41
.github/workflows/release.yaml
vendored
41
.github/workflows/release.yaml
vendored
@@ -17,17 +17,22 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Set Up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Run Go Releaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean -p 1
|
||||
version: "~> v2"
|
||||
args: "release --clean -p 1"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||
@@ -35,30 +40,54 @@ jobs:
|
||||
container-release:
|
||||
name: Container Release Job
|
||||
runs-on: ubuntu-latest
|
||||
needs: [go-release]
|
||||
timeout-minutes: 30
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Set Up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
- name: Authenticate to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and Push to GitHub Container Registry
|
||||
- name: Authenticate to DockerHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and Push Release Container to GitHub Container Registry
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
target: release
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
||||
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}, docker.io/hauler/hauler:${{ github.ref_name }}
|
||||
|
||||
- name: Build and Push Debug Container to GitHub Container Registry
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
target: debug
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ghcr.io/${{ github.repository }}-debug:${{ github.ref_name }}, docker.io/hauler/hauler-debug:${{ github.ref_name }}
|
||||
|
||||
16
.github/workflows/unittest.yaml
vendored
16
.github/workflows/unittest.yaml
vendored
@@ -20,6 +20,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Set Up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
@@ -29,9 +34,10 @@ jobs:
|
||||
run: |
|
||||
mkdir -p cmd/hauler/binaries
|
||||
touch cmd/hauler/binaries/dummy.txt
|
||||
go test -race -covermode=atomic -coverprofile=coverage.out ./pkg/... ./internal/... ./cmd/...
|
||||
go test -race -covermode=atomic -coverprofile=coverage.out ./...
|
||||
|
||||
- name: On Failure, Launch Debug Session
|
||||
if: ${{ failure() }}
|
||||
uses: mxschmitt/action-tmate@v3
|
||||
timeout-minutes: 10
|
||||
- name: Upload Coverage Report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report
|
||||
path: coverage.out
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,9 +1,5 @@
|
||||
.DS_Store
|
||||
|
||||
# Vagrant
|
||||
.vagrant
|
||||
|
||||
# Editor directories and files
|
||||
**/.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
@@ -12,13 +8,9 @@
|
||||
*.sln
|
||||
*.sw?
|
||||
*.dir-locals.el
|
||||
|
||||
# old, ad-hoc ignores
|
||||
artifacts
|
||||
local-artifacts
|
||||
airgap-scp.sh
|
||||
|
||||
# generated
|
||||
dist/
|
||||
tmp/
|
||||
bin/
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
version: 2
|
||||
|
||||
project_name: hauler
|
||||
before:
|
||||
hooks:
|
||||
@@ -7,9 +9,10 @@ before:
|
||||
|
||||
release:
|
||||
prerelease: auto
|
||||
make_latest: false
|
||||
|
||||
env:
|
||||
- vpkg=github.com/rancherfederal/hauler/internal/version
|
||||
- vpkg=github.com/hauler-dev/hauler/internal/version
|
||||
- cosign_version=v2.2.3+carbide.2
|
||||
|
||||
builds:
|
||||
@@ -36,14 +39,14 @@ universal_binaries:
|
||||
- replace: false
|
||||
|
||||
changelog:
|
||||
skip: false
|
||||
disable: false
|
||||
use: git
|
||||
|
||||
brews:
|
||||
- name: hauler
|
||||
tap:
|
||||
owner: rancherfederal
|
||||
repository:
|
||||
owner: hauler-dev
|
||||
name: homebrew-tap
|
||||
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
|
||||
folder: Formula
|
||||
directory: Formula
|
||||
description: "Hauler CLI"
|
||||
|
||||
26
Dockerfile
26
Dockerfile
@@ -1,25 +1,45 @@
|
||||
# builder stage
|
||||
FROM registry.suse.com/bci/golang:1.21 AS builder
|
||||
|
||||
RUN zypper --non-interactive install make bash wget ca-certificates
|
||||
|
||||
COPY . /build
|
||||
WORKDIR /build
|
||||
RUN make build
|
||||
|
||||
RUN echo "hauler:x:1001:1001::/home:" > /etc/passwd \
|
||||
RUN echo "hauler:x:1001:1001::/home/hauler:" > /etc/passwd \
|
||||
&& echo "hauler:x:1001:hauler" > /etc/group \
|
||||
&& mkdir /home/hauler \
|
||||
&& mkdir /store \
|
||||
&& mkdir /fileserver \
|
||||
&& mkdir /registry
|
||||
|
||||
FROM scratch
|
||||
# release stage
|
||||
FROM scratch AS release
|
||||
|
||||
COPY --from=builder /var/lib/ca-certificates/ca-bundle.pem /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /etc/passwd /etc/passwd
|
||||
COPY --from=builder /etc/group /etc/group
|
||||
COPY --from=builder --chown=hauler:hauler /home/. /home
|
||||
COPY --from=builder --chown=hauler:hauler /home/hauler/. /home/hauler
|
||||
COPY --from=builder --chown=hauler:hauler /tmp/. /tmp
|
||||
COPY --from=builder --chown=hauler:hauler /store/. /store
|
||||
COPY --from=builder --chown=hauler:hauler /registry/. /registry
|
||||
COPY --from=builder --chown=hauler:hauler /fileserver/. /fileserver
|
||||
COPY --from=builder --chown=hauler:hauler /build/bin/hauler /
|
||||
|
||||
USER hauler
|
||||
ENTRYPOINT [ "/hauler" ]
|
||||
|
||||
# debug stage
|
||||
FROM alpine AS debug
|
||||
|
||||
COPY --from=builder /var/lib/ca-certificates/ca-bundle.pem /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /etc/passwd /etc/passwd
|
||||
COPY --from=builder /etc/group /etc/group
|
||||
COPY --from=builder --chown=hauler:hauler /home/hauler/. /home/hauler
|
||||
COPY --from=builder --chown=hauler:hauler /build/bin/hauler /bin/hauler
|
||||
|
||||
RUN apk --no-cache add curl
|
||||
|
||||
USER hauler
|
||||
WORKDIR /home/hauler
|
||||
8
Makefile
8
Makefile
@@ -10,17 +10,17 @@ all: fmt vet install test
|
||||
build:
|
||||
rm -rf cmd/hauler/binaries;\
|
||||
mkdir -p cmd/hauler/binaries;\
|
||||
wget -P cmd/hauler/binaries/ https://github.com/rancher-government-carbide/cosign/releases/download/$(COSIGN_VERSION)/cosign-$(shell go env GOOS)-$(shell go env GOARCH);\
|
||||
wget -P cmd/hauler/binaries/ https://github.com/hauler-dev/cosign/releases/download/$(COSIGN_VERSION)/cosign-$(shell go env GOOS)-$(shell go env GOARCH);\
|
||||
mkdir bin;\
|
||||
CGO_ENABLED=0 go build -o bin ./cmd/...;\
|
||||
|
||||
build-all: fmt vet
|
||||
goreleaser build --rm-dist --snapshot
|
||||
|
||||
goreleaser build --clean --snapshot
|
||||
|
||||
install:
|
||||
rm -rf cmd/hauler/binaries;\
|
||||
mkdir -p cmd/hauler/binaries;\
|
||||
wget -P cmd/hauler/binaries/ https://github.com/rancher-government-carbide/cosign/releases/download/$(COSIGN_VERSION)/cosign-$(shell go env GOOS)-$(shell go env GOARCH);\
|
||||
wget -P cmd/hauler/binaries/ https://github.com/hauler-dev/cosign/releases/download/$(COSIGN_VERSION)/cosign-$(shell go env GOOS)-$(shell go env GOARCH);\
|
||||
CGO_ENABLED=0 go install ./cmd/...;\
|
||||
|
||||
vet:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
`Hauler` does this by storing contents and collections as OCI Artifacts and allows operators to serve contents and collections with an embedded registry and fileserver. Additionally, `Hauler` has the ability to store and inspect various non-image OCI Artifacts.
|
||||
|
||||
For more information, please review the **[Hauler Documentation](https://rancherfederal.github.io/hauler-docs)!**
|
||||
For more information, please review the **[Hauler Documentation](https://hauler.dev)!**
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -25,7 +25,7 @@ curl -sfL https://get.hauler.dev | bash
|
||||
|
||||
```bash
|
||||
# installs latest release
|
||||
brew tap rancherfederal/homebrew-tap
|
||||
brew tap hauler-dev/homebrew-tap
|
||||
brew install hauler
|
||||
```
|
||||
|
||||
|
||||
@@ -3,23 +3,24 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func addCompletion(parent *cobra.Command) {
|
||||
cmd := &cobra.Command{
|
||||
Use: "completion",
|
||||
Short: "Generates completion scripts for various shells",
|
||||
Use: "completion",
|
||||
Short: "Generates completion scripts for various shells",
|
||||
Long: `The completion sub-command generates completion scripts for various shells.`,
|
||||
}
|
||||
|
||||
|
||||
cmd.AddCommand(
|
||||
addCompletionZsh(),
|
||||
addCompletionBash(),
|
||||
addCompletionFish(),
|
||||
addCompletionPowershell(),
|
||||
)
|
||||
|
||||
|
||||
parent.AddCommand(cmd)
|
||||
}
|
||||
|
||||
@@ -34,19 +35,19 @@ func addCompletionZsh() *cobra.Command {
|
||||
Short: "Generates zsh completion scripts",
|
||||
Long: `The completion sub-command generates completion scripts for zsh.`,
|
||||
Example: `To load completion run
|
||||
|
||||
|
||||
. <(hauler completion zsh)
|
||||
|
||||
|
||||
To configure your zsh shell to load completions for each session add to your zshrc
|
||||
|
||||
|
||||
# ~/.zshrc or ~/.profile
|
||||
command -v hauler >/dev/null && . <(hauler completion zsh)
|
||||
|
||||
|
||||
or write a cached file in one of the completion directories in your ${fpath}:
|
||||
|
||||
|
||||
echo "${fpath// /\n}" | grep -i completion
|
||||
hauler completion zsh > _hauler
|
||||
|
||||
|
||||
mv _hauler ~/.oh-my-zsh/completions # oh-my-zsh
|
||||
mv _hauler ~/.zprezto/modules/completion/external/src/ # zprezto`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -64,11 +65,11 @@ func addCompletionBash() *cobra.Command {
|
||||
Short: "Generates bash completion scripts",
|
||||
Long: `The completion sub-command generates completion scripts for bash.`,
|
||||
Example: `To load completion run
|
||||
|
||||
|
||||
. <(hauler completion bash)
|
||||
|
||||
|
||||
To configure your bash shell to load completions for each session add to your bashrc
|
||||
|
||||
|
||||
# ~/.bashrc or ~/.profile
|
||||
command -v hauler >/dev/null && . <(hauler completion bash)`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -84,9 +85,9 @@ func addCompletionFish() *cobra.Command {
|
||||
Short: "Generates fish completion scripts",
|
||||
Long: `The completion sub-command generates completion scripts for fish.`,
|
||||
Example: `To configure your fish shell to load completions for each session write this script to your completions dir:
|
||||
|
||||
|
||||
hauler completion fish > ~/.config/fish/completions/hauler.fish
|
||||
|
||||
|
||||
See http://fishshell.com/docs/current/index.html#completion-own for more details`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.GenFishCompletion(os.Stdout, true)
|
||||
@@ -101,18 +102,18 @@ func addCompletionPowershell() *cobra.Command {
|
||||
Short: "Generates powershell completion scripts",
|
||||
Long: `The completion sub-command generates completion scripts for powershell.`,
|
||||
Example: `To load completion run
|
||||
|
||||
|
||||
. <(hauler completion powershell)
|
||||
|
||||
|
||||
To configure your powershell shell to load completions for each session add to your powershell profile
|
||||
|
||||
|
||||
Windows:
|
||||
|
||||
|
||||
cd "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"
|
||||
hauler completion powershell >> hauler-completion.ps1
|
||||
|
||||
|
||||
Linux:
|
||||
|
||||
|
||||
cd "${XDG_CONFIG_HOME:-"$HOME/.config/"}/powershell/modules"
|
||||
hauler completion powershell >> hauler-completions.ps1`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -120,4 +121,4 @@ func addCompletionPowershell() *cobra.Command {
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"os"
|
||||
"io"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"oras.land/oras-go/pkg/content"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/cosign"
|
||||
)
|
||||
|
||||
type Opts struct {
|
||||
Username string
|
||||
Password string
|
||||
Username string
|
||||
Password string
|
||||
PasswordStdin bool
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func addLogin(parent *cobra.Command) {
|
||||
Example: `
|
||||
# Log in to reg.example.com
|
||||
hauler login reg.example.com -u bob -p haulin`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, arg []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
@@ -47,7 +47,7 @@ hauler login reg.example.com -u bob -p haulin`,
|
||||
o.Password = strings.TrimSuffix(string(contents), "\n")
|
||||
o.Password = strings.TrimSuffix(o.Password, "\r")
|
||||
}
|
||||
|
||||
|
||||
if o.Username == "" && o.Password == "" {
|
||||
return fmt.Errorf("username and password required")
|
||||
}
|
||||
@@ -62,14 +62,14 @@ hauler login reg.example.com -u bob -p haulin`,
|
||||
|
||||
func login(ctx context.Context, o *Opts, registry string) error {
|
||||
ropts := content.RegistryOptions{
|
||||
Username: o.Username,
|
||||
Password: o.Password,
|
||||
Username: o.Username,
|
||||
Password: o.Password,
|
||||
}
|
||||
|
||||
err := cosign.RegistryLogin(ctx, nil, registry, ropts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"fmt"
|
||||
|
||||
"github.com/rancherfederal/hauler/cmd/hauler/cli/store"
|
||||
)
|
||||
@@ -125,11 +126,11 @@ func addStoreServe() *cobra.Command {
|
||||
|
||||
// RegistryCmd serves the embedded registry
|
||||
func addStoreServeRegistry() *cobra.Command {
|
||||
o := &store.ServeRegistryOpts{RootOpts: rootStoreOpts}
|
||||
o := &store.ServeRegistryOpts{RootOpts: rootStoreOpts}
|
||||
cmd := &cobra.Command{
|
||||
Use: "registry",
|
||||
Short: "Serve the embedded registry",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "registry",
|
||||
Short: "Serve the embedded registry",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
s, err := o.Store(ctx)
|
||||
@@ -138,21 +139,21 @@ func addStoreServeRegistry() *cobra.Command {
|
||||
}
|
||||
|
||||
return store.ServeRegistryCmd(ctx, o, s)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
o.AddFlags(cmd)
|
||||
o.AddFlags(cmd)
|
||||
|
||||
return cmd
|
||||
return cmd
|
||||
}
|
||||
|
||||
// FileServerCmd serves the file server
|
||||
func addStoreServeFiles() *cobra.Command {
|
||||
o := &store.ServeFilesOpts{RootOpts: rootStoreOpts}
|
||||
o := &store.ServeFilesOpts{RootOpts: rootStoreOpts}
|
||||
cmd := &cobra.Command{
|
||||
Use: "fileserver",
|
||||
Short: "Serve the file server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Use: "fileserver",
|
||||
Short: "Serve the file server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
s, err := o.Store(ctx)
|
||||
@@ -161,12 +162,12 @@ func addStoreServeFiles() *cobra.Command {
|
||||
}
|
||||
|
||||
return store.ServeFilesCmd(ctx, o, s)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
o.AddFlags(cmd)
|
||||
o.AddFlags(cmd)
|
||||
|
||||
return cmd
|
||||
return cmd
|
||||
}
|
||||
|
||||
func addStoreSave() *cobra.Command {
|
||||
@@ -210,7 +211,7 @@ func addStoreInfo() *cobra.Command {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
for _, allowed := range allowedValues {
|
||||
if o.TypeFilter == allowed {
|
||||
return store.InfoCmd(ctx, o, s)
|
||||
|
||||
@@ -8,15 +8,13 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/file"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/file"
|
||||
"github.com/rancherfederal/hauler/pkg/content/chart"
|
||||
"github.com/rancherfederal/hauler/pkg/cosign"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type AddFileOpts struct {
|
||||
@@ -103,7 +101,7 @@ func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image, platform
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
err = cosign.SaveImage(ctx, s, r.Name(), platform)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -147,7 +145,7 @@ func AddChartCmd(ctx context.Context, o *AddChartOpts, s *store.Layout, chartNam
|
||||
func storeChart(ctx context.Context, s *store.Layout, cfg v1alpha1.Chart, opts *action.ChartPathOptions) error {
|
||||
l := log.FromContext(ctx)
|
||||
l.Infof("adding 'chart' [%s] to the store", cfg.Name)
|
||||
|
||||
|
||||
// TODO: This shouldn't be necessary
|
||||
opts.RepoURL = cfg.RepoURL
|
||||
opts.Version = cfg.Version
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"oras.land/oras-go/pkg/content"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/cosign"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type CopyOpts struct {
|
||||
@@ -55,7 +54,7 @@ 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 {
|
||||
|
||||
@@ -2,18 +2,17 @@ package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
|
||||
"github.com/rancherfederal/hauler/internal/mapper"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type ExtractOpts struct {
|
||||
@@ -37,7 +36,7 @@ func ExtractCmd(ctx context.Context, o *ExtractOpts, s *store.Layout, ref string
|
||||
|
||||
found := false
|
||||
if err := s.Walk(func(reference string, desc ocispec.Descriptor) error {
|
||||
|
||||
|
||||
if !strings.Contains(reference, r.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -4,18 +4,16 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/consts"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type InfoOpts struct {
|
||||
@@ -47,7 +45,7 @@ func InfoCmd(ctx context.Context, o *InfoOpts, s *store.Layout) error {
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
// handle multi-arch images
|
||||
// handle multi-arch images
|
||||
if desc.MediaType == consts.OCIImageIndexSchema || desc.MediaType == consts.DockerManifestListSchema2 {
|
||||
var idx ocispec.Index
|
||||
if err := json.NewDecoder(rc).Decode(&idx); err != nil {
|
||||
@@ -72,13 +70,13 @@ func InfoCmd(ctx context.Context, o *InfoOpts, s *store.Layout) error {
|
||||
items = append(items, i)
|
||||
}
|
||||
}
|
||||
// handle "non" multi-arch images
|
||||
// handle "non" multi-arch images
|
||||
} else if desc.MediaType == consts.DockerManifestSchema2 || desc.MediaType == consts.OCIManifestSchema1 {
|
||||
var m ocispec.Manifest
|
||||
if err := json.NewDecoder(rc).Decode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
rc, err := s.FetchManifest(ctx, m)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,7 +88,7 @@ func InfoCmd(ctx context.Context, o *InfoOpts, s *store.Layout) error {
|
||||
if err := json.NewDecoder(rc).Decode(&internalManifest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
if internalManifest.Architecture != "" {
|
||||
i := newItem(s, desc, m, fmt.Sprintf("%s/%s", internalManifest.OS, internalManifest.Architecture), o)
|
||||
var emptyItem item
|
||||
@@ -104,8 +102,8 @@ func InfoCmd(ctx context.Context, o *InfoOpts, s *store.Layout) error {
|
||||
items = append(items, i)
|
||||
}
|
||||
}
|
||||
// handle the rest
|
||||
} else {
|
||||
// handle the rest
|
||||
} else {
|
||||
var m ocispec.Manifest
|
||||
if err := json.NewDecoder(rc).Decode(&m); err != nil {
|
||||
return err
|
||||
@@ -144,7 +142,7 @@ func buildTable(items ...item) {
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetRowLine(false)
|
||||
table.SetAutoMergeCellsByColumnIndex([]int{0})
|
||||
|
||||
|
||||
totalSize := int64(0)
|
||||
for _, i := range items {
|
||||
if i.Type != "" {
|
||||
@@ -173,11 +171,11 @@ func buildJson(item ...item) string {
|
||||
}
|
||||
|
||||
type item struct {
|
||||
Reference string
|
||||
Type string
|
||||
Platform string
|
||||
Layers int
|
||||
Size int64
|
||||
Reference string
|
||||
Type string
|
||||
Platform string
|
||||
Layers int
|
||||
Size int64
|
||||
}
|
||||
|
||||
type byReferenceAndArch []item
|
||||
@@ -227,7 +225,7 @@ func newItem(s *store.Layout, desc ocispec.Descriptor, m ocispec.Manifest, plat
|
||||
case "dev.cosignproject.cosign/sboms":
|
||||
ctype = "sbom"
|
||||
}
|
||||
|
||||
|
||||
ref, err := reference.Parse(desc.Annotations[ocispec.AnnotationRefName])
|
||||
if err != nil {
|
||||
return item{}
|
||||
@@ -238,11 +236,11 @@ func newItem(s *store.Layout, desc ocispec.Descriptor, m ocispec.Manifest, plat
|
||||
}
|
||||
|
||||
return item{
|
||||
Reference: ref.Name(),
|
||||
Type: ctype,
|
||||
Platform: plat,
|
||||
Layers: len(m.Layers),
|
||||
Size: size,
|
||||
Reference: ref.Name(),
|
||||
Type: ctype,
|
||||
Platform: plat,
|
||||
Layers: len(m.Layers),
|
||||
Size: size,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/mholt/archiver/v3"
|
||||
"github.com/rancherfederal/hauler/pkg/content"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/content"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type LoadOpts struct {
|
||||
|
||||
@@ -14,10 +14,9 @@ import (
|
||||
"github.com/distribution/distribution/v3/version"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
|
||||
"github.com/rancherfederal/hauler/internal/server"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
)
|
||||
|
||||
type ServeRegistryOpts struct {
|
||||
@@ -26,8 +25,7 @@ type ServeRegistryOpts struct {
|
||||
Port int
|
||||
RootDir string
|
||||
ConfigFile string
|
||||
|
||||
storedir string
|
||||
ReadOnly bool
|
||||
}
|
||||
|
||||
func (o *ServeRegistryOpts) AddFlags(cmd *cobra.Command) {
|
||||
@@ -36,6 +34,7 @@ func (o *ServeRegistryOpts) AddFlags(cmd *cobra.Command) {
|
||||
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.BoolVar(&o.ReadOnly, "readonly", true, "Run the registry as readonly.")
|
||||
}
|
||||
|
||||
func ServeRegistryCmd(ctx context.Context, o *ServeRegistryOpts, s *store.Layout) error {
|
||||
@@ -80,15 +79,15 @@ type ServeFilesOpts struct {
|
||||
*RootOpts
|
||||
|
||||
Port int
|
||||
Timeout 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.IntVarP(&o.Timeout, "timeout", "t", 60, "Set the http request timeout duration in seconds for both reads and write.")
|
||||
f.StringVar(&o.RootDir, "directory", "fileserver", "Directory to use for backend. Defaults to $PWD/fileserver")
|
||||
}
|
||||
|
||||
@@ -102,8 +101,9 @@ func ServeFilesCmd(ctx context.Context, o *ServeFilesOpts, s *store.Layout) erro
|
||||
}
|
||||
|
||||
cfg := server.FileConfig{
|
||||
Root: o.RootDir,
|
||||
Port: o.Port,
|
||||
Root: o.RootDir,
|
||||
Port: o.Port,
|
||||
Timeout: o.Timeout,
|
||||
}
|
||||
|
||||
f, err := server.NewFile(ctx, cfg)
|
||||
@@ -134,9 +134,9 @@ func (o *ServeRegistryOpts) defaultRegistryConfig() *configuration.Configuration
|
||||
Storage: configuration.Storage{
|
||||
"cache": configuration.Parameters{"blobdescriptor": "inmemory"},
|
||||
"filesystem": configuration.Parameters{"rootdirectory": o.RootDir},
|
||||
|
||||
// TODO: Ensure this is toggleable via cli arg if necessary
|
||||
// "maintenance": configuration.Parameters{"readonly.enabled": false},
|
||||
"maintenance": configuration.Parameters{
|
||||
"readonly": map[any]any{"enabled": o.ReadOnly},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -27,20 +27,20 @@ import (
|
||||
|
||||
type SyncOpts struct {
|
||||
*RootOpts
|
||||
ContentFiles []string
|
||||
Key string
|
||||
Products []string
|
||||
Platform string
|
||||
Registry string
|
||||
ContentFiles []string
|
||||
Key string
|
||||
Products []string
|
||||
Platform string
|
||||
Registry string
|
||||
ProductRegistry string
|
||||
}
|
||||
|
||||
func (o *SyncOpts) AddFlags(cmd *cobra.Command) {
|
||||
f := cmd.Flags()
|
||||
|
||||
f.StringSliceVarP(&o.ContentFiles, "files", "f", []string{}, "Path to content files")
|
||||
f.StringSliceVarP(&o.ContentFiles, "files", "f", []string{}, "Path(s) to local content files (Manifests). i.e. '--files ./rke2-files.yml")
|
||||
f.StringVarP(&o.Key, "key", "k", "", "(Optional) Path to the key for signature verification")
|
||||
f.StringSliceVar(&o.Products, "products", []string{}, "Used for RGS Carbide customers to supply a product and version and Hauler will retrieve the images. i.e. '--product rancher=v2.7.6'")
|
||||
f.StringSliceVar(&o.Products, "products", []string{}, "(Optional) Feature for RGS Carbide customers to fetch collections and content from the Carbide Registry. i.e. '--product rancher=v2.8.5,rke2=v1.28.11+rke2r1'")
|
||||
f.StringVarP(&o.Platform, "platform", "p", "", "(Optional) Specific platform to save. i.e. linux/amd64. Defaults to all if flag is omitted.")
|
||||
f.StringVarP(&o.Registry, "registry", "r", "", "(Optional) Default pull registry for image refs that are not specifying a registry name.")
|
||||
f.StringVarP(&o.ProductRegistry, "product-registry", "c", "", "(Optional) Specific Product Registry to use. Defaults to RGS Carbide Registry (rgcrprod.azurecr.us).")
|
||||
@@ -70,7 +70,7 @@ func SyncCmd(ctx context.Context, o *SyncOpts, s *store.Layout) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ExtractCmd(ctx, &ExtractOpts{RootOpts: o.RootOpts}, s, fmt.Sprintf("hauler/%s-manifest.yaml:%s", parts[0],tag))
|
||||
err = ExtractCmd(ctx, &ExtractOpts{RootOpts: o.RootOpts}, s, fmt.Sprintf("hauler/%s-manifest.yaml:%s", parts[0], tag))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -151,19 +151,19 @@ func processContent(ctx context.Context, fi *os.File, o *SyncOpts, s *store.Layo
|
||||
}
|
||||
a := cfg.GetAnnotations()
|
||||
for _, i := range cfg.Spec.Images {
|
||||
|
||||
|
||||
// Check if the user provided a registry. If a registry is provided in the annotation, use it for the images that don't have a registry in their ref name.
|
||||
if a[consts.ImageAnnotationRegistry] != "" || o.Registry != ""{
|
||||
newRef,_ := reference.Parse(i.Name)
|
||||
|
||||
if a[consts.ImageAnnotationRegistry] != "" || o.Registry != "" {
|
||||
newRef, _ := reference.Parse(i.Name)
|
||||
|
||||
newReg := o.Registry // cli flag
|
||||
// if no cli flag but there was an annotation, use the annotation.
|
||||
if o.Registry == "" && a[consts.ImageAnnotationRegistry] != "" {
|
||||
newReg = a[consts.ImageAnnotationRegistry]
|
||||
}
|
||||
|
||||
|
||||
if newRef.Context().RegistryStr() == "" {
|
||||
newRef,err = reference.Relocate(i.Name, newReg)
|
||||
newRef, err = reference.Relocate(i.Name, newReg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -189,7 +189,7 @@ func processContent(ctx context.Context, fi *os.File, o *SyncOpts, s *store.Layo
|
||||
}
|
||||
}
|
||||
l.Debugf("key for image [%s]", key)
|
||||
|
||||
|
||||
// verify signature using the provided key.
|
||||
err := cosign.VerifySignature(ctx, s, key, i.Name)
|
||||
if err != nil {
|
||||
@@ -209,7 +209,7 @@ func processContent(ctx context.Context, fi *os.File, o *SyncOpts, s *store.Layo
|
||||
if i.Platform != "" {
|
||||
platform = i.Platform
|
||||
}
|
||||
|
||||
|
||||
err = storeImage(ctx, s, i, platform)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# HELM IGNORE OPTIONS:
|
||||
# Patterns to ignore when building Helm packages.
|
||||
# Supports shell glob matching, relative path matching, and negation (prefixed with !)
|
||||
|
||||
.DS_Store
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: hauler
|
||||
description: Hauler Helm Chart - Airgap Swiss Army Knife
|
||||
icon: https://raw.githubusercontent.com/rancherfederal/hauler/main/static/rgs-hauler-logo-icon.svg
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: 1.0.2
|
||||
@@ -1,33 +0,0 @@
|
||||
# Hauler Helm Chart
|
||||
|
||||
### Airgap Swiss Army Knife
|
||||
|
||||
`Rancher Government Hauler` simplifies the airgap experience without requiring operators to adopt a specific workflow. **Hauler** simplifies the airgapping process, by representing assets (images, charts, files, etc...) as content and collections to allow operators to easily fetch, store, package, and distribute these assets with declarative manifests or through the command line.
|
||||
|
||||
`Hauler` does this by storing contents and collections as OCI Artifacts and allows operators to serve contents and collections with an embedded registry and fileserver. Additionally, `Hauler` has the ability to store and inspect various non-image OCI Artifacts.
|
||||
|
||||
**GitHub Repostiory:** https://github.com/rancherfederal/hauler
|
||||
|
||||
**Documentation:** http://hauler.dev
|
||||
|
||||
---
|
||||
|
||||
| Type | Chart Version | App Version |
|
||||
| ----------- | ------------- | ----------- |
|
||||
| application | `0.1.0` | `1.0.2` |
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
```bash
|
||||
helm install hauler hauler/hauler -n hauler-system -f values.yaml
|
||||
```
|
||||
|
||||
```bash
|
||||
helm status hauler -n hauler-system
|
||||
```
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
```bash
|
||||
helm uninstall hauler -n hauler-system
|
||||
```
|
||||
@@ -1,33 +0,0 @@
|
||||
# Hauler Helm Chart
|
||||
|
||||
### Airgap Swiss Army Knife
|
||||
|
||||
`Rancher Government Hauler` simplifies the airgap experience without requiring operators to adopt a specific workflow. **Hauler** simplifies the airgapping process, by representing assets (images, charts, files, etc...) as content and collections to allow operators to easily fetch, store, package, and distribute these assets with declarative manifests or through the command line.
|
||||
|
||||
`Hauler` does this by storing contents and collections as OCI Artifacts and allows operators to serve contents and collections with an embedded registry and fileserver. Additionally, `Hauler` has the ability to store and inspect various non-image OCI Artifacts.
|
||||
|
||||
**GitHub Repostiory:** https://github.com/rancherfederal/hauler
|
||||
|
||||
**Documentation:** http://hauler.dev
|
||||
|
||||
---
|
||||
|
||||
| Type | Chart Version | App Version |
|
||||
| ----------- | ------------- | ----------- |
|
||||
| application | `0.1.0` | `1.0.2` |
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
```bash
|
||||
helm install hauler hauler/hauler -n hauler-system -f values.yaml
|
||||
```
|
||||
|
||||
```bash
|
||||
helm status hauler -n hauler-system
|
||||
```
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
```bash
|
||||
helm uninstall hauler -n hauler-system
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "hauler.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "hauler.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "hauler.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "hauler.labels" -}}
|
||||
helm.sh/chart: {{ include "hauler.chart" . }}
|
||||
{{ include "hauler.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "hauler.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "hauler.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "hauler.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "hauler.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,76 +0,0 @@
|
||||
{{- if .Values.haulerFileserver.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hauler-fileserver
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.haulerFileserver.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: hauler-fileserver
|
||||
{{- include "hauler.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hauler-fileserver
|
||||
{{- include "hauler.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- if or .Values.haulerJobs.hauls.enabled .Values.haulerJobs.manifests.enabled }}
|
||||
initContainers:
|
||||
{{- if .Values.haulerJobs.hauls.enabled }}
|
||||
- name: wait-for-hauler-hauls-job
|
||||
image: {{ .Values.hauler.initContainers.image.repository }}:{{ .Values.hauler.initContainers.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.initContainers.imagePullPolicy }}
|
||||
args: ["wait", "--for=condition=complete", "job", "hauler-hauls-job", "--namespace", "{{ .Release.Namespace }}", "--timeout={{ .Values.hauler.initContainers.timeout }}"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- end }}
|
||||
{{- if .Values.haulerJobs.manifests.enabled }}
|
||||
- name: wait-for-hauler-manifests-job
|
||||
image: {{ .Values.hauler.initContainers.image.repository }}:{{ .Values.hauler.initContainers.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.initContainers.imagePullPolicy }}
|
||||
args: ["wait", "--for=condition=complete", "job", "hauler-manifests-job", "--namespace", "{{ .Release.Namespace }}", "--timeout={{ .Values.hauler.initContainers.timeout }}"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: hauler-fileserver
|
||||
image: {{ .Values.hauler.image.repository }}:{{ .Values.hauler.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.imagePullPolicy }}
|
||||
args: ["store", "serve", "fileserver", "--port", "{{ .Values.haulerFileserver.port }}"]
|
||||
ports:
|
||||
- containerPort: {{ .Values.haulerFileserver.port }}
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /store
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
restartPolicy: Always
|
||||
serviceAccountName: hauler-service-account
|
||||
volumes:
|
||||
- name: hauler-data
|
||||
persistentVolumeClaim:
|
||||
claimName: hauler-data
|
||||
{{- end }}
|
||||
@@ -1,27 +0,0 @@
|
||||
{{- if and .Values.haulerFileserver.enabled .Values.haulerFileserver.ingress.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: hauler-fileserver
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .Values.haulerFileserver.ingress.hostname }}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: hauler-fileserver
|
||||
port:
|
||||
number: {{ .Values.haulerFileserver.service.ports.targetPort }}
|
||||
path: /
|
||||
pathType: Prefix
|
||||
{{- if .Values.haulerFileserver.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.haulerFileserver.ingress.hostname }}
|
||||
secretName: {{ .Values.haulerFileserver.ingress.tls.secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,18 +0,0 @@
|
||||
{{- if and .Values.haulerFileserver.enabled .Values.haulerFileserver.service.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hauler-fileserver
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
app: hauler-fileserver
|
||||
ports:
|
||||
- name: hauler-fileserver
|
||||
protocol: {{ .Values.haulerFileserver.service.ports.protocol }}
|
||||
port: {{ .Values.haulerFileserver.service.ports.port }}
|
||||
targetPort: {{ .Values.haulerFileserver.service.ports.targetPort }}
|
||||
type: {{ .Values.haulerFileserver.service.type }}
|
||||
{{- end }}
|
||||
@@ -1,76 +0,0 @@
|
||||
{{- if .Values.haulerRegistry.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hauler-registry
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.haulerRegistry.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: hauler-registry
|
||||
{{- include "hauler.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hauler-registry
|
||||
{{- include "hauler.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- if or .Values.haulerJobs.hauls.enabled .Values.haulerJobs.manifests.enabled }}
|
||||
initContainers:
|
||||
{{- if .Values.haulerJobs.hauls.enabled }}
|
||||
- name: wait-for-hauler-hauls-job
|
||||
image: {{ .Values.hauler.initContainers.image.repository }}:{{ .Values.hauler.initContainers.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.initContainers.imagePullPolicy }}
|
||||
args: ["wait", "--for=condition=complete", "job", "hauler-hauls-job", "--namespace", "{{ .Release.Namespace }}", "--timeout={{ .Values.hauler.initContainers.timeout }}"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- end }}
|
||||
{{- if .Values.haulerJobs.manifests.enabled }}
|
||||
- name: wait-for-hauler-manifests-job
|
||||
image: {{ .Values.hauler.initContainers.image.repository }}:{{ .Values.hauler.initContainers.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.initContainers.imagePullPolicy }}
|
||||
args: ["wait", "--for=condition=complete", "job", "hauler-manifests-job", "--namespace", "{{ .Release.Namespace }}", "--timeout={{ .Values.hauler.initContainers.timeout }}"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: hauler-registry
|
||||
image: {{ .Values.hauler.image.repository }}:{{ .Values.hauler.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.imagePullPolicy }}
|
||||
args: ["store", "serve", "registry", "--port", "{{ .Values.haulerRegistry.port }}"]
|
||||
ports:
|
||||
- containerPort: {{ .Values.haulerRegistry.port }}
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /store
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
restartPolicy: Always
|
||||
serviceAccountName: hauler-service-account
|
||||
volumes:
|
||||
- name: hauler-data
|
||||
persistentVolumeClaim:
|
||||
claimName: hauler-data
|
||||
{{- end }}
|
||||
@@ -1,28 +0,0 @@
|
||||
{{- if and .Values.haulerRegistry.enabled .Values.haulerRegistry.ingress.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: hauler-registry
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .Values.haulerRegistry.ingress.hostname }}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: hauler-registry
|
||||
port:
|
||||
number: {{ .Values.haulerRegistry.service.ports.targetPort }}
|
||||
path: /
|
||||
pathType: Prefix
|
||||
{{- if .Values.haulerRegistry.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.haulerRegistry.ingress.hostname }}
|
||||
secretName: {{ .Values.haulerRegistry.ingress.tls.secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{{- if and .Values.haulerRegistry.enabled .Values.haulerRegistry.service.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hauler-registry
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
app: hauler-registry
|
||||
ports:
|
||||
- name: hauler-registry
|
||||
protocol: {{ .Values.haulerRegistry.service.ports.protocol }}
|
||||
port: {{ .Values.haulerRegistry.service.ports.port }}
|
||||
targetPort: {{ .Values.haulerRegistry.service.ports.targetPort }}
|
||||
type: {{ .Values.haulerRegistry.service.type }}
|
||||
{{- end }}
|
||||
@@ -1,126 +0,0 @@
|
||||
{{- if .Values.haulerJobs.hauls.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: hauler-hauls-job
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: hauler-fetch-hauls
|
||||
image: {{ .Values.haulerJobs.image.repository }}:{{ .Values.haulerJobs.image.tag }}
|
||||
imagePullPolicy: {{ .Values.haulerJobs.imagePullPolicy }}
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{- range .Values.haulerJobs.hauls.artifacts }}
|
||||
curl -o /hauls/{{ .name }} {{ .path }} &&
|
||||
{{- end }}
|
||||
echo hauler fetch completed
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /hauls
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: hauler-load-hauls
|
||||
image: {{ .Values.hauler.image.repository }}:{{ .Values.hauler.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.imagePullPolicy }}
|
||||
args:
|
||||
- "store"
|
||||
- "load"
|
||||
{{- range .Values.haulerJobs.hauls.artifacts }}
|
||||
- "/hauls/{{ .name }}"
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /hauls
|
||||
- name: hauler-data
|
||||
mountPath: /store
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: hauler-data
|
||||
persistentVolumeClaim:
|
||||
claimName: hauler-data
|
||||
{{- end }}
|
||||
---
|
||||
{{- if .Values.haulerJobs.manifests.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: hauler-manifests-job
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: hauler-fetch-manifests
|
||||
image: {{ .Values.haulerJobs.image.repository }}:{{ .Values.haulerJobs.image.tag }}
|
||||
imagePullPolicy: {{ .Values.haulerJobs.imagePullPolicy }}
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{- range .Values.haulerJobs.manifests.artifacts }}
|
||||
curl -o /manifests/{{ .name }} {{ .path }} &&
|
||||
{{- end }}
|
||||
echo hauler fetch completed
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /manifests
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: hauler-load-manifests
|
||||
image: {{ .Values.hauler.image.repository }}:{{ .Values.hauler.image.tag }}
|
||||
imagePullPolicy: {{ .Values.hauler.imagePullPolicy }}
|
||||
args:
|
||||
{{- range .Values.haulerJobs.manifests.artifacts }}
|
||||
- "store"
|
||||
- "sync"
|
||||
- "--files"
|
||||
- "/manifests/{{ .name }}"
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: hauler-data
|
||||
mountPath: /manifests
|
||||
- name: hauler-data
|
||||
mountPath: /store
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: hauler-data
|
||||
persistentVolumeClaim:
|
||||
claimName: hauler-data
|
||||
{{- end }}
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: hauler-data
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.hauler.data.pvc.accessModes }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.hauler.data.pvc.storageRequest }}
|
||||
{{- if .Values.hauler.data.pvc.storageClass }}
|
||||
storageClassName: {{ .Values.hauler.data.pvc.storageClass }}
|
||||
{{- end }}
|
||||
@@ -1,35 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: hauler-service-account
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: hauler-role
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups: ["batch"]
|
||||
resources: ["jobs"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: hauler-role-binding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "hauler.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: hauler-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: hauler-service-account
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -1,94 +0,0 @@
|
||||
# Helm Chart Values for Hauler
|
||||
# Docs: https://hauler.dev
|
||||
|
||||
hauler:
|
||||
image:
|
||||
repository: ghcr.io/rancherfederal/hauler
|
||||
tag: v1.0.2
|
||||
imagePullPolicy: Always
|
||||
|
||||
initContainers:
|
||||
image:
|
||||
repository: rancher/kubectl
|
||||
tag: v1.27.0 # update to your kubernetes version
|
||||
imagePullPolicy: Always
|
||||
timeout: 1h
|
||||
|
||||
data:
|
||||
pvc:
|
||||
accessModes: ReadWriteMany
|
||||
storageClass: longhorn # optional... will use default storage class
|
||||
storageRequest: 48Gi # recommended size of 3x the artifact(s)
|
||||
|
||||
# Helm Chart Values for the Hauler Jobs
|
||||
# Docs: https://rancherfederal.github.io/hauler-docs/docs/introduction/quickstart
|
||||
|
||||
haulerJobs:
|
||||
image:
|
||||
repository: rancher/shell
|
||||
tag: v0.1.22
|
||||
imagePullPolicy: Always
|
||||
|
||||
hauls:
|
||||
enabled: true
|
||||
artifacts:
|
||||
- path: https://raw.githubusercontent.com/rancherfederal/hauler/main/testdata/haul.tar.zst
|
||||
name: haul.tar.zst
|
||||
# - path: /path/to/additional-hauls.tar.zst
|
||||
# name: additional-hauls.tar.zst
|
||||
|
||||
manifests:
|
||||
enabled: true
|
||||
artifacts:
|
||||
- path: https://raw.githubusercontent.com/rancherfederal/hauler/main/testdata/hauler-manifest.yaml
|
||||
name: hauler-manifest.yaml
|
||||
# - path: /path/to/additional-manifests.yaml
|
||||
# name: additional-manifests.yaml
|
||||
|
||||
# Helm Chart Values for the Hauler Fileserver
|
||||
# Docs: https://rancherfederal.github.io/hauler-docs/docs/guides-references/command-line/hauler-store#hauler-store-serve-fileserver
|
||||
|
||||
haulerFileserver:
|
||||
enabled: true
|
||||
port: 8080 # default port for the fileserver
|
||||
replicas: 1
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
hostname: fileserver.ranchers.io
|
||||
tls:
|
||||
enabled: true
|
||||
source: secret # only supported source
|
||||
secretName: tls-certs # must be created outside of this chart
|
||||
|
||||
service:
|
||||
enabled: true
|
||||
type: ClusterIP
|
||||
ports:
|
||||
protocol: TCP
|
||||
port: 8080 # default port for the fileserver
|
||||
targetPort: 8080 # default port for the fileserver
|
||||
|
||||
# Helm Chart Values for the Hauler Registry
|
||||
# Docs: https://rancherfederal.github.io/hauler-docs/docs/guides-references/command-line/hauler-store#hauler-store-serve-registry
|
||||
|
||||
haulerRegistry:
|
||||
enabled: true
|
||||
port: 5000 # default port for the registry
|
||||
replicas: 1
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
hostname: registry.ranchers.io
|
||||
tls:
|
||||
enabled: true
|
||||
source: secret # only supported source
|
||||
secretName: tls-certs # must be created outside of this chart
|
||||
|
||||
service:
|
||||
enabled: true
|
||||
type: ClusterIP
|
||||
ports:
|
||||
protocol: TCP
|
||||
port: 5000 # default port for the registry
|
||||
targetPort: 5000 # default port for the registry
|
||||
2
go.mod
2
go.mod
@@ -54,7 +54,7 @@ require (
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/docker/cli v25.0.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v25.0.5+incompatible // indirect
|
||||
github.com/docker/docker v25.0.6+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -129,8 +129,8 @@ github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbT
|
||||
github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
||||
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
|
||||
github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
|
||||
190
install.sh
190
install.sh
@@ -13,15 +13,23 @@
|
||||
# - curl -sfL https://get.hauler.dev | HAULER_VERSION=1.0.0 bash
|
||||
# - HAULER_VERSION=1.0.0 ./install.sh
|
||||
#
|
||||
# Set Install Directory
|
||||
# - curl -sfL https://get.hauler.dev | HAULER_INSTALL_DIR=/usr/local/bin bash
|
||||
# - HAULER_INSTALL_DIR=/usr/local/bin ./install.sh
|
||||
#
|
||||
# Debug Usage:
|
||||
# - curl -sfL https://get.hauler.dev | HAULER_DEBUG=true bash
|
||||
# - HAULER_DEBUG=true ./install.sh
|
||||
#
|
||||
# Uninstall Usage:
|
||||
# - curl -sfL https://get.hauler.dev | HAULER_UNINSTALL=true bash
|
||||
# - HAULER_UNINSTALL=true ./install.sh
|
||||
#
|
||||
# Documentation:
|
||||
# - https://hauler.dev
|
||||
# - https://github.com/rancherfederal/hauler
|
||||
# - https://github.com/hauler-dev/hauler
|
||||
|
||||
# set functions for debugging/logging
|
||||
# set functions for logging
|
||||
function verbose {
|
||||
echo "$1"
|
||||
}
|
||||
@@ -36,60 +44,87 @@ function warn {
|
||||
|
||||
function fatal {
|
||||
echo && echo "[ERROR] Hauler: $1"
|
||||
exit 0
|
||||
exit 1
|
||||
}
|
||||
|
||||
# check for required dependencies
|
||||
for cmd in sudo rm curl grep mkdir sed awk openssl tar; do
|
||||
# debug hauler from argument or environment variable
|
||||
if [ "${HAULER_DEBUG}" = "true" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# start hauler preflight checks
|
||||
info "Starting Preflight Checks..."
|
||||
|
||||
# check for required packages and dependencies
|
||||
for cmd in echo curl grep sed rm mkdir awk openssl tar install source; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
fatal "$cmd is not installed"
|
||||
fatal "$cmd is required to install Hauler"
|
||||
fi
|
||||
done
|
||||
|
||||
# set version environment variable
|
||||
if [ -z "${HAULER_VERSION}" ]; then
|
||||
version="${HAULER_VERSION:-$(curl -s https://api.github.com/repos/rancherfederal/hauler/releases/latest | grep '"tag_name":' | sed 's/.*"v\([^"]*\)".*/\1/')}"
|
||||
else
|
||||
version="${HAULER_VERSION}"
|
||||
# set install directory from argument or environment variable
|
||||
HAULER_INSTALL_DIR=${HAULER_INSTALL_DIR:-/usr/local/bin}
|
||||
|
||||
# ensure install directory exists
|
||||
if [ ! -d "${HAULER_INSTALL_DIR}" ]; then
|
||||
mkdir -p "${HAULER_INSTALL_DIR}" || fatal "Failed to Create Install Directory: ${HAULER_INSTALL_DIR}"
|
||||
fi
|
||||
|
||||
# set uninstall environment variable from argument or environment
|
||||
# ensure install directory is writable (by user or root privileges)
|
||||
if [ ! -w "${HAULER_INSTALL_DIR}" ]; then
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
fatal "Root privileges are required to install Hauler to Directory: ${HAULER_INSTALL_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# uninstall hauler from argument or environment variable
|
||||
if [ "${HAULER_UNINSTALL}" = "true" ]; then
|
||||
# remove the hauler binary
|
||||
sudo rm -f /usr/local/bin/hauler || fatal "Failed to Remove Hauler from /usr/local/bin"
|
||||
rm -rf "${HAULER_INSTALL_DIR}/hauler" || fatal "Failed to Remove Hauler from ${HAULER_INSTALL_DIR}"
|
||||
|
||||
# remove the installation directory
|
||||
rm -rf "$HOME/.hauler" || fatal "Failed to Remove Directory: $HOME/.hauler"
|
||||
# remove the working directory
|
||||
rm -rf "$HOME/.hauler" || fatal "Failed to Remove Hauler Directory: $HOME/.hauler"
|
||||
|
||||
info "Hauler Uninstalled Successfully"
|
||||
info "Successfully Uninstalled Hauler" && echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# set version environment variable
|
||||
if [ -z "${HAULER_VERSION}" ]; then
|
||||
# attempt to retrieve the latest version from GitHub
|
||||
HAULER_VERSION=$(curl -s https://api.github.com/repos/hauler-dev/hauler/releases/latest | grep '"tag_name":' | sed 's/.*"v\([^"]*\)".*/\1/')
|
||||
|
||||
# exit if the version could not be detected
|
||||
if [ -z "${HAULER_VERSION}" ]; then
|
||||
fatal "HAULER_VERSION is unable to be detected and/or retrieved from GitHub"
|
||||
fi
|
||||
fi
|
||||
|
||||
# detect the operating system
|
||||
platform=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
case $platform in
|
||||
PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
case $PLATFORM in
|
||||
linux)
|
||||
platform="linux"
|
||||
PLATFORM="linux"
|
||||
;;
|
||||
darwin)
|
||||
platform="darwin"
|
||||
PLATFORM="darwin"
|
||||
;;
|
||||
*)
|
||||
fatal "Unsupported Platform: $platform"
|
||||
fatal "Unsupported Platform: $PLATFORM"
|
||||
;;
|
||||
esac
|
||||
|
||||
# detect the architecture
|
||||
arch=$(uname -m)
|
||||
case $arch in
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
x86_64 | x86-32 | x64 | x32 | amd64)
|
||||
arch="amd64"
|
||||
ARCH="amd64"
|
||||
;;
|
||||
aarch64 | arm64)
|
||||
arch="arm64"
|
||||
ARCH="arm64"
|
||||
;;
|
||||
*)
|
||||
fatal "Unsupported Architecture: $arch"
|
||||
fatal "Unsupported Architecture: $ARCH"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -97,85 +132,84 @@ esac
|
||||
info "Starting Installation..."
|
||||
|
||||
# display the version, platform, and architecture
|
||||
verbose "- Version: v$version"
|
||||
verbose "- Platform: $platform"
|
||||
verbose "- Architecture: $arch"
|
||||
verbose "- Version: v${HAULER_VERSION}"
|
||||
verbose "- Platform: $PLATFORM"
|
||||
verbose "- Architecture: $ARCH"
|
||||
verbose "- Install Directory: ${HAULER_INSTALL_DIR}"
|
||||
|
||||
# check if install directory exists, create it if not
|
||||
# check working directory and/or create it
|
||||
if [ ! -d "$HOME/.hauler" ]; then
|
||||
mkdir -p "$HOME/.hauler" || fatal "Failed to Create Directory: ~/.hauler"
|
||||
mkdir -p "$HOME/.hauler" || fatal "Failed to Create Directory: $HOME/.hauler"
|
||||
fi
|
||||
|
||||
# change to install directory
|
||||
cd "$HOME/.hauler" || fatal "Failed to Change Directory: ~/.hauler"
|
||||
# update permissions of working directory
|
||||
chmod -R 777 "$HOME/.hauler" || fatal "Failed to Update Permissions of Directory: $HOME/.hauler"
|
||||
|
||||
# change to working directory
|
||||
cd "$HOME/.hauler" || fatal "Failed to Change Directory: $HOME/.hauler"
|
||||
|
||||
# start hauler artifacts download
|
||||
info "Starting Download..."
|
||||
|
||||
# download the checksum file
|
||||
if ! curl -sfOL "https://github.com/rancherfederal/hauler/releases/download/v${version}/hauler_${version}_checksums.txt"; then
|
||||
fatal "Failed to Download: hauler_${version}_checksums.txt"
|
||||
if ! curl -sfOL "https://github.com/hauler-dev/hauler/releases/download/v${HAULER_VERSION}/hauler_${HAULER_VERSION}_checksums.txt"; then
|
||||
fatal "Failed to Download: hauler_${HAULER_VERSION}_checksums.txt"
|
||||
fi
|
||||
|
||||
# download the archive file
|
||||
if ! curl -sfOL "https://github.com/rancherfederal/hauler/releases/download/v${version}/hauler_${version}_${platform}_${arch}.tar.gz"; then
|
||||
fatal "Failed to Download: hauler_${version}_${platform}_${arch}.tar.gz"
|
||||
if ! curl -sfOL "https://github.com/hauler-dev/hauler/releases/download/v${HAULER_VERSION}/hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"; then
|
||||
fatal "Failed to Download: hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"
|
||||
fi
|
||||
|
||||
# start hauler checksum verification
|
||||
info "Starting Checksum Verification..."
|
||||
|
||||
# verify the Hauler checksum
|
||||
expected_checksum=$(awk -v version="$version" -v platform="$platform" -v arch="$arch" '$2 == "hauler_"version"_"platform"_"arch".tar.gz" {print $1}' "hauler_${version}_checksums.txt")
|
||||
determined_checksum=$(openssl dgst -sha256 "hauler_${version}_${platform}_${arch}.tar.gz" | awk '{print $2}')
|
||||
EXPECTED_CHECKSUM=$(awk -v HAULER_VERSION="${HAULER_VERSION}" -v PLATFORM="${PLATFORM}" -v ARCH="${ARCH}" '$2 == "hauler_"HAULER_VERSION"_"PLATFORM"_"ARCH".tar.gz" {print $1}' "hauler_${HAULER_VERSION}_checksums.txt")
|
||||
DETERMINED_CHECKSUM=$(openssl dgst -sha256 "hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz" | awk '{print $2}')
|
||||
|
||||
if [ -z "$expected_checksum" ]; then
|
||||
fatal "Failed to Locate Checksum: hauler_${version}_${platform}_${arch}.tar.gz"
|
||||
elif [ "$determined_checksum" = "$expected_checksum" ]; then
|
||||
verbose "- Expected Checksum: $expected_checksum"
|
||||
verbose "- Determined Checksum: $determined_checksum"
|
||||
verbose "- Successfully Verified Checksum: hauler_${version}_${platform}_${arch}.tar.gz"
|
||||
if [ -z "${EXPECTED_CHECKSUM}" ]; then
|
||||
fatal "Failed to Locate Checksum: hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"
|
||||
elif [ "${DETERMINED_CHECKSUM}" = "${EXPECTED_CHECKSUM}" ]; then
|
||||
verbose "- Expected Checksum: ${EXPECTED_CHECKSUM}"
|
||||
verbose "- Determined Checksum: ${DETERMINED_CHECKSUM}"
|
||||
verbose "- Successfully Verified Checksum: hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"
|
||||
else
|
||||
verbose "- Expected: $expected_checksum"
|
||||
verbose "- Determined: $determined_checksum"
|
||||
fatal "Failed Checksum Verification: hauler_${version}_${platform}_${arch}.tar.gz"
|
||||
verbose "- Expected: ${EXPECTED_CHECKSUM}"
|
||||
verbose "- Determined: ${DETERMINED_CHECKSUM}"
|
||||
fatal "Failed Checksum Verification: hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"
|
||||
fi
|
||||
|
||||
# uncompress the archive
|
||||
tar -xzf "hauler_${version}_${platform}_${arch}.tar.gz" || fatal "Failed to Extract: hauler_${version}_${platform}_${arch}.tar.gz"
|
||||
# uncompress the hauler archive
|
||||
tar -xzf "hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz" || fatal "Failed to Extract: hauler_${HAULER_VERSION}_${PLATFORM}_${ARCH}.tar.gz"
|
||||
|
||||
# install the binary
|
||||
case "$platform" in
|
||||
linux)
|
||||
sudo install -m 755 hauler /usr/local/bin || fatal "Failed to Install Hauler to /usr/local/bin"
|
||||
;;
|
||||
darwin)
|
||||
sudo install -m 755 hauler /usr/local/bin || fatal "Failed to Install Hauler to /usr/local/bin"
|
||||
;;
|
||||
*)
|
||||
fatal "Unsupported Platform or Architecture: $platform/$arch"
|
||||
;;
|
||||
esac
|
||||
# install the hauler binary
|
||||
install -m 755 hauler "${HAULER_INSTALL_DIR}" || fatal "Failed to Install Hauler: ${HAULER_INSTALL_DIR}"
|
||||
|
||||
# add hauler to the path
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
echo "export PATH=$PATH:/usr/local/bin/" >> "$HOME/.bashrc"
|
||||
source "$HOME/.bashrc"
|
||||
elif [ -f "$HOME/.bash_profile" ]; then
|
||||
echo "export PATH=$PATH:/usr/local/bin/" >> "$HOME/.bash_profile"
|
||||
source "$HOME/.bash_profile"
|
||||
elif [ -f "$HOME/.zshrc" ]; then
|
||||
echo "export PATH=$PATH:/usr/local/bin/" >> "$HOME/.zshrc"
|
||||
source "$HOME/.zshrc"
|
||||
elif [ -f "$HOME/.profile" ]; then
|
||||
echo "export PATH=$PATH:/usr/local/bin/" >> "$HOME/.profile"
|
||||
source "$HOME/.profile"
|
||||
else
|
||||
echo "Failed to add /usr/local/bin to PATH: Unsupported Shell"
|
||||
if [[ ":$PATH:" != *":${HAULER_INSTALL_DIR}:"* ]]; then
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
echo "export PATH=\$PATH:${HAULER_INSTALL_DIR}" >> "$HOME/.bashrc"
|
||||
source "$HOME/.bashrc"
|
||||
elif [ -f "$HOME/.bash_profile" ]; then
|
||||
echo "export PATH=\$PATH:${HAULER_INSTALL_DIR}" >> "$HOME/.bash_profile"
|
||||
source "$HOME/.bash_profile"
|
||||
elif [ -f "$HOME/.zshrc" ]; then
|
||||
echo "export PATH=\$PATH:${HAULER_INSTALL_DIR}" >> "$HOME/.zshrc"
|
||||
source "$HOME/.zshrc"
|
||||
elif [ -f "$HOME/.profile" ]; then
|
||||
echo "export PATH=\$PATH:${HAULER_INSTALL_DIR}" >> "$HOME/.profile"
|
||||
source "$HOME/.profile"
|
||||
else
|
||||
warn "Failed to add ${HAULER_INSTALL_DIR} to PATH: Unsupported Shell"
|
||||
fi
|
||||
fi
|
||||
|
||||
# display success message
|
||||
info "Successfully Installed at /usr/local/bin/hauler"
|
||||
info "Successfully Installed Hauler at ${HAULER_INSTALL_DIR}/hauler"
|
||||
|
||||
# display availability message
|
||||
verbose "- Hauler v${version} is now available for use!"
|
||||
info "Hauler v${HAULER_VERSION} is now available for use!"
|
||||
|
||||
# display hauler docs message
|
||||
verbose "- Documentation: https://hauler.dev" && echo
|
||||
|
||||
@@ -2,7 +2,7 @@ package mapper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -15,7 +15,8 @@ import (
|
||||
)
|
||||
|
||||
// NewMapperFileStore creates a new file store that uses mapper functions for each detected descriptor.
|
||||
// This extends content.File, and differs in that it allows much more functionality into how each descriptor is written.
|
||||
//
|
||||
// This extends content.File, and differs in that it allows much more functionality into how each descriptor is written.
|
||||
func NewMapperFileStore(root string, mapper map[string]Fn) *store {
|
||||
fs := content.NewFile(root)
|
||||
return &store{
|
||||
@@ -58,7 +59,7 @@ func (s *pusher) Push(ctx context.Context, desc ocispec.Descriptor) (ccontent.Wr
|
||||
|
||||
// If no custom mapper found, fall back to content.File mapper
|
||||
if _, ok := s.mapper[desc.MediaType]; !ok {
|
||||
return content.NewIoContentWriter(ioutil.Discard, content.WithOutputHash(desc.Digest)), nil
|
||||
return content.NewIoContentWriter(io.Discard, content.WithOutputHash(desc.Digest)), nil
|
||||
}
|
||||
|
||||
filename, err := s.mapper[desc.MediaType](desc)
|
||||
|
||||
@@ -12,9 +12,10 @@ import (
|
||||
)
|
||||
|
||||
type FileConfig struct {
|
||||
Root string
|
||||
Host string
|
||||
Port int
|
||||
Root string
|
||||
Host string
|
||||
Port int
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// NewFile returns a fileserver
|
||||
@@ -30,11 +31,15 @@ func NewFile(ctx context.Context, cfg FileConfig) (Server, error) {
|
||||
cfg.Port = 8080
|
||||
}
|
||||
|
||||
if cfg.Timeout == 0 {
|
||||
cfg.Timeout = 60
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: r,
|
||||
Addr: fmt.Sprintf(":%d", cfg.Port),
|
||||
WriteTimeout: 15 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: time.Duration(cfg.Timeout) * time.Second,
|
||||
ReadTimeout: time.Duration(cfg.Timeout) * time.Second,
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewTempRegistry(ctx context.Context, root string) *tmpRegistryServer {
|
||||
}
|
||||
// Add validation configuration
|
||||
cfg.Validation.Manifests.URLs.Allow = []string{".+"}
|
||||
|
||||
|
||||
cfg.Log.Level = "error"
|
||||
cfg.HTTP.Headers = http.Header{
|
||||
"X-Content-Type-Options": []string{"nosniff"},
|
||||
|
||||
@@ -226,4 +226,4 @@ func (i *Info) CheckFontName(fontName string) bool {
|
||||
|
||||
fmt.Fprintln(os.Stderr, "font not valid, using default")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type ImageSpec struct {
|
||||
type Image struct {
|
||||
// Name is the full location for the image, can be referenced by tags or digests
|
||||
Name string `json:"name"`
|
||||
|
||||
|
||||
// Path is the path to the cosign public key used for verifying image signatures
|
||||
//Key string `json:"key,omitempty"`
|
||||
Key string `json:"key"`
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const K3sCollectionKind = "K3s"
|
||||
|
||||
|
||||
@@ -54,27 +54,27 @@ func NewImage(name string, opts ...remote.Option) (*Image, error) {
|
||||
}
|
||||
|
||||
func IsMultiArchImage(name string, opts ...remote.Option) (bool, error) {
|
||||
ref, err := gname.ParseReference(name)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("parsing reference %q: %v", name, err)
|
||||
}
|
||||
ref, err := gname.ParseReference(name)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("parsing reference %q: %v", name, err)
|
||||
}
|
||||
|
||||
defaultOpts := []remote.Option{
|
||||
remote.WithAuthFromKeychain(authn.DefaultKeychain),
|
||||
}
|
||||
opts = append(opts, defaultOpts...)
|
||||
|
||||
desc, err := remote.Get(ref, opts...)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("getting image %q: %v", name, err)
|
||||
}
|
||||
desc, err := remote.Get(ref, opts...)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("getting image %q: %v", name, err)
|
||||
}
|
||||
|
||||
_, err = desc.ImageIndex()
|
||||
if err != nil {
|
||||
// If the descriptor could not be converted to an image index, it's not a multi-arch image
|
||||
return false, nil
|
||||
}
|
||||
_, err = desc.ImageIndex()
|
||||
if err != nil {
|
||||
// If the descriptor could not be converted to an image index, it's not a multi-arch image
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// If the descriptor could be converted to an image index, it's a multi-arch image
|
||||
return true, nil
|
||||
}
|
||||
// If the descriptor could be converted to an image index, it's a multi-arch image
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package artifacts
|
||||
import "github.com/google/go-containerregistry/pkg/v1"
|
||||
|
||||
// OCI is the bare minimum we need to represent an artifact in an oci layout
|
||||
// At a high level, it is not constrained by an Image's config, manifests, and layer ordinality
|
||||
// This specific implementation fully encapsulates v1.Layer's within a more generic form
|
||||
//
|
||||
// At a high level, it is not constrained by an Image's config, manifests, and layer ordinality
|
||||
// This specific implementation fully encapsulates v1.Layer's within a more generic form
|
||||
type OCI interface {
|
||||
MediaType() string
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package chart
|
||||
|
||||
import (
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/apis/hauler.cattle.io/v1alpha1"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
"github.com/rancherfederal/hauler/pkg/content/chart"
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
)
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
artifact "github.com/rancherfederal/hauler/pkg/artifacts"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/file/getter"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
)
|
||||
|
||||
type ImageTxt struct {
|
||||
|
||||
@@ -11,12 +11,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/file"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/file/getter"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
)
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ const (
|
||||
KindAnnotationName = "kind"
|
||||
KindAnnotation = "dev.cosignproject.cosign/image"
|
||||
|
||||
CarbideRegistry = "rgcrprod.azurecr.us"
|
||||
ImageAnnotationKey = "hauler.dev/key"
|
||||
CarbideRegistry = "rgcrprod.azurecr.us"
|
||||
ImageAnnotationKey = "hauler.dev/key"
|
||||
ImageAnnotationPlatform = "hauler.dev/platform"
|
||||
ImageAnnotationRegistry = "hauler.dev/registry"
|
||||
)
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -15,17 +17,21 @@ import (
|
||||
gtypes "github.com/google/go-containerregistry/pkg/v1/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/layer"
|
||||
"helm.sh/helm/v3/pkg/registry"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/consts"
|
||||
"github.com/rancherfederal/hauler/pkg/layer"
|
||||
)
|
||||
|
||||
var _ artifacts.OCI = (*Chart)(nil)
|
||||
var (
|
||||
_ artifacts.OCI = (*Chart)(nil)
|
||||
settings = cli.New()
|
||||
)
|
||||
|
||||
// Chart implements the OCI interface for Chart API objects. API spec values are
|
||||
// stored into the Repo, Name, and Version fields.
|
||||
@@ -36,22 +42,31 @@ type Chart struct {
|
||||
|
||||
// NewChart is a helper method that returns NewLocalChart or NewRemoteChart depending on v1alpha1.Chart contents
|
||||
func NewChart(name string, opts *action.ChartPathOptions) (*Chart, error) {
|
||||
cpo := action.ChartPathOptions{
|
||||
RepoURL: opts.RepoURL,
|
||||
Version: opts.Version,
|
||||
|
||||
CaFile: opts.CaFile,
|
||||
CertFile: opts.CertFile,
|
||||
KeyFile: opts.KeyFile,
|
||||
InsecureSkipTLSverify: opts.InsecureSkipTLSverify,
|
||||
Keyring: opts.Keyring,
|
||||
Password: opts.Password,
|
||||
PassCredentialsAll: opts.PassCredentialsAll,
|
||||
Username: opts.Username,
|
||||
Verify: opts.Verify,
|
||||
chartRef := name
|
||||
actionConfig := new(action.Configuration)
|
||||
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), log.NewLogger(os.Stdout).Debugf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chartPath, err := cpo.LocateChart(name, cli.New())
|
||||
client := action.NewInstall(actionConfig)
|
||||
client.ChartPathOptions.Version = opts.Version
|
||||
|
||||
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
|
||||
client.InsecureSkipTLSverify, client.PlainHTTP)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("missing registry client: %w", err)
|
||||
}
|
||||
|
||||
client.SetRegistryClient(registryClient)
|
||||
if registry.IsOCI(opts.RepoURL) {
|
||||
chartRef = opts.RepoURL + "/" + name
|
||||
} else if isUrl(opts.RepoURL) { // OCI Protocol registers as a valid URL
|
||||
client.ChartPathOptions.RepoURL = opts.RepoURL
|
||||
} else { // Handles cases like grafana/loki
|
||||
chartRef = opts.RepoURL + "/" + name
|
||||
}
|
||||
|
||||
chartPath, err := client.ChartPathOptions.LocateChart(chartRef, settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -217,3 +232,52 @@ func (h *Chart) chartData() (gv1.Layer, error) {
|
||||
|
||||
return chartDataLayer, err
|
||||
}
|
||||
func isUrl(name string) bool {
|
||||
_, err := url.ParseRequestURI(name)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool) (*registry.Client, error) {
|
||||
if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify {
|
||||
registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
}
|
||||
registryClient, err := newDefaultRegistryClient(plainHTTP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) {
|
||||
opts := []registry.ClientOption{
|
||||
registry.ClientOptDebug(settings.Debug),
|
||||
registry.ClientOptEnableCache(true),
|
||||
registry.ClientOptWriter(os.Stderr),
|
||||
registry.ClientOptCredentialsFile(settings.RegistryConfig),
|
||||
}
|
||||
if plainHTTP {
|
||||
opts = append(opts, registry.ClientOptPlainHTTP())
|
||||
}
|
||||
|
||||
// Create a new registry client
|
||||
registryClient, err := registry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
func newRegistryClientWithTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) {
|
||||
// Create a new registry client
|
||||
registryClient, err := registry.NewRegistryClientWithTLS(os.Stderr, certFile, keyFile, caFile, insecureSkipTLSverify,
|
||||
settings.RegistryConfig, settings.Debug,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
@@ -6,19 +6,13 @@ import (
|
||||
"testing"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/mholt/archiver/v3"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/consts"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/content/chart"
|
||||
)
|
||||
|
||||
var (
|
||||
chartpath = "../../../testdata/rancher-cluster-templates-0.4.4.tgz"
|
||||
)
|
||||
|
||||
func TestNewChart(t *testing.T) {
|
||||
tmpdir, err := os.MkdirTemp("", "hauler")
|
||||
if err != nil {
|
||||
@@ -26,10 +20,6 @@ func TestNewChart(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
if err := archiver.Unarchive(chartpath, tmpdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
name string
|
||||
opts *action.ChartPathOptions
|
||||
@@ -43,8 +33,8 @@ func TestNewChart(t *testing.T) {
|
||||
{
|
||||
name: "should create from a chart archive",
|
||||
args: args{
|
||||
name: chartpath,
|
||||
opts: &action.ChartPathOptions{},
|
||||
name: "rancher-cluster-templates-0.4.4.tgz",
|
||||
opts: &action.ChartPathOptions{RepoURL: "../../../testdata"},
|
||||
},
|
||||
want: v1.Descriptor{
|
||||
MediaType: consts.ChartLayerMediaType,
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"oras.land/oras-go/pkg/target"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/consts"
|
||||
"github.com/rancherfederal/hauler/pkg/reference"
|
||||
)
|
||||
|
||||
var _ target.Target = (*OCI)(nil)
|
||||
@@ -45,8 +46,20 @@ func (o *OCI) AddIndex(desc ocispec.Descriptor) error {
|
||||
if _, ok := desc.Annotations[ocispec.AnnotationRefName]; !ok {
|
||||
return fmt.Errorf("descriptor must contain a reference from the annotation: %s", ocispec.AnnotationRefName)
|
||||
}
|
||||
key := fmt.Sprintf("%s-%s-%s", desc.Digest.String(), desc.Annotations[ocispec.AnnotationRefName], desc.Annotations[consts.KindAnnotationName])
|
||||
o.nameMap.Store(key, desc)
|
||||
|
||||
key, err := reference.Parse(desc.Annotations[ocispec.AnnotationRefName])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.TrimSpace(key.String()) != "--" {
|
||||
switch key.(type) {
|
||||
case name.Digest:
|
||||
o.nameMap.Store(key.Context().String(), desc)
|
||||
case name.Tag:
|
||||
o.nameMap.Store(key.String(), desc)
|
||||
}
|
||||
}
|
||||
return o.SaveIndex()
|
||||
}
|
||||
|
||||
@@ -72,11 +85,21 @@ func (o *OCI) LoadIndex() error {
|
||||
}
|
||||
|
||||
for _, desc := range o.index.Manifests {
|
||||
key := fmt.Sprintf("%s-%s-%s", desc.Digest.String(), desc.Annotations[ocispec.AnnotationRefName], desc.Annotations[consts.KindAnnotationName])
|
||||
if strings.TrimSpace(key) != "--" {
|
||||
o.nameMap.Store(key, desc)
|
||||
key, err := reference.Parse(desc.Annotations[ocispec.AnnotationRefName])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.TrimSpace(key.String()) != "--" {
|
||||
switch key.(type) {
|
||||
case name.Digest:
|
||||
o.nameMap.Store(key.Context().String(), desc)
|
||||
case name.Tag:
|
||||
o.nameMap.Store(key.String(), desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -180,9 +203,11 @@ func (o *OCI) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
|
||||
var baseRef, hash string
|
||||
parts := strings.SplitN(ref, "@", 2)
|
||||
baseRef = parts[0]
|
||||
|
||||
if len(parts) > 1 {
|
||||
hash = parts[1]
|
||||
}
|
||||
|
||||
return &ociPusher{
|
||||
oci: o,
|
||||
ref: baseRef,
|
||||
@@ -275,7 +300,7 @@ func (p *ociPusher) Push(ctx context.Context, d ocispec.Descriptor) (ccontent.Wr
|
||||
|
||||
if _, err := os.Stat(blobPath); err == nil {
|
||||
// file already exists, discard (but validate digest)
|
||||
return content.NewIoContentWriter(ioutil.Discard, content.WithOutputHash(d.Digest)), nil
|
||||
return content.NewIoContentWriter(io.Discard, content.WithOutputHash(d.Digest)), nil
|
||||
}
|
||||
|
||||
f, err := os.Create(blobPath)
|
||||
|
||||
@@ -13,10 +13,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"oras.land/oras-go/pkg/content"
|
||||
|
||||
"github.com/rancherfederal/hauler/pkg/artifacts/image"
|
||||
"github.com/rancherfederal/hauler/pkg/log"
|
||||
"github.com/rancherfederal/hauler/pkg/store"
|
||||
"oras.land/oras-go/pkg/content"
|
||||
)
|
||||
|
||||
const maxRetries = 3
|
||||
@@ -276,4 +277,4 @@ func getCosignPath() (string, error) {
|
||||
binaryPath := filepath.Join(haulerDir, binaryName)
|
||||
|
||||
return binaryPath, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@ type Fields map[string]string
|
||||
|
||||
// NewLogger returns a new Logger
|
||||
func NewLogger(out io.Writer) Logger {
|
||||
customTimeFormat := "2006-01-02 15:04:05"
|
||||
zerolog.TimeFieldFormat = customTimeFormat
|
||||
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: customTimeFormat}
|
||||
l := log.Output(output)
|
||||
return &logger{
|
||||
zl: l.With().Timestamp().Logger(),
|
||||
}
|
||||
customTimeFormat := "2006-01-02 15:04:05"
|
||||
zerolog.TimeFieldFormat = customTimeFormat
|
||||
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: customTimeFormat}
|
||||
l := log.Output(output)
|
||||
return &logger{
|
||||
zl: l.With().Timestamp().Logger(),
|
||||
}
|
||||
}
|
||||
|
||||
// FromContext returns a Logger from a context if it exists
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package reference provides general types to represent oci content within a registry or local oci layout
|
||||
// Grammar (stolen mostly from containerd's grammar)
|
||||
//
|
||||
// reference :=
|
||||
// reference :=
|
||||
package reference
|
||||
|
||||
import (
|
||||
|
||||
0
testdata/haul.tar.zst
vendored
Normal file → Executable file
0
testdata/haul.tar.zst
vendored
Normal file → Executable file
0
testdata/hauler-manifest.yaml
vendored
Normal file → Executable file
0
testdata/hauler-manifest.yaml
vendored
Normal file → Executable file
0
testdata/rancher-cluster-templates-0.4.4.tgz
vendored
Normal file → Executable file
0
testdata/rancher-cluster-templates-0.4.4.tgz
vendored
Normal file → Executable file
Reference in New Issue
Block a user