Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"os/exec"
"os/user"
"path"
"runtime"
"strings"
"time"

Expand Down Expand Up @@ -210,8 +209,8 @@ func (b *Builder) updateOCIConfigForOutput(sf *types.Stackerfile, s types.Storag
author := fmt.Sprintf("%s@%s", username, host)

meta.Created = time.Now()
meta.Architecture = runtime.GOARCH
meta.OS = runtime.GOOS
meta.Architecture = *l.Arch
meta.OS = *l.OS
meta.Author = author

annotations, err := mutator.Annotations(context.Background())
Expand Down
2 changes: 1 addition & 1 deletion cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,5 @@ func TestCacheEntryChanged(t *testing.T) {
// This test works because the type information is included in the
// hashstructure hash above, so using a zero valued CacheEntry is
// enough to capture changes in types.
assert.Equal(uint64(0x98ab47c70ff0b70), h)
assert.Equal(uint64(0x1ec739cbb7ee4e77), h)
}
11 changes: 11 additions & 0 deletions doc/stacker_yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,14 @@ While `config` section supports a similar `labels`, it is more pertitent to the
image runtime. On the other hand, `annotations` is intended to be
image-specific metadata aligned with the
[annotations in the image spec](https://github.com/opencontainers/image-spec/blob/main/annotations.md).

##### `os`

`os` is a user-specified string value indicating which _operating system_ this image is being
built for, for example, `linux`, `darwin`, etc. It is an optional field and it
defaults to the host operating system if not specified.

##### `arch`
`arch` is a user-specified string value indicating which machine _architecture_ this image is being
built for, for example, `amd64`, `arm64`, etc. It is an optional field and it
defaults to the host machine architecture if not specified.
44 changes: 44 additions & 0 deletions test/multi-arch.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
load helpers

function setup() {
stacker_setup
}

function teardown() {
cleanup
}

@test "multi-arch/os support" {
cat > stacker.yaml <<EOF
centos:
os: darwin
arch: arm64
from:
type: oci
url: $CENTOS_OCI
import:
- https://www.cisco.com/favicon.ico
EOF
stacker build

# check OCI image generation
manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:)
layer=$(cat oci/blobs/sha256/$manifest | jq -r .layers[0].digest)
config=$(cat oci/blobs/sha256/$manifest | jq -r .config.digest | cut -f2 -d:)
[ "$(cat oci/blobs/sha256/$config | jq -r '.architecture')" = "arm64" ]
[ "$(cat oci/blobs/sha256/$config | jq -r '.os')" = "darwin" ]
}

@test "multi-arch/os bad config fails" {
cat > stacker.yaml <<EOF
centos:
os:
from:
type: oci
url: $CENTOS_OCI
import:
- https://www.cisco.com/favicon.ico
EOF
bad_stacker build
[ "$status" -eq 1 ]
}
23 changes: 23 additions & 0 deletions types/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"
"reflect"
"regexp"
"runtime"
"strings"

"github.com/anmitsu/go-shlex"
Expand Down Expand Up @@ -192,6 +193,8 @@ type Layer struct {
Binds Binds `yaml:"binds"`
RuntimeUser string `yaml:"runtime_user"`
Annotations map[string]string `yaml:"annotations"`
OS *string `yaml:"os"`
Arch *string `yaml:"arch"`
}

func parseLayers(referenceDirectory string, lms yaml.MapSlice, requireHash bool) (map[string]Layer, error) {
Expand Down Expand Up @@ -227,6 +230,12 @@ func parseLayers(referenceDirectory string, lms yaml.MapSlice, requireHash bool)
}
}
}

if directive.Key.(string) == "os" || directive.Key.(string) == "arch" {
if directive.Value == nil {
return nil, errors.Errorf("stackerfile: %q value cannot be empty", directive.Key.(string))
}
}
}
}

Expand Down Expand Up @@ -257,6 +266,18 @@ func parseLayers(referenceDirectory string, lms yaml.MapSlice, requireHash bool)
}
}

if layer.OS == nil {
// if not specified, default to runtime
os := runtime.GOOS
layer.OS = &os
}

if layer.Arch == nil {
// if not specified, default to runtime
arch := runtime.GOARCH
layer.Arch = &arch
}

ret[name], err = layer.absolutify(referenceDirectory)
if err != nil {
return nil, err
Expand Down Expand Up @@ -467,6 +488,8 @@ func init() {
layerType := reflect.TypeOf(Layer{})
for i := 0; i < layerType.NumField(); i++ {
tag := layerType.Field(i).Tag.Get("yaml")
// some fields are ",omitempty"
tag = strings.Split(tag, ",")[0]
layerFields = append(layerFields, tag)
}
}