Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/go_modules-6387e463ea
Browse files Browse the repository at this point in the history
  • Loading branch information
kichristensen authored May 10, 2024
2 parents fafec89 + 03297bf commit a353403
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

/docs/content/ @iennae

* @schristoff @sgettys @bdegeeter @troy0820
* @schristoff @sgettys @bdegeeter @troy0820 @kichristensen
2 changes: 2 additions & 0 deletions .github/workflows/build_pipelinesrelease_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v4.1.0
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: "${{ inputs.GOVERSION }}"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/trivy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
# Dependabot pushes to branches in our repo, not in a fork. This causes the push event to trigger for dependabot PRs and the CodeQL check fails.
- "dependabot/**"
# Only do a security scan on a PR when there are non-doc changes to save time
pull_request_target:
pull_request:
paths-ignore:
- 'docs/**'

Expand Down
7 changes: 5 additions & 2 deletions cmd/porter/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func buildBundleArchiveCommand(p *porter.Porter) *cobra.Command {
Long: "Archives a bundle by generating a gzipped tar archive containing the bundle, invocation image and any referenced images.",
Example: ` porter bundle archive mybun.tgz --reference ghcr.io/getporter/examples/porter-hello:v0.2.0
porter bundle archive mybun.tgz --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --force
porter bundle archive mybun.tgz --compression NoCompression --reference ghcr.io/getporter/examples/porter-hello:v0.2.0
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
return opts.Validate(cmd.Context(), args, p)
Expand All @@ -199,7 +200,9 @@ func buildBundleArchiveCommand(p *porter.Porter) *cobra.Command {
},
}

addBundlePullFlags(cmd.Flags(), &opts.BundlePullOptions)

f := cmd.Flags()
addBundlePullFlags(f, &opts.BundlePullOptions)
f.StringVarP(&opts.CompressionLevel, "compression", "c", opts.GetCompressionLevelDefault(),
fmt.Sprintf("Compression level to use when creating the gzipped tar archive. Allowed values are: %s", strings.Join(opts.GetCompressionLevelAllowedValues(), ", ")))
return &cmd
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ replace (
)

require (
get.porter.sh/magefiles v0.6.3
get.porter.sh/magefiles v0.6.5
github.com/Masterminds/semver/v3 v3.2.1
github.com/PaesslerAG/jsonpath v0.1.1
github.com/carolynvs/aferox v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
get.porter.sh/magefiles v0.6.3 h1:OE9YqCArn9fvM+VdanGlXNyIjy2F8W4yJGy5kcC/xD0=
get.porter.sh/magefiles v0.6.3/go.mod h1:w37oTKICvvaEKR5KVB9UfN2EX30uYO9Qk0oRoz80DOU=
get.porter.sh/magefiles v0.6.5 h1:A7rKeM3zGG6A8Z/cvOjhexuC07rQ+Ih2FcFX1cwdYzA=
get.porter.sh/magefiles v0.6.5/go.mod h1:w37oTKICvvaEKR5KVB9UfN2EX30uYO9Qk0oRoz80DOU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
Expand Down
46 changes: 42 additions & 4 deletions pkg/porter/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,30 @@ import (
// ArchiveOptions defines the valid options for performing an archive operation
type ArchiveOptions struct {
BundleReferenceOptions
ArchiveFile string
ArchiveFile string
CompressionLevel string
compressionLevelInt int
}

var compressionLevelValues = map[string]int{
"NoCompression": gzip.NoCompression,
"BestSpeed": gzip.BestSpeed,
"BestCompression": gzip.BestCompression,
"DefaultCompression": gzip.DefaultCompression,
"HuffmanOnly": gzip.HuffmanOnly,
}

func (o *ArchiveOptions) GetCompressionLevelDefault() string {
return "DefaultCompression"
}

func (p *ArchiveOptions) GetCompressionLevelAllowedValues() []string {
levels := make([]string, 0, len(compressionLevelValues))
for level := range compressionLevelValues {
levels = append(levels, level)
}
sort.Strings(levels)
return levels
}

// Validate performs validation on the publish options
Expand All @@ -47,6 +70,16 @@ func (o *ArchiveOptions) Validate(ctx context.Context, args []string, p *Porter)
if o.Reference == "" {
return errors.New("must provide a value for --reference of the form REGISTRY/bundle:tag")
}

if o.CompressionLevel == "" {
o.CompressionLevel = o.GetCompressionLevelDefault()
}
level, ok := compressionLevelValues[o.CompressionLevel]
if !ok {
return fmt.Errorf("invalid compression level: %s", o.CompressionLevel)
}
o.compressionLevelInt = level

return o.BundleReferenceOptions.Validate(ctx, args, p)
}

Expand Down Expand Up @@ -87,6 +120,7 @@ func (p *Porter) Archive(ctx context.Context, opts ArchiveOptions) error {
destination: dest,
imageStoreConstructor: ctor,
insecureRegistry: opts.InsecureRegistry,
compressionLevel: opts.compressionLevelInt,
}
if err := exp.export(ctx); err != nil {
return log.Error(err)
Expand All @@ -105,6 +139,7 @@ type exporter struct {
imageStoreConstructor imagestore.Constructor
imageStore imagestore.Store
insecureRegistry bool
compressionLevel int
}

func (ex *exporter) export(ctx context.Context) error {
Expand Down Expand Up @@ -156,7 +191,7 @@ func (ex *exporter) export(ctx context.Context) error {
return fmt.Errorf("error preparing bundle artifact: %s", err)
}

rc, err := ex.CustomTar(ctx, archiveDir)
rc, err := ex.CustomTar(ctx, archiveDir, ex.compressionLevel)
if err != nil {
return fmt.Errorf("error creating archive: %w", err)
}
Expand Down Expand Up @@ -219,10 +254,13 @@ func (ex *exporter) createTarHeader(ctx context.Context, path string, file strin
return header, nil
}

func (ex *exporter) CustomTar(ctx context.Context, srcPath string) (io.ReadCloser, error) {
func (ex *exporter) CustomTar(ctx context.Context, srcPath string, compressionLevel int) (io.ReadCloser, error) {
pipeReader, pipeWriter := io.Pipe()

gzipWriter := gzip.NewWriter(pipeWriter)
gzipWriter, err := gzip.NewWriterLevel(pipeWriter, compressionLevel)
if err != nil {
return nil, err
}
tarWriter := tar.NewWriter(gzipWriter)

cleanSrcPath := filepath.Clean(srcPath)
Expand Down
20 changes: 12 additions & 8 deletions pkg/porter/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,25 @@ func TestArchive_Validate(t *testing.T) {
defer p.Close()

testcases := []struct {
name string
args []string
reference string
wantError string
name string
args []string
reference string
compressionLevel string
wantError string
}{
{"no arg", nil, "", "destination file is required"},
{"no tag", []string{"/path/to/file"}, "", "must provide a value for --reference of the form REGISTRY/bundle:tag"},
{"too many args", []string{"/path/to/file", "moar args!"}, "myreg/mybuns:v0.1.0", "only one positional argument may be specified, the archive file name, but multiple were received: [/path/to/file moar args!]"},
{"just right", []string{"/path/to/file"}, "myreg/mybuns:v0.1.0", ""},
{"no arg", nil, "", "", "destination file is required"},
{"no tag", []string{"/path/to/file"}, "", "", "must provide a value for --reference of the form REGISTRY/bundle:tag"},
{"too many args", []string{"/path/to/file", "moar args!"}, "myreg/mybuns:v0.1.0", "", "only one positional argument may be specified, the archive file name, but multiple were received: [/path/to/file moar args!]"},
{"invalid compression level", []string{"/path/to/file"}, "myreg/mybuns:v0.1.0", "NotValidCompression", "invalid compression level: NotValidCompression"},
{"no compression level", []string{"/path/to/file"}, "myreg/mybuns:v0.1.0", "NoCompression", ""},
{"just right", []string{"/path/to/file"}, "myreg/mybuns:v0.1.0", "", ""},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
opts := ArchiveOptions{}
opts.Reference = tc.reference
opts.CompressionLevel = tc.compressionLevel

err := opts.Validate(context.Background(), tc.args, p.Porter)
if tc.wantError != "" {
Expand Down
42 changes: 42 additions & 0 deletions tests/integration/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,45 @@ func getHash(p *porter.TestPorter, path string) string {

return fmt.Sprintf("%x", h.Sum(nil))
}

// Validate that a bundle archived with NoCompression can be published
func TestArchive_WithNoCompression(t *testing.T) {
t.Parallel()
p := porter.NewTestPorter(t)
defer p.Close()
ctx := p.SetupIntegrationTest()

// Use a fixed bundle to work with so that we can rely on the registry and layer digests
const reference = "ghcr.io/getporter/examples/whalegap:v0.2.0"

// Archive bundle
archiveOpts := porter.ArchiveOptions{}
archiveOpts.Reference = reference
archiveOpts.CompressionLevel = "NoCompression"
archiveFile := "mybuns1nocomp.tgz"
err := archiveOpts.Validate(ctx, []string{archiveFile}, p.Porter)
require.NoError(p.T(), err, "validation of archive opts for bundle failed")

err = p.Archive(ctx, archiveOpts)
require.NoError(p.T(), err, "archival of bundle failed")

hash := getHash(p, archiveFile)

// different compressions yields different (but consistent) hashes
consistentHash := "191a249d861f41492ee568080a063718ad77e9b18ad0672cbf4fc2f0e4d1c07c"
assert.Equal(p.T(), consistentHash, hash, "shasum of archive did not match expected hash")

// Publish bundle from archive, with new reference
localReference := "localhost:5000/archived-nocompression-whalegap:v0.2.0"
publishFromArchiveOpts := porter.PublishOptions{
ArchiveFile: archiveFile,
BundlePullOptions: porter.BundlePullOptions{
Reference: localReference,
},
}
err = publishFromArchiveOpts.Validate(p.Config)
require.NoError(p.T(), err, "validation of publish opts for bundle failed")

err = p.Publish(ctx, publishFromArchiveOpts)
require.NoError(p.T(), err, "publish of bundle from archive failed")
}

0 comments on commit a353403

Please sign in to comment.