Skip to content

Commit 64491e4

Browse files
committed
update ignition patch
1 parent 8956301 commit 64491e4

File tree

1 file changed

+192
-124
lines changed

1 file changed

+192
-124
lines changed

sdk_container/src/third_party/coreos-overlay/sys-apps/ignition/files/0021-support-ionoscloud.patch

Lines changed: 192 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
From 971fc5f34ec13656fe12ae4d698272f8c23a6387 Mon Sep 17 00:00:00 2001
2-
From: Jan Larwig <jan.larwig@ionos.com>
1+
From 71503fcd472dcec66bf56576b8907e5fd81b9493 Mon Sep 17 00:00:00 2001
2+
From: Mohamed Chiheb Ben Jemaa <mc.benjemaa@gmail.com>
33
Date: Thu, 17 Oct 2024 15:43:10 +0200
4-
Subject: [PATCH] providers: add support for ionos cloud
4+
Subject: [PATCH 21/21] providers: add support for ionos cloud
55

66
Add support for IONOS Cloud
7-
87
Add check to ignore cloud-config
8+
Add mounting of root partition
9+
Add better documentation
10+
11+
Co-authored-by: Jan Larwig <[email protected]>
912
---
1013
docs/release-notes.md | 2 +
1114
docs/supported-platforms.md | 2 +
12-
internal/providers/ionoscloud/ionoscloud.go | 149 ++++++++++++++++++++
15+
internal/providers/ionoscloud/ionoscloud.go | 200 ++++++++++++++++++++
1316
internal/providers/proxmoxve/proxmoxve.go | 4 +-
14-
internal/providers/util/cloudconfig.go | 13 ++
17+
internal/providers/util/cloudconfig.go | 27 +++
1518
internal/register/providers.go | 1 +
16-
6 files changed, 168 insertions(+), 3 deletions(-)
19+
6 files changed, 233 insertions(+), 3 deletions(-)
1720
create mode 100644 internal/providers/ionoscloud/ionoscloud.go
1821
create mode 100644 internal/providers/util/cloudconfig.go
1922

@@ -31,18 +34,18 @@ index 342fb1aa..2f25b609 100644
3134

