Skip to content
Open
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
6 changes: 4 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ updates:
- dependency-name: "sigs.k8s.io/controller-runtime"
update-types:
["version-update:semver-major", "version-update:semver-minor"]
# Ignore k8s and its transitives modules as they are upgraded manually together with controller-runtime.
# Ignore k8s and its transitives modules as they are upgraded manually
# together with controller-runtime.
- dependency-name: "k8s.io/*"
update-types:
["version-update:semver-major", "version-update:semver-minor"]
Expand All @@ -30,7 +31,8 @@ updates:
- dependency-name: "google.golang.org/grpc"
update-types:
["version-update:semver-major", "version-update:semver-minor"]
# Bumping the kustomize API independently can break compatibility with client-go as they share k8s.io/kube-openapi as a dependency.
# Bumping the kustomize API independently can break compatibility with
# client-go as they share k8s.io/kube-openapi as a dependency.
- dependency-name: "sigs.k8s.io/kustomize/api"
update-types:
["version-update:semver-major", "version-update:semver-minor"]
Expand Down
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/ionos-cloud/cluster-api-provider-ionoscloud
go 1.22.0

require (
github.com/flatcar/ignition v0.36.2
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
Expand All @@ -16,6 +17,7 @@ require (
k8s.io/apimachinery v0.30.7
k8s.io/client-go v0.30.7
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20231127182322-b307cd553661
sigs.k8s.io/cluster-api v1.8.5
sigs.k8s.io/cluster-api/test v1.8.5
sigs.k8s.io/controller-runtime v0.18.6
Expand All @@ -31,6 +33,7 @@ require (
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/adrg/xdg v0.5.0 // indirect
github.com/ajeddeloh/go-json v0.0.0-20200220154158-5ae607161559 // indirect
github.com/alessio/shellescape v1.4.2 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
Expand All @@ -39,6 +42,8 @@ require (
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v27.1.1+incompatible // indirect
Expand Down Expand Up @@ -107,6 +112,7 @@ require (
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/vincent-petithory/dataurl v1.0.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect
Expand All @@ -117,6 +123,7 @@ require (
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.33.0 // indirect
Expand All @@ -141,7 +148,6 @@ require (
k8s.io/cluster-bootstrap v0.30.3 // indirect
k8s.io/component-base v0.30.3 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kind v0.24.0 // indirect
Expand Down
224 changes: 224 additions & 0 deletions go.sum

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions internal/service/cloud/cloudinit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright 2024 IONOS Cloud.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cloud

import (
"encoding/base64"
"fmt"
)

func enrichCloudInitConfig(machineName string, userData string) string {
const bootCmdFormat = `bootcmd:
- echo %[1]s > /etc/hostname
- hostname %[1]s
`
bootCmdString := fmt.Sprintf(bootCmdFormat, machineName)
enrichedData := fmt.Sprintf("%s\n%s", userData, bootCmdString)

return base64.StdEncoding.EncodeToString([]byte(enrichedData))
}
102 changes: 102 additions & 0 deletions internal/service/cloud/ignition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Copyright 2024 IONOS Cloud.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cloud

import (
"encoding/json"
"fmt"
"net/url"

ignition "github.com/flatcar/ignition/config/v2_3"
igntypes "github.com/flatcar/ignition/config/v2_3/types"
"k8s.io/utils/ptr"

infrav1 "github.com/ionos-cloud/cluster-api-provider-ionoscloud/api/v1alpha1"
)

func enrichIgnitionConfig(machine *infrav1.IonosCloudMachine, bootstrapData []byte) ([]byte, error) {
ign, err := convertToIgnition(bootstrapData)
if err != nil {
return nil, fmt.Errorf("converting bootstrap-data to Ignition: %w", err)
}

baseConfig := getIgnitionBaseConfig(machine)
ign = ignition.Append(ign, baseConfig)

userData, err := json.Marshal(&ign)
if err != nil {
return nil, fmt.Errorf("marshaling generated Ignition config into JSON: %w", err)
}

return userData, nil
}

func convertToIgnition(data []byte) (igntypes.Config, error) {
cfg, reports, err := ignition.Parse(data)
if err != nil {
return igntypes.Config{}, fmt.Errorf("parsing Ignition config: %w", err)
}
if reports.IsFatal() {
return igntypes.Config{}, fmt.Errorf("error parsing Ignition config: %v", reports.String())
}

return cfg, nil
}

func getIgnitionBaseConfig(machine *infrav1.IonosCloudMachine) igntypes.Config {
metadata := fmt.Sprintf("COREOS_CUSTOM_HOSTNAME=%s\n", machine.Name)
return igntypes.Config{
Storage: igntypes.Storage{
Files: []igntypes.File{
{
Node: igntypes.Node{
Filesystem: "root",
Path: "/etc/hostname",
Overwrite: ptr.To(true),
},
FileEmbedded1: igntypes.FileEmbedded1{
Mode: ptr.To(0o644),
Contents: igntypes.FileContents{
Source: "data:," + machine.Name,
},
},
},
{
Node: igntypes.Node{
Filesystem: "root",
Path: "/etc/ionoscloud-env",
Overwrite: ptr.To(true),
},
FileEmbedded1: igntypes.FileEmbedded1{
Mode: ptr.To(420),
Contents: igntypes.FileContents{
Source: "data:," + url.PathEscape(metadata),
},
},
},
},
},
Systemd: igntypes.Systemd{
Units: []igntypes.Unit{
{
Name: "systemd-resolved.service",
Enable: true,
},
},
},
}
}
38 changes: 29 additions & 9 deletions internal/service/cloud/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ import (
"github.com/ionos-cloud/cluster-api-provider-ionoscloud/scope"
)

const (
// FormatCloudInit is the default bootstrap data format.
FormatCloudInit = "cloud-config"
// FormatIgnition is used for ignition support.
FormatIgnition = "ignition"
)

// ReconcileServer ensures the cluster server exist, creating one if it doesn't.
func (s *Service) ReconcileServer(ctx context.Context, ms *scope.Machine) (requeue bool, retErr error) {
log := s.logger.WithName("ReconcileServer")
Expand Down Expand Up @@ -318,6 +325,11 @@ func (s *Service) createServer(ctx context.Context, secret *corev1.Secret, ms *s
return errors.New("unable to obtain bootstrap data from secret")
}

bootstrapFormat := FormatCloudInit
if f, exists := secret.Data["format"]; exists {
bootstrapFormat = string(f)
}

lan, err := s.getLAN(ctx, ms)
if err != nil {
return err
Expand All @@ -334,7 +346,11 @@ func (s *Service) createServer(ctx context.Context, secret *corev1.Secret, ms *s
return fmt.Errorf("image lookup: %w", err)
}

renderedData := s.renderUserData(ms, string(bootstrapData))
renderedData, err := s.enrichUserData(ms, bootstrapFormat, string(bootstrapData))
if err != nil {
return fmt.Errorf("enriching user data: %w", err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can improve user visibility here.
by setting a condition and throwing a warning event.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly do you mean by setting a condition?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like:

conditions.MarkFalse(
	ms.IonosMachine,
	infrav1.MachineProvisionedCondition,
	infrav1.RenderBootstrapDataReason,
	clusterv1.ConditionSeverityInfo, "",
)

}

copySpec := ms.IonosMachine.Spec.DeepCopy()
entityParams := serverEntityParams{
boostrapData: renderedData,
Expand Down Expand Up @@ -464,15 +480,19 @@ func (s *Service) buildServerEntities(ms *scope.Machine, params serverEntityPara
}
}

func (*Service) renderUserData(ms *scope.Machine, input string) string {
const bootCmdFormat = `bootcmd:
- echo %[1]s > /etc/hostname
- hostname %[1]s
`
bootCmdString := fmt.Sprintf(bootCmdFormat, ms.IonosMachine.Name)
input = fmt.Sprintf("%s\n%s", input, bootCmdString)
func (*Service) enrichUserData(ms *scope.Machine, format string, userData string) (string, error) {
switch format {
case FormatIgnition:
enrichedData, err := enrichIgnitionConfig(ms.IonosMachine, []byte(userData))
if err != nil {
return "", fmt.Errorf("couldn't enrich ignition config: %w", err)
}

return base64.StdEncoding.EncodeToString([]byte(input))
return base64.StdEncoding.EncodeToString(enrichedData), nil

default:
return enrichCloudInitConfig(ms.IonosMachine.Name, userData), nil
}
}

func (*Service) serversURL(datacenterID string) string {
Expand Down
Loading