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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY internal/controller/ internal/controller/
COPY server/ server/
COPY templates/ templates/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
Expand All @@ -29,6 +30,7 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o ma
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
COPY --from=builder /workspace/templates/ templates/
USER 65532:65532

ENTRYPOINT ["/manager"]
6 changes: 0 additions & 6 deletions api/v1alpha1/httpbootconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,6 @@ type HTTPBootConfigList struct {
Items []HTTPBootConfig `json:"items"`
}

const (
DefaultIgnitionKey = "ignition"
SystemUUIDIndexKey = "spec.systemUUID"
SystemIPIndexKey = "spec.systemIPs"
)

func init() {
SchemeBuilder.Register(&HTTPBootConfig{}, &HTTPBootConfigList{})
}
77 changes: 77 additions & 0 deletions api/v1alpha1/ipxebootconfig_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// IPXEBootConfigSpec defines the desired state of IPXEBootConfig
type IPXEBootConfigSpec struct {
// Important: Run "make" to regenerate code after modifying this file
SystemUUID string `json:"systemUUID,omitempty"`
SystemIPs []string `json:"systemIPs,omitempty"` // TODO: Add the custom serialization. For now validate at the controller.
// TODO: remove image as this is not needed
Image string `json:"image,omitempty"`
KernelURL string `json:"kernelURL,omitempty"`
InitrdURL string `json:"initrdURL,omitempty"`
SquashfsURL string `json:"squashfsURL,omitempty"`
// TODO: remove later
IPXEServerURL string `json:"ipxeServerURL,omitempty"`
IgnitionSecretRef *corev1.LocalObjectReference `json:"ignitionSecretRef,omitempty"`
IPXEScriptSecretRef *corev1.LocalObjectReference `json:"ipxeScriptSecretRef,omitempty"`
}

type IPXEBootConfigState string

const (
IPXEBootConfigStateReady IPXEBootConfigState = "Ready"
IPXEBootConfigStatePending IPXEBootConfigState = "Pending"
IPXEBootConfigStateError IPXEBootConfigState = "Error"
)