3235
### Bug fixes
3336
diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md
34-
index eef319b2..c6846087 100644
37+
index 232482e6..696c9604 100644
3538
--- a/docs/supported-platforms.md
3639
+++ b/docs/supported-platforms.md
37-
@@ -20,6 +20,7 @@ Ignition is currently supported for the following platforms:
40+
@@ -22,6 +22,7 @@ Ignition is currently supported for the following platforms:
3841
* [Hetzner Cloud] (`hetzner`) - Ignition will read its configuration from the instance userdata. Cloud SSH keys are handled separately.
3942
* [Microsoft Hyper-V] (`hyperv`) - Ignition will read its configuration from the `ignition.config` key in pool 0 of the Hyper-V Data Exchange Service (KVP). Values are limited to approximately 1 KiB of text, so Ignition can also read and concatenate multiple keys named `ignition.config.0`, `ignition.config.1`, and so on.
4043
* [IBM Cloud] (`ibmcloud`) - Ignition will read its configuration from the instance userdata. Cloud SSH keys are handled separately.
41-
+* [IONOS Cloud] (`ionoscloud`) - Ignition will read its configuration from the instance user-data. Per default the user-data is retrieved from a partition or disk with the label `OEM-CONFIG` which can be customized using the environment variable `IGNITION_CONFIG_DISK_LABEL`.
44+
+* [IONOS Cloud] (`ionoscloud`) - Ignition will read its configuration from the instance user-data. Per default the user-data are injected on a disk or partition with the label `OEM` which can be customized using the environment variable `IGNITION_CONFIG_DEVICE_LABEL`.
4245
* [KubeVirt] (`kubevirt`) - Ignition will read its configuration from the instance userdata via config drive. Cloud SSH keys are handled separately.
4346
* Bare Metal (`metal`) - Use the `ignition.config.url` kernel parameter to provide a URL to the configuration. The URL can use the `http://`, `https://`, `tftp://`, `s3://`, `arn:`, or `gs://` schemes to specify a remote config.
4447
* [Nutanix] (`nutanix`) - Ignition will read its configuration from the instance userdata via config drive. Cloud SSH keys are handled separately.
45-
@@ -52,6 +53,7 @@ For most cloud providers, cloud SSH keys and custom network configuration are ha
48+
@@ -57,6 +58,7 @@ For most cloud providers, cloud SSH keys and custom network configuration are ha
4649
[Hetzner Cloud]: https://www.hetzner.com/cloud
4750
[Microsoft Hyper-V]: https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/
4851
[IBM Cloud]: https://www.ibm.com/cloud/vpc
@@ -52,10 +55,10 @@ index eef319b2..c6846087 100644
5255
[OpenStack]: https://www.openstack.org/
5356
diff --git a/internal/providers/ionoscloud/ionoscloud.go b/internal/providers/ionoscloud/ionoscloud.go
5457
new file mode 100644
55-
index 00000000..cc660998
58+
index 00000000..69f3ccd5
5659
--- /dev/null
5760
+++ b/internal/providers/ionoscloud/ionoscloud.go
58-
@@ -0,0 +1,149 @@
61+
@@ -0,0 +1,200 @@
5962
+// Copyright 2024 Red Hat, Inc.
6063
+//
6164
+// Licensed under the Apache License, Version 2.0 (the "License");
@@ -83,130 +86,181 @@ index 00000000..cc660998
8386
+package ionoscloud
8487
+
8588
+import (
86-
+ "context"
87-
+ "fmt"
88-
+ "os"
89-
+ "os/exec"
90-
+ "path/filepath"
91-
+ "time"
92-
+
93-
+ "github.com/flatcar/ignition/v2/config/v3_6_experimental/types"
94-
+ "github.com/flatcar/ignition/v2/internal/distro"
95-
+ "github.com/flatcar/ignition/v2/internal/log"
96-
+ "github.com/flatcar/ignition/v2/internal/platform"
97-
+ "github.com/flatcar/ignition/v2/internal/providers/util"
98-
+ "github.com/flatcar/ignition/v2/internal/resource"
99-
+ ut "github.com/flatcar/ignition/v2/internal/util"
100-
+
101-
+ "github.com/coreos/vcontext/report"
89+
+ "context"
90+
+ "fmt"
91+
+ "os"
92+
+ "os/exec"
93+
+ "path/filepath"
94+
+ "strings"
95+
+ "time"
96+
+
97+
+ "github.com/flatcar/ignition/v2/config/v3_6_experimental/types"
98+
+ "github.com/flatcar/ignition/v2/internal/distro"
99+
+ "github.com/flatcar/ignition/v2/internal/log"
100+
+ "github.com/flatcar/ignition/v2/internal/platform"
101+
+ "github.com/flatcar/ignition/v2/internal/providers/util"
102+
+ "github.com/flatcar/ignition/v2/internal/resource"
103+
+ ut "github.com/flatcar/ignition/v2/internal/util"
104+
+
105+
+ "github.com/coreos/vcontext/report"
102106
+)
103107
+
104108
+const (
105-
+ deviceLabelEnvVar = "IGNITION_CONFIG_DEVICE_LABEL"
106-
+ defaultDeviceLabel = "OEM"
107-
+ userDataPath = "/config/user-data"
109+
+ deviceLabelKernelFlag = "ignition.config.device"
110+
+ defaultDeviceLabel = "OEM"
111+
+ userDataKernelFlag = "ignition.config.path"
112+
+ defaultUserDataPath = "config.ign"
108113
+)
109114
+
110115
+func init() {
111-
+ platform.Register(platform.Provider{
112-
+ Name: "ionoscloud",
113-
+ Fetch: fetchConfig,
114-
+ })
116+
+ platform.Register(platform.Provider{
117+
+ Name: "ionoscloud",
118+
+ Fetch: fetchConfig,
119+
+ })
115120
+}
116121
+
117122
+func fetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) {
118-
+ var data []byte
119-
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
120-
+
121-
+ dispatch := func(name string, fn func() ([]byte, error)) {
122-
+ raw, err := fn()
123-
+ if err != nil {
124-
+ switch err {
125-
+ case context.Canceled:
126-
+ case context.DeadlineExceeded:
127-
+ f.Logger.Err("timed out while fetching config from %s", name)
128-
+ default:
129-
+ f.Logger.Err("failed to fetch config from %s: %v", name, err)
130-
+ }
131-
+ return
132-
+ }
133-
+
134-
+ data = raw
135-
+ cancel()
136-
+ }
137-
+
138-
+ deviceLabel := os.Getenv(deviceLabelEnvVar)
139-
+ if deviceLabel == "" {
140-
+ deviceLabel = defaultDeviceLabel
141-
+ }
142-
+
143-
+ go dispatch(
144-
+ "load config from disk", func() ([]byte, error) {
145-
+ return fetchConfigFromDevice(f.Logger, ctx, filepath.Join(distro.DiskByLabelDir(), deviceLabel))
146-
+ },
147-
+ )
148-
+
149-
+ <-ctx.Done()
150-
+ if ctx.Err() == context.DeadlineExceeded {
151-
+ f.Logger.Info("disk was not available in time. Continuing without a config...")
152-
+ }
153-
+
154-
+ return util.ParseConfig(f.Logger, data)
123+
+ var data []byte
124+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
125+
+
126+
+ dispatch := func(name string, fn func() ([]byte, error)) {
127+
+ raw, err := fn()
128+
+ if err != nil {
129+
+ switch err {
130+
+ case context.Canceled:
131+
+ case context.DeadlineExceeded:
132+
+ f.Logger.Err("timed out while fetching config from %s", name)
133+
+ default:
134+
+ f.Logger.Err("failed to fetch config from %s: %v", name, err)
135+
+ }
136+
+ return
137+
+ }
138+
+
139+
+ data = raw
140+
+ cancel()
141+
+ }
142+
+
143+
+ deviceLabel, userDataPath, err := readFromKernelParams(f.Logger)
144+
+
145+
+ if err != nil {
146+
+ f.Logger.Err("couldn't read kernel parameters: %v", err)
147+
+ return types.Config{}, report.Report{}, err
148+
+ }
149+
+
150+
+ if deviceLabel == "" {
151+
+ deviceLabel = defaultDeviceLabel
152+
+ }
153+
+
154+
+ if userDataPath == "" {
155+
+ userDataPath = defaultUserDataPath
156+
+ }
157+
+
158+
+ go dispatch(
159+
+ "load config from disk", func() ([]byte, error) {
160+
+ return fetchConfigFromDevice(f.Logger, ctx, deviceLabel, userDataPath)
161+
+ },
162+
+ )
163+
+
164+
+ <-ctx.Done()
165+
+ if ctx.Err() == context.DeadlineExceeded {
166+
+ f.Logger.Info("disk was not available in time. Continuing without a config...")
167+
+ }
168+
+
169+
+ return util.ParseConfig(f.Logger, data)
155170
+}
156171
+
157172
+func fileExists(path string) bool {
158-
+ _, err := os.Stat(path)
159-
+ return (err == nil)
173+
+ _, err := os.Stat(path)
174+
+ return (err == nil)
175+
+}
176+
+
177+
+func fetchConfigFromDevice(logger *log.Logger,
178+
+ ctx context.Context,
179+
+ deviceLabel string,
180+
+ dataPath string,
181+
+) ([]byte, error) {
182+
+ device := filepath.Join(distro.DiskByLabelDir(), deviceLabel)
183+
+ for !fileExists(device) {
184+
+ logger.Debug("disk (%q) not found. Waiting...", device)
185+
+ select {
186+
+ case <-time.After(time.Second):
187+
+ case <-ctx.Done():
188+
+ return nil, ctx.Err()
189+
+ }
190+
+ }
191+
+
192+
+ logger.Debug("creating temporary mount point")
193+
+ mnt, err := os.MkdirTemp("", "ignition-config")
194+
+ if err != nil {
195+
+ return nil, fmt.Errorf("failed to create temp directory: %v", err)
196+
+ }
197+
+ defer os.Remove(mnt)
198+
+
199+
+ cmd := exec.Command(distro.MountCmd(), "-o", "ro", "-t", "auto", device, mnt)
200+
+ if _, err := logger.LogCmd(cmd, "mounting disk"); err != nil {
201+
+ return nil, err
202+
+ }
203+
+ defer func() {
204+
+ _ = logger.LogOp(
205+
+ func() error {
206+
+ return ut.UmountPath(mnt)
207+
+ },
208+
+ "unmounting %q at %q", device, mnt,
209+
+ )
210+
+ }()
211+
+
212+
+ if !fileExists(filepath.Join(mnt, dataPath)) {
213+
+ return nil, nil
214+
+ }
215+
+
216+
+ contents, err := os.ReadFile(filepath.Join(mnt, dataPath))
217+
+ if err != nil {
218+
+ return nil, err
219+
+ }
220+
+
221+
+ if util.IsCloudConfig(contents) {
222+
+ logger.Debug("disk (%q) contains a cloud-config configuration, ignoring", device)
223+
+ return nil, nil
224+
+ }
225+
+
226+
+ return contents, nil
227+
+}
228+
+
229+
+func readFromKernelParams(logger *log.Logger) (string, string, error) {
230+
+ args, err := os.ReadFile(distro.KernelCmdlinePath())
231+
+ if err != nil {
232+
+ return "", "", err
233+
+ }
234+
+
235+
+ deviceLabel, userDataPath := parseParams(args)
236+
+ logger.Debug("parsed device label from parameters: %s", deviceLabel)
237+
+ logger.Debug("parsed user-data path from parameters: %s", userDataPath)
238+
+ return deviceLabel, userDataPath, nil
160239
+}
161240
+
162-
+func fetchConfigFromDevice(logger *log.Logger, ctx context.Context, device string) ([]byte, error) {
163-
+ for !fileExists(device) {
164-
+ logger.Debug("disk (%q) not found. Waiting...", device)
165-
+ select {
166-
+ case <-time.After(time.Second):
167-
+ case <-ctx.Done():
168-
+ return nil, ctx.Err()
169-
+ }
170-
+ }
171-
+
172-
+ logger.Debug("creating temporary mount point")
173-
+ mnt, err := os.MkdirTemp("", "ignition-config")
174-
+ if err != nil {
175-
+ return nil, fmt.Errorf("failed to create temp directory: %v", err)
176-
+ }
177-
+ defer os.Remove(mnt)
178-
+
179-
+ cmd := exec.Command(distro.MountCmd(), "-o", "ro", "-t", "auto", device, mnt)
180-
+ if _, err := logger.LogCmd(cmd, "mounting disk"); err != nil {
181-
+ return nil, err
182-
+ }
183-
+ defer func() {
184-
+ _ = logger.LogOp(
185-
+ func() error {
186-
+ return ut.UmountPath(mnt)
187-
+ },
188-
+ "unmounting %q at %q", device, mnt,
189-
+ )
190-
+ }()
191-
+
192-
+ if !fileExists(filepath.Join(mnt, userDataPath)) {
193-
+ return nil, nil
194-
+ }
195-
+
196-
+ contents, err := os.ReadFile(filepath.Join(mnt, userDataPath))
197-
+ if err != nil {
198-
+ return nil, err
199-
+ }
200-
+
201-
+ if util.IsCloudConfig(contents) {
202-
+ logger.Debug("disk (%q) contains a cloud-config configuration, ignoring", device)
203-
+ return nil, nil
204-
+ }
205-
+
206-
+ return contents, nil
241+
+func parseParams(args []byte) (deviceLabel, userDataPath string) {
242+
+ for _, arg := range strings.Split(string(args), " ") {
243+
+ parts := strings.SplitN(strings.TrimSpace(arg), "=", 2)
244+
+ if len(parts) != 2 {
245+
+ continue
246+
+ }
247+
+
248+
+ key := parts[0]
249+
+ value := parts[1]
250+
+
251+
+ if key == deviceLabelKernelFlag {
252+
+ deviceLabel = value
253+
+ }
254+
+
255+
+ if key == userDataKernelFlag {
256+
+ userDataPath = value
257+
+ }
258+
+ }
259+
+
260+
+ return
207261
+}
208262
diff --git a/internal/providers/proxmoxve/proxmoxve.go b/internal/providers/proxmoxve/proxmoxve.go
209-
index 490bfe30..b0dbb481 100644
263+
index cbfe7c7d..58525c50 100644
210264
--- a/internal/providers/proxmoxve/proxmoxve.go
211265
+++ b/internal/providers/proxmoxve/proxmoxve.go
212266
@@ -20,7 +20,6 @@
@@ -229,10 +283,24 @@ index 490bfe30..b0dbb481 100644
229283
}
230284
diff --git a/internal/providers/util/cloudconfig.go b/internal/providers/util/cloudconfig.go
231285
new file mode 100644
232-
index 00000000..abe9a2b6
286+
index 00000000..82ed9f36
233287
--- /dev/null
234288
+++ b/internal/providers/util/cloudconfig.go
235-
@@ -0,0 +1,13 @@
289+
@@ -0,0 +1,27 @@
290+
+// Copyright 2024 Red Hat, Inc.
291+
+//
292+
+// Licensed under the Apache License, Version 2.0 (the "License");
293+
+// you may not use this file except in compliance with the License.
294+
+// You may obtain a copy of the License at
295+
+//
296+
+// http://www.apache.org/licenses/LICENSE-2.0
297+
+//
298+
+// Unless required by applicable law or agreed to in writing, software
299+
+// distributed under the License is distributed on an "AS IS" BASIS,
300+
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
301+
+// See the License for the specific language governing permissions and
302+
+// limitations under the License.
303+
+
236304
+package util
237305
+
238306
+import (
@@ -247,7 +315,7 @@ index 00000000..abe9a2b6
247315
+ return false
248316
+}
249317
diff --git a/internal/register/providers.go b/internal/register/providers.go
250-
index bda4b7cf..63249c7d 100644
318+
index eb4bd9d2..f37aa906 100644
251319
--- a/internal/register/providers.go
252320
+++ b/internal/register/providers.go
253321
@@ -29,6 +29,7 @@ import (

0 commit comments

Comments
 (0)