Skip to content

Commit dc73c85

Browse files
committed
feat: add support for embedding machine configuration (enterprise)
allow embedding machine configuration into Talos images. Signed-off-by: Orzelius <33936483+Orzelius@users.noreply.github.com>
1 parent ba34dab commit dc73c85

27 files changed

Lines changed: 374 additions & 48 deletions

cmd/image-factory/cmd/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ func RunFactory(ctx context.Context, logger *zap.Logger, opts Options) error {
129129
artifactsManager,
130130
secureBootService,
131131
enterprise.NewChecksummer(),
132+
enterprise.NewConfigurator(),
132133
enterprisePlugins,
133134
frontendOptions,
134135
)

docs/api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ customization:
6565
# optional, include well-known UEFI certificates into auto-enrollment database (SecureBoot ISO only)
6666
includeWellKnownCertificates: true
6767
bootloader: sd-boot # optional, defaults to auto (bootloader chosen by imager), other options: dual-boot, grub
68+
embeddedMachineConfiguration: | # optional, embedded machine configuration (YAML-encoded) (Enterprise only)
69+
apiVersion: v1alpha1
70+
kind: HostnameConfig
71+
hostname: my-custom-hostname
72+
auto: off
6873
overlay: # optional
6974
image: ghcr.io/siderolabs/sbc-raspberry-pi # overlay image
7075
name: rpi_generic # overlay name
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2026 Sidero Labs, Inc.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the LICENSE file.
5+
6+
//go:build enterprise
7+
8+
// Package config adds configuration related functionality.
9+
package config
10+
11+
import (
12+
"github.com/siderolabs/talos/pkg/imager/profile"
13+
14+
"github.com/siderolabs/image-factory/pkg/schematic"
15+
)
16+
17+
type Configurator struct{}
18+
19+
// EmbedConfigIntoSchematic embeds the machine config into the schematic.
20+
func (Configurator) EmbedConfigIntoSchematic(config string, schematic *schematic.Schematic) {
21+
schematic.Customization.EmbeddedMachineConfiguration = config
22+
}
23+
24+
// EmbedConfigIntoProfile embeds the machine config into the profile.
25+
func (Configurator) EmbedConfigIntoProfile(config string, profile *profile.Profile) {
26+
profile.Customization.EmbeddedMachineConfiguration = config
27+
}

internal/frontend/http/configuration.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"github.com/siderolabs/gen/xerrors"
1616

1717
"github.com/siderolabs/image-factory/internal/schematic/storage"
18+
"github.com/siderolabs/image-factory/pkg/enterprise"
19+
enterrors "github.com/siderolabs/image-factory/pkg/enterprise/errors"
1820
schematicpkg "github.com/siderolabs/image-factory/pkg/schematic"
1921
)
2022

@@ -34,6 +36,10 @@ func (f *Frontend) handleSchematicCreate(ctx context.Context, w http.ResponseWri
3436
return err
3537
}
3638

39+
if schematic.Customization.EmbeddedMachineConfiguration != "" && !enterprise.Enabled() {
40+
return xerrors.NewTaggedf[enterrors.NotEnabledTag]("enterprise not enabled: embedding machine configuration is not available")
41+
}
42+
3743
if f.options.AuthProvider != nil {
3844
if username, ok := f.options.AuthProvider.UsernameFromContext(ctx); ok {
3945
if schematic.Owner != "" && schematic.Owner != username {

internal/frontend/http/css/output.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/frontend/http/http.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type Frontend struct {
5050
artifactsManager *artifacts.Manager
5151
secureBootService *secureboot.Service
5252
checksummer enterprise.Checksummer
53+
configurator enterprise.Configurator
5354
logger *zap.Logger
5455
puller remotewrap.Puller
5556
pusher remotewrap.Pusher
@@ -85,6 +86,7 @@ func NewFrontend(
8586
artifactsManager *artifacts.Manager,
8687
secureBootService *secureboot.Service,
8788
checksummer enterprise.Checksummer,
89+
configEmbedder enterprise.Configurator,
8890
enterprisePlugins []enterprise.FrontendPlugin,
8991
opts Options,
9092
) (*Frontend, error) {
@@ -95,6 +97,7 @@ func NewFrontend(
9597
artifactsManager: artifactsManager,
9698
secureBootService: secureBootService,
9799
checksummer: checksummer,
100+
configurator: configEmbedder,
98101
logger: logger.With(zap.String("frontend", "http")),
99102
options: opts,
100103
}

internal/frontend/http/image.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (f *Frontend) handleImage(ctx context.Context, w http.ResponseWriter, r *ht
8181
return fmt.Errorf("error parsing profile from path: %w", err)
8282
}
8383

84-
prof, err = profile.EnhanceFromSchematic(ctx, prof, schematic, f.artifactsManager, f.secureBootService, versionTag)
84+
prof, err = profile.EnhanceFromSchematic(ctx, prof, schematic, f.artifactsManager, f.secureBootService, f.configurator, versionTag)
8585
if err != nil {
8686
return fmt.Errorf("error enhancing profile from schematic: %w", err)
8787
}

internal/frontend/http/locales/active.en.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@
184184
- id: customization.overlay.skip
185185
translation: "If unsure, you can skip this step."
186186

187+
- id: customization.embedded_config
188+
translation: "Embedded machine configuration:"
189+
190+
- id: customization.embedded_config.description
191+
translation: "This configuration will be embedded into the image. For more details see the "
192+
193+
- id: customization.embedded_config.reference
194+
translation: "documentation"
195+
196+
- id: customization.embedded_config.skip
197+
translation: "Skip this step if unsure."
198+
187199
- id: customization.bootloader.title
188200
translation: "Bootloader"
189201

internal/frontend/http/locales/active.fr.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@
184184
- id: customization.overlay.skip
185185
translation: "En cas de doute, vous pouvez ignorer cette étape."
186186

187+
- id: customization.embedded_config
188+
translation: "Configuration machine intégrée :"
189+
190+
- id: customization.embedded_config.description
191+
translation: "Cette configuration sera intégrée à l'image. Pour plus de détails, consultez la "
192+
193+
- id: customization.embedded_config.reference
194+
translation: "documentation"
195+
196+
- id: customization.embedded_config.skip
197+
translation: "Ignorez cette étape en cas de doute."
198+
187199
- id: customization.bootloader.title
188200
translation: "Chargeur d'amorçage"
189201

internal/frontend/http/locales/active.pl.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@
184184
- id: customization.overlay.skip
185185
translation: "Jeśli nie masz pewności - możesz pominąć ten krok."
186186

187+
- id: customization.embedded_config
188+
translation: "Wbudowana konfiguracja maszyny:"
189+
190+
- id: customization.embedded_config.description
191+
translation: "Ta konfiguracja zostanie wbudowana w obraz. Aby uzyskać więcej informacji, zobacz "
192+
193+
- id: customization.embedded_config.reference
194+
translation: "dokumentację"
195+
196+
- id: customization.embedded_config.skip
197+
translation: "Pomiń ten krok, jeśli nie masz pewności."
198+
187199
- id: customization.bootloader.title
188200
translation: "Program rozruchowy"
189201

0 commit comments

Comments
 (0)