// IPXEBootConfigStatus defines the observed state of IPXEBootConfig
type IPXEBootConfigStatus struct {
// Important: Run "make" to regenerate code after modifying this file
State IPXEBootConfigState `json:"state,omitempty"`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state`
//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
// +genclient

// IPXEBootConfig is the Schema for the ipxebootconfigs API
type IPXEBootConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec IPXEBootConfigSpec `json:"spec,omitempty"`
Status IPXEBootConfigStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// IPXEBootConfigList contains a list of IPXEBootConfig
type IPXEBootConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []IPXEBootConfig `json:"items"`
}

const (
DefaultIgnitionKey = "ignition"
DefaultIPXEScriptKey = "ipxe-script"
SystemUUIDIndexKey = "spec.systemUUID"
SystemIPIndexKey = "spec.systemIPs"
)

func init() {
SchemeBuilder.Register(&IPXEBootConfig{}, &IPXEBootConfigList{})
}
104 changes: 104 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 93 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ var (

const (
// core controllers
machineBootConfigControllerHttp = "machinebootconfighttp"
ipxeBootConfigController = "ipxebootconfig"
serverBootConfigControllerPxe = "serverbootconfigpxe"
httpBootConfigController = "httpbootconfig"
serverBootConfigControllerHttp = "serverbootconfighttp"
machineBootConfigControllerHttp = "machinebootconfighttp"
)

func init() {
Expand All @@ -58,6 +60,7 @@ func init() {

func main() {
ctx := ctrl.LoggerInto(ctrl.SetupSignalHandler(), setupLog)
defaultIpxeTemplateData := NewDefaultIPXETemplateData()
defaultHttpUKIURL := NewDefaultHTTPBootData()

var metricsAddr string
Expand All @@ -66,14 +69,22 @@ func main() {
var secureMetrics bool
var enableHTTP2 bool
var bootserverAddr string
var imageProxyServerAddr string
var ipxeServiceURL string
var ipxeServiceProtocol string
var ipxeServicePort int
var imageServerURL string
var bootconfigNamespace string

flag.IntVar(&ipxeServicePort, "ipxe-service-port", 5000, "IPXE Service port to listen on.")
flag.StringVar(&ipxeServiceProtocol, "ipxe-service-protocol", "http", "IPXE Service Protocol.")
flag.StringVar(&ipxeServiceURL, "ipxe-service-url", "", "IPXE Service URL.")
flag.StringVar(&imageServerURL, "image-server-url", "", "OS Image Server URL.")
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.StringVar(&bootserverAddr, "boot-server-address", ":8082", "The address the boot-server binds to.")
flag.StringVar(&bootconfigNamespace, "machinebootconfig-namespace", "default", "The namespace in which HTTPBootConfigs should be created for MachineBootConfiguration Controller.")
flag.StringVar(&imageProxyServerAddr, "image-proxy-server-address", ":8083", "The address the image-proxy-server binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
Expand All @@ -84,6 +95,8 @@ func main() {

controllers := switches.New(
// core controllers
ipxeBootConfigController,
serverBootConfigControllerPxe,
serverBootConfigControllerHttp,
machineBootConfigControllerHttp,
httpBootConfigController,
Expand All @@ -104,6 +117,17 @@ func main() {

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

// set the correct ipxe service URL by getting the address from the environment
var ipxeServiceAddr string
if ipxeServiceURL == "" {
ipxeServiceAddr = os.Getenv("IPXE_SERVER_ADDRESS")
if ipxeServiceAddr == "" {
setupLog.Error(nil, "failed to set the ipxe service URL as no address is provided")
os.Exit(1)
}
ipxeServiceURL = fmt.Sprintf("%s://%s:%d", ipxeServiceProtocol, ipxeServiceAddr, ipxeServicePort)
}

// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancelation and
Expand Down Expand Up @@ -152,6 +176,27 @@ func main() {
os.Exit(1)
}

if controllers.Enabled(ipxeBootConfigController) {
if err = (&controller.IPXEBootConfigReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "IPXEBootConfig")
os.Exit(1)
}
}

if controllers.Enabled(serverBootConfigControllerPxe) {
if err = (&controller.ServerBootConfigurationPXEReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
IPXEServiceURL: ipxeServiceURL,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ServerBootConfigPxe")
os.Exit(1)
}
}

if controllers.Enabled(serverBootConfigControllerHttp) {
if err = (&controller.ServerBootConfigurationHTTPReconciler{
Client: mgr.GetClient(),
Expand Down Expand Up @@ -196,18 +241,31 @@ func main() {
os.Exit(1)
}

if err := IndexIPXEBootConfigBySystemUUID(ctx, mgr); err != nil {
setupLog.Error(err, "unable to set up indexer for IPXEBootConfig SystemUUID")
os.Exit(1)
}

if err := IndexHTTPBootConfigBySystemUUID(ctx, mgr); err != nil {
setupLog.Error(err, "unable to set up indexer for HTTPBootConfig SystemUUID")
os.Exit(1)
}

if err := IndexIPXEBootConfigBySystemIPs(ctx, mgr); err != nil {
setupLog.Error(err, "unable to set up indexer for IPXEBootConfig SystemIPs")
os.Exit(1)
}

if err := IndexHTTPBootConfigBySystemIPs(ctx, mgr); err != nil {
setupLog.Error(err, "unable to set up indexer for HTTPBootConfig SystemIP")
os.Exit(1)
}

setupLog.Info("starting boot-server")
go bootserver.RunBootServer(mgr.GetClient(), serverLog.WithName("bootserver"), bootserverAddr, *defaultHttpUKIURL)
go bootserver.RunBootServer(bootserverAddr, ipxeServiceURL, mgr.GetClient(), serverLog.WithName("bootserver"), *defaultIpxeTemplateData, *defaultHttpUKIURL)

setupLog.Info("starting image-proxy-server")
go bootserver.RunImageProxyServer(imageProxyServerAddr, mgr.GetClient(), serverLog.WithName("imageproxyserver"))

setupLog.Info("starting manager")
if err := mgr.Start(ctx); err != nil {
Expand All @@ -216,6 +274,29 @@ func main() {
}
}

func IndexIPXEBootConfigBySystemUUID(ctx context.Context, mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(
ctx,
&bootv1alpha1.IPXEBootConfig{},
bootv1alpha1.SystemUUIDIndexKey,
func(Obj client.Object) []string {
ipxeBootConfig := Obj.(*bootv1alpha1.IPXEBootConfig)
return []string{ipxeBootConfig.Spec.SystemUUID}
},
)
}

func IndexIPXEBootConfigBySystemIPs(ctx context.Context, mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(
ctx, &bootv1alpha1.IPXEBootConfig{},
bootv1alpha1.SystemIPIndexKey,
func(Obj client.Object) []string {
ipxeBootConfig := Obj.(*bootv1alpha1.IPXEBootConfig)
return ipxeBootConfig.Spec.SystemIPs
},
)
}

func IndexHTTPBootConfigBySystemUUID(ctx context.Context, mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(
ctx,
Expand All @@ -240,6 +321,16 @@ func IndexHTTPBootConfigBySystemIPs(ctx context.Context, mgr ctrl.Manager) error
)
}

func NewDefaultIPXETemplateData() *bootserver.IPXETemplateData {
var cfg bootserver.IPXETemplateData
flag.StringVar(&cfg.KernelURL, "default-kernel-url", "", "Default URL for the kernel")
flag.StringVar(&cfg.InitrdURL, "default-initrd-url", "", "Default URL for the initrd")
flag.StringVar(&cfg.SquashfsURL, "default-squashfs-url", "", "Default URL for the squashfs")
flag.StringVar(&cfg.IPXEServerURL, "default-ipxe-server-url", "", "Default IPXE Server URL to while generating ipxe-script")

return &cfg
}

func NewDefaultHTTPBootData() *string {
var defaultUKIURL string
flag.StringVar(&defaultUKIURL, "default-httpboot-uki-url", "", "Default UKI URL for http boot")
Expand Down
Loading