@@ -10,10 +10,11 @@ Add check to ignore cloud-config
10
10
docs/release-notes.md | 2 +
11
11
docs/supported-platforms.md | 2 +
12
12
internal/providers/ionoscloud/ionoscloud.go | 149 ++++++++++++++++++++
13
+ internal/providers/ionoscloud/ionoscloud.go | 200 ++++++++++++++++++++
13
14
internal/providers/proxmoxve/proxmoxve.go | 4 +-
14
15
internal/providers/util/cloudconfig.go | 13 ++
15
16
internal/register/providers.go | 1 +
16
- 6 files changed, 168 insertions(+), 3 deletions(-)
17
+ 6 files changed, 219 insertions(+), 3 deletions(-)
17
18
create mode 100644 internal/providers/ionoscloud/ionoscloud.go
18
19
create mode 100644 internal/providers/util/cloudconfig.go
19
20
@@ -55,7 +56,7 @@ new file mode 100644
55
56
index 00000000..cc660998
56
57
--- /dev/null
57
58
+++ b/internal/providers/ionoscloud/ionoscloud.go
58
- @@ -0,0 +1,149 @@
59
+ @@ -0,0 +1,200 @@
59
60
+ // Copyright 2024 Red Hat, Inc.
60
61
+ //
61
62
+ // Licensed under the Apache License, Version 2.0 (the "License");
@@ -83,127 +84,178 @@ index 00000000..cc660998
83
84
+ package ionoscloud
84
85
+
85
86
+ 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"
87
+ + "context"
88
+ + "fmt"
89
+ + "os"
90
+ + "os/exec"
91
+ + "path/filepath"
92
+ + "strings"
93
+ + "time"
94
+ +
95
+ + "github.com/flatcar/ignition/v2/config/v3_6_experimental/types"
96
+ + "github.com/flatcar/ignition/v2/internal/distro"
97
+ + "github.com/flatcar/ignition/v2/internal/log"
98
+ + "github.com/flatcar/ignition/v2/internal/platform"
99
+ + "github.com/flatcar/ignition/v2/internal/providers/util"
100
+ + "github.com/flatcar/ignition/v2/internal/resource"
101
+ + ut "github.com/flatcar/ignition/v2/internal/util"
102
+ +
103
+ + "github.com/coreos/vcontext/report"
102
104
+ )
103
105
+
104
106
+ const (
105
- + deviceLabelEnvVar = "IGNITION_CONFIG_DEVICE_LABEL"
106
- + defaultDeviceLabel = "OEM"
107
- + userDataPath = "/config/user-data"
107
+ + deviceLabelKernelFlag = "ignition.config.device"
108
+ + defaultDeviceLabel = "OEM"
109
+ + userDataKernelFlag = "ignition.config.path"
110
+ + defaultUserDataPath = "config.ign"
108
111
+ )
109
112
+
110
113
+ func init() {
111
- + platform.Register(platform.Provider{
112
- + Name: "ionoscloud",
113
- + Fetch: fetchConfig,
114
- + })
114
+ + platform.Register(platform.Provider{
115
+ + Name: "ionoscloud",
116
+ + Fetch: fetchConfig,
117
+ + })
115
118
+ }
116
119
+
117
120
+ 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)
121
+ + var data []byte
122
+ + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
123
+ +
124
+ + dispatch := func(name string, fn func() ([]byte, error)) {
125
+ + raw, err := fn()
126
+ + if err != nil {
127
+ + switch err {
128
+ + case context.Canceled:
129
+ + case context.DeadlineExceeded:
130
+ + f.Logger.Err("timed out while fetching config from %s", name)
131
+ + default:
132
+ + f.Logger.Err("failed to fetch config from %s: %v", name, err)
133
+ + }
134
+ + return
135
+ + }
136
+ +
137
+ + data = raw
138
+ + cancel()
139
+ + }
140
+ +
141
+ + deviceLabel, userDataPath, err := readFromKernelParams(f.Logger)
142
+ +
143
+ + if err != nil {
144
+ + f.Logger.Err("couldn't read kernel parameters: %v", err)
145
+ + return types.Config{}, report.Report{}, err
146
+ + }
147
+ +
148
+ + if deviceLabel == "" {
149
+ + deviceLabel = defaultDeviceLabel
150
+ + }
151
+ +
152
+ + if userDataPath == "" {
153
+ + userDataPath = defaultUserDataPath
154
+ + }
155
+ +
156
+ + go dispatch(
157
+ + "load config from disk", func() ([]byte, error) {
158
+ + return fetchConfigFromDevice(f.Logger, ctx, deviceLabel, userDataPath)
159
+ + },
160
+ + )
161
+ +
162
+ + <-ctx.Done()
163
+ + if ctx.Err() == context.DeadlineExceeded {
164
+ + f.Logger.Info("disk was not available in time. Continuing without a config...")
165
+ + }
166
+ +
167
+ + return util.ParseConfig(f.Logger, data)
155
168
+ }
156
169
+
157
170
+ func fileExists(path string) bool {
158
- + _, err := os.Stat(path)
159
- + return (err == nil)
171
+ + _, err := os.Stat(path)
172
+ + return (err == nil)
173
+ + }
174
+ +
175
+ + func fetchConfigFromDevice(logger *log.Logger,
176
+ + ctx context.Context,
177
+ + deviceLabel string,
178
+ + dataPath string,
179
+ + ) ([]byte, error) {
180
+ + device := filepath.Join(distro.DiskByLabelDir(), deviceLabel)
181
+ + for !fileExists(device) {
182
+ + logger.Debug("disk (%q) not found. Waiting...", device)
183
+ + select {
184
+ + case <-time.After(time.Second):
185
+ + case <-ctx.Done():
186
+ + return nil, ctx.Err()
187
+ + }
188
+ + }
189
+ +
190
+ + logger.Debug("creating temporary mount point")
191
+ + mnt, err := os.MkdirTemp("", "ignition-config")
192
+ + if err != nil {
193
+ + return nil, fmt.Errorf("failed to create temp directory: %v", err)
194
+ + }
195
+ + defer os.Remove(mnt)
196
+ +
197
+ + cmd := exec.Command(distro.MountCmd(), "-o", "ro", "-t", "auto", device, mnt)
198
+ + if _, err := logger.LogCmd(cmd, "mounting disk"); err != nil {
199
+ + return nil, err
200
+ + }
201
+ + defer func() {
202
+ + _ = logger.LogOp(
203
+ + func() error {
204
+ + return ut.UmountPath(mnt)
205
+ + },
206
+ + "unmounting %q at %q", device, mnt,
207
+ + )
208
+ + }()
209
+ +
210
+ + if !fileExists(filepath.Join(mnt, dataPath)) {
211
+ + return nil, nil
212
+ + }
213
+ +
214
+ + contents, err := os.ReadFile(filepath.Join(mnt, dataPath))
215
+ + if err != nil {
216
+ + return nil, err
217
+ + }
218
+ +
219
+ + if util.IsCloudConfig(contents) {
220
+ + logger.Debug("disk (%q) contains a cloud-config configuration, ignoring", device)
221
+ + return nil, nil
222
+ + }
223
+ +
224
+ + return contents, nil
225
+ + }
226
+ +
227
+ + func readFromKernelParams(logger *log.Logger) (string, string, error) {
228
+ + args, err := os.ReadFile(distro.KernelCmdlinePath())
229
+ + if err != nil {
230
+ + return "", "", err
231
+ + }
232
+ +
233
+ + deviceLabel, userDataPath := parseParams(args)
234
+ + logger.Debug("parsed device label from parameters: %s", deviceLabel)
235
+ + logger.Debug("parsed user-data path from parameters: %s", userDataPath)
236
+ + return deviceLabel, userDataPath, nil
160
237
+ }
161
238
+
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
239
+ + func parseParams(args []byte) (deviceLabel, userDataPath string) {
240
+ + for _, arg := range strings.Split(string(args), " ") {
241
+ + parts := strings.SplitN(strings.TrimSpace(arg), "=", 2)
242
+ + if len(parts) != 2 {
243
+ + continue
244
+ + }
245
+ +
246
+ + key := parts[0]
247
+ + value := parts[1]
248
+ +
249
+ + if key == deviceLabelKernelFlag {
250
+ + deviceLabel = value
251
+ + }
252
+ +
253
+ + if key == userDataKernelFlag {
254
+ + userDataPath = value
255
+ + }
256
+ + }
257
+ +
258
+ + return
207
259
+ }
208
260
diff --git a/internal/providers/proxmoxve/proxmoxve.go b/internal/providers/proxmoxve/proxmoxve.go
209
261
index 490bfe30..b0dbb481 100644
0 commit comments