Blame internal/osbuild2/oci_archive_stage.go

Packit Service 15f37d
package osbuild2
Packit Service 15f37d
Packit Service 15f37d
import (
Packit Service 15f37d
	"bytes"
Packit Service 15f37d
	"encoding/json"
Packit Service 15f37d
	"fmt"
Packit Service 15f37d
	"regexp"
Packit Service 15f37d
	"sort"
Packit Service 15f37d
)
Packit Service 15f37d
Packit Service 15f37d
type OCIArchiveStageOptions struct {
Packit Service 15f37d
	// The CPU architecture of the image
Packit Service 15f37d
	Architecture string `json:"architecture"`
Packit Service 15f37d
Packit Service 15f37d
	// Resulting image filename
Packit Service 15f37d
	Filename string `json:"filename"`
Packit Service 15f37d
Packit Service 15f37d
	// The execution parameters
Packit Service 15f37d
	Config *OCIArchiveConfig `json:"config,omitempty"`
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
type OCIArchiveConfig struct {
Packit Service 15f37d
	Cmd          []string          `json:"Cmd,omitempty"`
Packit Service 15f37d
	Env          []string          `json:"Env,omitempty"`
Packit Service 15f37d
	ExposedPorts []string          `json:"ExposedPorts,omitempty"`
Packit Service 15f37d
	User         string            `json:"User,omitempty"`
Packit Service 15f37d
	Labels       map[string]string `json:"Labels,omitempty"`
Packit Service 15f37d
	StopSignal   string            `json:"StopSignal,omitempty"`
Packit Service 15f37d
	Volumes      []string          `json:"Volumes,omitempty"`
Packit Service 15f37d
	WorkingDir   string            `json:"WorkingDir,omitempty"`
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
func (OCIArchiveStageOptions) isStageOptions() {}
Packit Service 15f37d
Packit Service 15f37d
type OCIArchiveStageInputs struct {
Packit Service 15f37d
	// Base layer for the container
Packit Service 15f37d
	Base *OCIArchiveStageInput `json:"base"`
Packit Service 15f37d
	// Additional layers in ascending order
Packit Service 15f37d
	Layers []OCIArchiveStageInput `json:",omitempty"`
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
func (OCIArchiveStageInputs) isStageInputs() {}
Packit Service 15f37d
Packit Service 15f37d
type OCIArchiveStageInput struct {
Packit Service 15f37d
	inputCommon
Packit Service 15f37d
	References OCIArchiveStageReferences `json:"references"`
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
func (OCIArchiveStageInput) isStageInput() {}
Packit Service 15f37d
Packit Service 15f37d
type OCIArchiveStageReferences []string
Packit Service 15f37d
Packit Service 15f37d
func (OCIArchiveStageReferences) isReferences() {}
Packit Service 15f37d
Packit Service 15f37d
// A new OCIArchiveStage to to assemble an OCI image archive
Packit Service 15f37d
func NewOCIArchiveStage(options *OCIArchiveStageOptions, inputs *OCIArchiveStageInputs) *Stage {
Packit Service 15f37d
	return &Stage{
Packit Service 15f37d
		Type:    "org.osbuild.oci-archive",
Packit Service 15f37d
		Options: options,
Packit Service 15f37d
		Inputs:  inputs,
Packit Service 15f37d
	}
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
// Custom marshaller for OCIArchiveStageInputs, needed to generate keys of the
Packit Service 15f37d
// form "layer.N", (where N = 1, 2, ...) for the Layers property
Packit Service 15f37d
func (inputs *OCIArchiveStageInputs) MarshalJSON() ([]byte, error) {
Packit Service 15f37d
	if inputs == nil {
Packit Service 15f37d
		return json.Marshal(inputs)
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	layers := inputs.Layers
Packit Service 15f37d
	inputsMap := make(map[string]OCIArchiveStageInput, len(layers)+1)
Packit Service 15f37d
	if inputs.Base != nil {
Packit Service 15f37d
		inputsMap["base"] = *inputs.Base
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	for idx, input := range layers {
Packit Service 15f37d
		key := fmt.Sprintf("layer.%d", idx+1)
Packit Service 15f37d
		inputsMap[key] = input
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	return json.Marshal(inputsMap)
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
// Get the sorted keys that match the pattern "layer.N" (for N > 0)
Packit Service 15f37d
func layerKeys(layers map[string]OCIArchiveStageInput) ([]string, error) {
Packit Service 15f37d
	keys := make([]string, 0, len(layers))
Packit Service 15f37d
	for key := range layers {
Packit Service 15f37d
		re := regexp.MustCompile(`layer\.[1-9]\d*`)
Packit Service 15f37d
		if key == "base" {
Packit Service 15f37d
			continue
Packit Service 15f37d
		}
Packit Service 15f37d
		if !re.MatchString(key) {
Packit Service 15f37d
			return nil, fmt.Errorf("invalid key: %q", key)
Packit Service 15f37d
		}
Packit Service 15f37d
		keys = append(keys, key)
Packit Service 15f37d
	}
Packit Service 15f37d
	sort.Strings(keys)
Packit Service 15f37d
	return keys, nil
Packit Service 15f37d
}
Packit Service 15f37d
Packit Service 15f37d
// Custom unmarshaller for OCIArchiveStageInputs, needed to handle keys of the
Packit Service 15f37d
// form "layer.N", (where N = 1, 2, ...) for the Layers property
Packit Service 15f37d
func (inputs *OCIArchiveStageInputs) UnmarshalJSON(data []byte) error {
Packit Service 15f37d
	if len(data) == 0 {
Packit Service 15f37d
		return nil
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	if inputs == nil {
Packit Service 15f37d
		inputs = new(OCIArchiveStageInputs)
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	inputsMap := make(map[string]OCIArchiveStageInput)
Packit Service 15f37d
Packit Service 15f37d
	dec := json.NewDecoder(bytes.NewReader(data))
Packit Service 15f37d
	dec.DisallowUnknownFields()
Packit Service 15f37d
Packit Service 15f37d
	if err := dec.Decode(&inputsMap); err != nil {
Packit Service 15f37d
		return err
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	// "base" layer is required
Packit Service 15f37d
	base, ok := inputsMap["base"]
Packit Service 15f37d
	if !ok {
Packit Service 15f37d
		return fmt.Errorf("missing required key \"base\"")
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	inputs.Base = &base
Packit Service 15f37d
	keys, err := layerKeys(inputsMap)
Packit Service 15f37d
	if err != nil {
Packit Service 15f37d
		return err
Packit Service 15f37d
	}
Packit Service 15f37d
	inputs.Layers = make([]OCIArchiveStageInput, len(inputsMap)-1)
Packit Service 15f37d
	for idx, key := range keys {
Packit Service 15f37d
		inputs.Layers[idx] = inputsMap[key]
Packit Service 15f37d
	}
Packit Service 15f37d
Packit Service 15f37d
	return nil
Packit Service 15f37d
}