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
13 changes: 13 additions & 0 deletions api/v1alpha1/imagebuild_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ type FlashSpec struct {
// FlashCmd overrides the flash command from OperatorConfig target mappings
// +optional
FlashCmd string `json:"flashCmd,omitempty"`

// ExporterSelector overrides the exporter selector from OperatorConfig target mappings
// When set, the target-based lookup is skipped entirely
// +optional
ExporterSelector string `json:"exporterSelector,omitempty"`
Comment thread
bennyz marked this conversation as resolved.
}

// AIBSpec defines the automotive-image-builder configuration
Expand Down Expand Up @@ -429,6 +434,14 @@ func (s *ImageBuildSpec) GetRebuildBuilder() bool {
return false
}

// GetFlashExporterSelector returns the user-specified exporter selector override, or empty string
func (s *ImageBuildSpec) GetFlashExporterSelector() string {
if s.Flash != nil {
return s.Flash.ExporterSelector
}
return ""
}

// GetFlashCmd returns the user-specified flash command override, or empty string
func (s *ImageBuildSpec) GetFlashCmd() string {
if s.Flash != nil {
Expand Down
13 changes: 10 additions & 3 deletions cmd/caib/buildcmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type Options struct {
JumpstarterClient *string
LeaseDuration *string
FlashCmd *string
ExporterSelector *string

UseInternalRegistry *bool
InternalRegistryImageName *string
Expand Down Expand Up @@ -385,7 +386,8 @@ func (h *Handler) RunBuild(cmd *cobra.Command, args []string) {
return
}

operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, *h.opts.FlashAfterBuild)
validateFlash := *h.opts.FlashAfterBuild && *h.opts.ExporterSelector == ""
operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, validateFlash)
if cfgErr != nil {
h.handleError(cfgErr)
return
Expand All @@ -410,6 +412,7 @@ func (h *Handler) RunBuild(cmd *cobra.Command, args []string) {
req.FlashClientConfig = base64.StdEncoding.EncodeToString(clientConfigBytes)
req.FlashLeaseDuration = *h.opts.LeaseDuration
req.FlashCmd = *h.opts.FlashCmd
req.FlashExporterSelector = *h.opts.ExporterSelector
}

resp, err := api.CreateBuild(ctx, req)
Expand Down Expand Up @@ -502,7 +505,8 @@ func (h *Handler) RunDisk(cmd *cobra.Command, args []string) {
return
}

operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, *h.opts.FlashAfterBuild)
validateFlash := *h.opts.FlashAfterBuild && *h.opts.ExporterSelector == ""
operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, validateFlash)
if cfgErr != nil {
h.handleError(cfgErr)
return
Expand All @@ -527,6 +531,7 @@ func (h *Handler) RunDisk(cmd *cobra.Command, args []string) {
req.FlashClientConfig = base64.StdEncoding.EncodeToString(clientConfigBytes)
req.FlashLeaseDuration = *h.opts.LeaseDuration
req.FlashCmd = *h.opts.FlashCmd
req.FlashExporterSelector = *h.opts.ExporterSelector
}

resp, err := api.CreateBuild(ctx, req)
Expand Down Expand Up @@ -636,7 +641,8 @@ func (h *Handler) RunBuildDev(cmd *cobra.Command, args []string) {
return
}

operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, *h.opts.FlashAfterBuild)
validateFlash := *h.opts.FlashAfterBuild && *h.opts.ExporterSelector == ""
operatorConfig, cfgErr := h.fetchTargetDefaults(ctx, api, *h.opts.Target, validateFlash)
if cfgErr != nil {
h.handleError(cfgErr)
return
Expand All @@ -662,6 +668,7 @@ func (h *Handler) RunBuildDev(cmd *cobra.Command, args []string) {
req.FlashClientConfig = base64.StdEncoding.EncodeToString(clientConfigBytes)
req.FlashLeaseDuration = *h.opts.LeaseDuration
req.FlashCmd = *h.opts.FlashCmd
req.FlashExporterSelector = *h.opts.ExporterSelector
}

resp, err := api.CreateBuild(ctx, req)
Expand Down
17 changes: 17 additions & 0 deletions cmd/caib/flashcmd/flash.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

common "github.com/centos-automotive-suite/automotive-dev-operator/cmd/caib/common"
"github.com/centos-automotive-suite/automotive-dev-operator/cmd/caib/logstream"
"github.com/centos-automotive-suite/automotive-dev-operator/cmd/caib/registryauth"
buildapitypes "github.com/centos-automotive-suite/automotive-dev-operator/internal/buildapi"
buildapiclient "github.com/centos-automotive-suite/automotive-dev-operator/internal/buildapi/client"
"github.com/spf13/cobra"
Expand All @@ -41,6 +42,7 @@ type Options struct {
WaitForBuild *bool
FollowLogs *bool
InsecureSkipTLS *bool
RegistryAuthFile *string

HandleError func(error)
}
Expand Down Expand Up @@ -120,6 +122,21 @@ func (h *Handler) RunFlash(cmd *cobra.Command, args []string) {
FlashCmd: *h.opts.FlashCmd,
}

// Resolve OCI registry credentials for the flash image
authFile := ""
if h.opts.RegistryAuthFile != nil {
authFile = *h.opts.RegistryAuthFile
}
registryURL, registryUsername, registryPassword := registryauth.ExtractRegistryCredentials(imageRef, "")
registryCreds, credErr := registryauth.ResolveRegistryCredentials(
registryURL, registryUsername, registryPassword, authFile,
)
if credErr != nil {
h.handleError(fmt.Errorf("failed to resolve registry credentials: %w", credErr))
return
}
req.RegistryCredentials = registryCreds

resp, err := api.CreateFlash(ctx, req)
if err != nil {
h.handleError(err)
Expand Down
9 changes: 9 additions & 0 deletions cmd/caib/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func NewImageCmd(opts Options) *cobra.Command {
buildCmd.Flags().StringVar(opts.JumpstarterClient, "client", "", "path to Jumpstarter client config file (required for --flash)")
buildCmd.Flags().StringVar(opts.LeaseDuration, "lease", "03:00:00", "device lease duration for flash (HH:MM:SS)")
buildCmd.Flags().StringVar(opts.FlashCmd, "flash-cmd", "", "override flash command (default: from OperatorConfig target mapping)")
buildCmd.Flags().StringVar(opts.ExporterSelector, "exporter", "", "direct exporter selector for flash (alternative to --target lookup)")
// Internal registry options
buildCmd.Flags().BoolVar(opts.UseInternalRegistry, "internal-registry", false, "push to OpenShift internal registry")
buildCmd.Flags().StringVar(opts.InternalRegistryImageName, "image-name", "", "override image name for internal registry (default: build name)")
Expand Down Expand Up @@ -198,6 +199,7 @@ func NewImageCmd(opts Options) *cobra.Command {
diskCmd.Flags().StringVar(opts.JumpstarterClient, "client", "", "path to Jumpstarter client config file (required for --flash)")
diskCmd.Flags().StringVar(opts.LeaseDuration, "lease", "03:00:00", "device lease duration for flash (HH:MM:SS)")
diskCmd.Flags().StringVar(opts.FlashCmd, "flash-cmd", "", "override flash command (default: from OperatorConfig target mapping)")
diskCmd.Flags().StringVar(opts.ExporterSelector, "exporter", "", "direct exporter selector for flash (alternative to --target lookup)")
// Internal registry options
diskCmd.Flags().BoolVar(opts.UseInternalRegistry, "internal-registry", false, "push to OpenShift internal registry")
diskCmd.Flags().StringVar(opts.InternalRegistryImageName, "image-name", "", "override image name for internal registry (default: build name)")
Expand Down Expand Up @@ -236,6 +238,7 @@ func NewImageCmd(opts Options) *cobra.Command {
buildDevCmd.Flags().StringVar(opts.JumpstarterClient, "client", "", "path to Jumpstarter client config file (required for --flash)")
buildDevCmd.Flags().StringVar(opts.LeaseDuration, "lease", "03:00:00", "device lease duration for flash (HH:MM:SS)")
buildDevCmd.Flags().StringVar(opts.FlashCmd, "flash-cmd", "", "override flash command (default: from OperatorConfig target mapping)")
buildDevCmd.Flags().StringVar(opts.ExporterSelector, "exporter", "", "direct exporter selector for flash (alternative to --target lookup)")
// Internal registry options
buildDevCmd.Flags().BoolVar(opts.UseInternalRegistry, "internal-registry", false, "push to OpenShift internal registry")
buildDevCmd.Flags().StringVar(opts.InternalRegistryImageName, "image-name", "", "override image name for internal registry (default: build name)")
Expand All @@ -260,6 +263,12 @@ func NewImageCmd(opts Options) *cobra.Command {
flashCmd.Flags().StringVar(opts.ExporterSelector, "exporter", "", "direct exporter selector (alternative to --target)")
flashCmd.Flags().StringVar(opts.LeaseDuration, "lease", "03:00:00", "device lease duration (HH:MM:SS)")
flashCmd.Flags().StringVar(opts.FlashCmd, "flash-cmd", "", "override flash command (default: from OperatorConfig target mapping)")
flashCmd.Flags().StringVar(
opts.RegistryAuthFile,
"registry-auth-file",
"",
"path to Docker/Podman auth file for OCI image pull authentication (takes precedence over env vars and auto-discovery)",
)
flashCmd.Flags().BoolVarP(opts.FollowLogs, "follow", "f", false, "follow flash logs (shows full log output instead of progress bar)")
flashCmd.Flags().BoolVarP(opts.WaitForBuild, "wait", "w", true, "wait for flash to complete")
_ = flashCmd.MarkFlagRequired("client")
Expand Down
27 changes: 3 additions & 24 deletions cmd/caib/registryauth/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ package registryauth
import (
"encoding/json"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/centos-automotive-suite/automotive-dev-operator/internal/common/registryutil"
)

type authConfigFile struct {
Expand All @@ -32,30 +33,8 @@ func authEntryHasCredentials(entry authConfigEntry) bool {
return strings.TrimSpace(entry.Username) != "" && strings.TrimSpace(entry.Password) != ""
}

func normalizeRegistryHost(raw string) string {
value := strings.TrimSpace(raw)
if value == "" {
return ""
}
if strings.Contains(value, "://") {
parsed, err := url.Parse(value)
if err == nil && parsed.Host != "" {
value = parsed.Host
}
}
value = strings.TrimPrefix(value, "//")
value = strings.SplitN(value, "/", 2)[0]
value = strings.TrimSuffix(value, "/")
return strings.ToLower(strings.TrimSpace(value))
}

func registryAuthKeyMatches(authKey, registryURL string) bool {
keyHost := normalizeRegistryHost(authKey)
registryHost := normalizeRegistryHost(registryURL)
if keyHost == "" || registryHost == "" {
return false
}
return keyHost == registryHost
return registryutil.RegistryHostMatches(authKey, registryURL)
}

func authFileHasRegistryAuth(content []byte, registryURL string) (bool, error) {
Expand Down
2 changes: 2 additions & 0 deletions cmd/caib/runtime_wiring.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ func (s runtimeState) newHandlers() handlerSet {
JumpstarterClient: s.JumpstarterClient,
LeaseDuration: s.LeaseDuration,
FlashCmd: s.FlashCmd,
ExporterSelector: s.ExporterSelector,
UseInternalRegistry: s.UseInternalRegistry,
InternalRegistryImageName: s.InternalRegistryImageName,
InternalRegistryTag: s.InternalRegistryTag,
Expand Down Expand Up @@ -192,6 +193,7 @@ func (s runtimeState) newHandlers() handlerSet {
WaitForBuild: s.WaitForBuild,
FollowLogs: s.FollowLogs,
InsecureSkipTLS: s.InsecureSkipTLS,
RegistryAuthFile: s.RegistryAuthFile,
HandleError: handleError,
}),
sealed: sealedcmd.NewHandler(sealedcmd.Options{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ spec:
The secret should have a key "client.yaml" with the config contents
If set, flash is enabled automatically
type: string
exporterSelector:
description: |-
ExporterSelector overrides the exporter selector from OperatorConfig target mappings
When set, the target-based lookup is skipped entirely
type: string
flashCmd:
description: FlashCmd overrides the flash command from OperatorConfig
target mappings
Expand Down
Loading
Loading