Skip to content

Commit 6099f3f

Browse files
committed
Add Starlark-based provisioner backend
- New provisioner implementation that delegates every `pkg/provisioner.Provisioner` method to a named function in a user-supplied Starlark script, enabled via `--starlark-provisioner-script` CLI arg. - The reference script `efi-vmedia.star` that targets Ironic redfish-virtualmedia UEFI (custom-deploy or qcow2) and rejects unsupported specs. Signed-off-by: s3rj1k <evasive.gyron@gmail.com>
1 parent 5a65e4a commit 6099f3f

19 files changed

Lines changed: 2951 additions & 10 deletions

File tree

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require (
1515
github.com/prometheus/client_golang v1.23.2
1616
github.com/stretchr/testify v1.11.1
1717
go.etcd.io/etcd/client/pkg/v3 v3.6.10
18+
go.starlark.net v0.0.0-20260326113308-fadfc96def35
1819
go.uber.org/zap v1.27.1
1920
k8s.io/api v0.34.6
2021
k8s.io/apimachinery v0.34.6
@@ -90,7 +91,7 @@ require (
9091
golang.org/x/oauth2 v0.34.0 // indirect
9192
golang.org/x/sync v0.19.0 // indirect
9293
golang.org/x/sys v0.42.0 // indirect
93-
golang.org/x/term v0.39.0 // indirect
94+
golang.org/x/term v0.41.0 // indirect
9495
golang.org/x/text v0.33.0 // indirect
9596
golang.org/x/time v0.9.0 // indirect
9697
golang.org/x/tools v0.41.0 // indirect

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09
217217
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
218218
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
219219
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
220+
go.starlark.net v0.0.0-20260326113308-fadfc96def35 h1:VYAqieSOJNxBDX8KJneTAwvdf4J4zRDE2u+UFXtt9h4=
221+
go.starlark.net v0.0.0-20260326113308-fadfc96def35/go.mod h1:Iue6g6iirlfLoVi/DYCi5/x0h/bAOuWF3dULTKpt2Vo=
220222
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
221223
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
222224
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -256,8 +258,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
256258
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
257259
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
258260
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
259-
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
260-
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
261+
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
262+
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
261263
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
262264
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
263265
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=

internal/controller/metal3.io/baremetalhost_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ func (r *BareMetalHostReconciler) registerHost(ctx context.Context, prov provisi
828828
dirty = true
829829
}
830830

831-
preprovImgFormats, err := prov.PreprovisioningImageFormats()
831+
preprovImgFormats, err := prov.PreprovisioningImageFormats(ctx)
832832
if err != nil {
833833
return actionError{err}
834834
}

internal/controller/metal3.io/host_state_machine_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ func (m *mockProvisioner) Register(_ context.Context, _ provisioner.ManagementAc
13191319
return m.getNextResultByMethod("ValidateManagementAccess"), "", err
13201320
}
13211321

1322-
func (m *mockProvisioner) PreprovisioningImageFormats() ([]metal3api.ImageFormat, error) {
1322+
func (m *mockProvisioner) PreprovisioningImageFormats(_ context.Context) ([]metal3api.ImageFormat, error) {
13231323
return nil, nil
13241324
}
13251325

main.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/metal3-io/baremetal-operator/pkg/provisioner/demo"
3434
"github.com/metal3-io/baremetal-operator/pkg/provisioner/fixture"
3535
"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic"
36+
starlarkprov "github.com/metal3-io/baremetal-operator/pkg/provisioner/starlark"
3637
"github.com/metal3-io/baremetal-operator/pkg/secretutils"
3738
"github.com/metal3-io/baremetal-operator/pkg/version"
3839
ironicv1alpha1 "github.com/metal3-io/ironic-standalone-operator/api/v1alpha1"
@@ -133,6 +134,7 @@ func main() {
133134
var devLogging bool
134135
var runInTestMode bool
135136
var runInDemoMode bool
137+
var starlarkScript string
136138
var webhookPort int
137139
var restConfigQPS float64
138140
var restConfigBurst int
@@ -157,6 +159,8 @@ func main() {
157159
flag.BoolVar(&runInTestMode, "test-mode", false, "disable ironic communication")
158160
flag.BoolVar(&runInDemoMode, "demo-mode", false,
159161
"use the demo provisioner to set host states")
162+
flag.StringVar(&starlarkScript, "starlark-provisioner-script", os.Getenv("STARLARK_PROVISIONER_SCRIPT"),
163+
"path to a Starlark script implementing the provisioner interface")
160164
flag.StringVar(&healthAddr, "health-addr", ":9440",
161165
"The address the health endpoint binds to.")
162166
flag.IntVar(&webhookPort, "webhook-port", 9443, //nolint:mnd
@@ -201,6 +205,23 @@ func main() {
201205

202206
printVersion()
203207

208+
// At most one provisioner mode may be selected. Silently picking the
209+
// first true mode (the previous behavior) hides a misconfiguration
210+
// that would otherwise surface much later as confusing reconcile
211+
// behavior. Run this guard before any expensive setup so the operator
212+
// fails fast at startup. Enumerating the three pairwise conflicts
213+
// covers every "two or more true" combination (the all-three case
214+
// matches all three disjuncts).
215+
if (runInTestMode && runInDemoMode) ||
216+
(runInTestMode && starlarkScript != "") ||
217+
(runInDemoMode && starlarkScript != "") {
218+
setupLog.Error(nil, "only one provisioner mode may be set",
219+
"test-mode", runInTestMode,
220+
"demo-mode", runInDemoMode,
221+
"starlark-provisioner-script", starlarkScript)
222+
os.Exit(1)
223+
}
224+
204225
enableWebhook := webhookPort != 0
205226

206227
leaderElectionNamespace := os.Getenv("POD_NAMESPACE")
@@ -320,6 +341,13 @@ func main() {
320341
} else if runInDemoMode {
321342
ctrl.Log.Info("using demo provisioner")
322343
provisionerFactory = &demo.Demo{}
344+
} else if starlarkScript != "" {
345+
ctrl.Log.Info("using starlark provisioner", "script", starlarkScript)
346+
provisionerFactory, err = starlarkprov.NewProvisionerFactory(starlarkScript)
347+
if err != nil {
348+
setupLog.Error(err, "cannot start starlark provisioner")
349+
os.Exit(1)
350+
}
323351
} else {
324352
provLog := zap.New(zap.UseFlagOptions(&logOpts)).WithName("provisioner")
325353
// Check if we should use Ironic CR integration

pkg/provisioner/demo/demo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (p *demoProvisioner) Register(_ context.Context, _ provisioner.ManagementAc
111111
return
112112
}
113113

114-
func (p *demoProvisioner) PreprovisioningImageFormats() ([]metal3api.ImageFormat, error) {
114+
func (p *demoProvisioner) PreprovisioningImageFormats(_ context.Context) ([]metal3api.ImageFormat, error) {
115115
return nil, nil
116116
}
117117

pkg/provisioner/fixture/fixture.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (p *fixtureProvisioner) Register(_ context.Context, _ provisioner.Managemen
149149
return
150150
}
151151

152-
func (p *fixtureProvisioner) PreprovisioningImageFormats() ([]metal3api.ImageFormat, error) {
152+
func (p *fixtureProvisioner) PreprovisioningImageFormats(_ context.Context) ([]metal3api.ImageFormat, error) {
153153
return nil, nil
154154
}
155155

pkg/provisioner/ironic/ironic.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ func (p *ironicProvisioner) configureNode(ctx context.Context, data provisioner.
382382
// PreprovisioningImageFormats returns a list of acceptable formats for a
383383
// pre-provisioning image to be built by a PreprovisioningImage object. The
384384
// list should be nil if no image build is requested.
385-
func (p *ironicProvisioner) PreprovisioningImageFormats() ([]metal3api.ImageFormat, error) {
385+
func (p *ironicProvisioner) PreprovisioningImageFormats(_ context.Context) ([]metal3api.ImageFormat, error) {
386386
if !p.config.havePreprovImgBuilder {
387387
return nil, nil
388388
}

pkg/provisioner/ironic/register_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ironic
22

33
import (
4+
"context"
45
"net/http"
56
"testing"
67

@@ -964,7 +965,7 @@ func TestPreprovisioningImageFormats(t *testing.T) {
964965
prov, _ := newProvisionerWithSettings(host, bmc.Credentials{}, nil, ironicEndpoint, auth)
965966
prov.config.havePreprovImgBuilder = tc.PreprovImgEnabled
966967

967-
fmts, err := prov.PreprovisioningImageFormats()
968+
fmts, err := prov.PreprovisioningImageFormats(context.Background())
968969

969970
require.NoError(t, err)
970971
assert.Equal(t, tc.Expected, fmts)

pkg/provisioner/provisioner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ type Provisioner interface {
147147
// PreprovisioningImageFormats returns a list of acceptable formats for a
148148
// pre-provisioning image to be built by a PreprovisioningImage object. The
149149
// list should be nil if no image build is requested.
150-
PreprovisioningImageFormats() ([]metal3api.ImageFormat, error)
150+
PreprovisioningImageFormats(ctx context.Context) ([]metal3api.ImageFormat, error)
151151

152152
// InspectHardware updates the HardwareDetails field of the host with
153153
// details of devices discovered on the hardware. It may be called

0 commit comments

Comments
 (0)