sigs.k8s.io/cluster-api@v1.7.1/bootstrap/kubeadm/internal/ignition/clc/clc_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package clc_test tests clc package. 18 package clc_test 19 20 import ( 21 "testing" 22 23 ignition "github.com/flatcar/ignition/config/v2_3" 24 "github.com/flatcar/ignition/config/v2_3/types" 25 "github.com/google/go-cmp/cmp" 26 "k8s.io/utils/ptr" 27 28 bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" 29 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit" 30 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/ignition/clc" 31 ) 32 33 const ( 34 configWithWarning = `--- 35 storage: 36 files: 37 - path: /foo 38 contents: 39 inline: foo 40 ` 41 42 // Should generate an Ignition warning about the colon in the partition label. 43 configWithIgnitionWarning = `--- 44 storage: 45 disks: 46 - device: /dev/sda 47 partitions: 48 - label: foo:bar 49 ` 50 ) 51 52 func TestRender(t *testing.T) { 53 t.Parallel() 54 55 preKubeadmCommands := []string{ 56 "pre-command", 57 "another-pre-command", 58 // Test multi-line commands as well. 59 "cat <<EOF > /etc/modules-load.d/containerd.conf\noverlay\nbr_netfilter\nEOF\n", 60 } 61 postKubeadmCommands := []string{ 62 "post-kubeadm-command", 63 "another-post-kubeamd-command", 64 // Test multi-line commands as well. 65 "cat <<EOF > /etc/modules-load.d/containerd.conf\noverlay\nbr_netfilter\nEOF\n", 66 } 67 68 tc := []struct { 69 desc string 70 input *cloudinit.BaseUserData 71 wantIgnition types.Config 72 }{ 73 { 74 desc: "renders valid Ignition JSON", 75 input: &cloudinit.BaseUserData{ 76 PreKubeadmCommands: preKubeadmCommands, 77 PostKubeadmCommands: postKubeadmCommands, 78 KubeadmCommand: "kubeadm join", 79 NTP: &bootstrapv1.NTP{ 80 Enabled: ptr.To(true), 81 Servers: []string{ 82 "foo.bar", 83 "baz", 84 }, 85 }, 86 Users: []bootstrapv1.User{ 87 { 88 Name: "foo", 89 Gecos: ptr.To("Foo B. Bar"), 90 Groups: ptr.To("foo, bar"), 91 HomeDir: ptr.To("/home/foo"), 92 Shell: ptr.To("/bin/false"), 93 Passwd: ptr.To("$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/"), 94 PrimaryGroup: ptr.To("foo"), 95 Sudo: ptr.To("ALL=(ALL) NOPASSWD:ALL"), 96 SSHAuthorizedKeys: []string{ 97 "foo", 98 "bar", 99 }, 100 }, 101 }, 102 DiskSetup: &bootstrapv1.DiskSetup{ 103 Partitions: []bootstrapv1.Partition{ 104 { 105 Device: "/dev/disk/azure/scsi1/lun0", 106 Layout: true, 107 Overwrite: ptr.To(true), 108 TableType: ptr.To("gpt"), 109 }, 110 }, 111 Filesystems: []bootstrapv1.Filesystem{ 112 { 113 Device: "/dev/disk/azure/scsi1/lun0", 114 Filesystem: "ext4", 115 Label: "test_disk", 116 ExtraOpts: []string{"-F", "-E", "lazy_itable_init=1,lazy_journal_init=1"}, 117 Overwrite: ptr.To(true), 118 }, 119 }, 120 }, 121 Mounts: []bootstrapv1.MountPoints{ 122 { 123 "test_disk", "/var/lib/testdir", "foo", 124 }, 125 }, 126 WriteFiles: []bootstrapv1.File{ 127 { 128 Path: "/etc/testfile.yaml", 129 Encoding: bootstrapv1.Base64, 130 Content: "Zm9vCg==", 131 Permissions: "0600", 132 Owner: "nobody:nobody", 133 }, 134 }, 135 }, 136 wantIgnition: types.Config{ 137 Ignition: types.Ignition{ 138 Version: "2.3.0", 139 }, 140 Passwd: types.Passwd{ 141 Users: []types.PasswdUser{ 142 { 143 Gecos: "Foo B. Bar", 144 Groups: []types.Group{ 145 "foo", 146 "bar", 147 }, 148 HomeDir: "/home/foo", 149 Name: "foo", 150 PasswordHash: ptr.To("$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/"), 151 PrimaryGroup: "foo", 152 SSHAuthorizedKeys: []types.SSHAuthorizedKey{ 153 "foo", 154 "bar", 155 }, 156 Shell: "/bin/false", 157 }, 158 }, 159 }, 160 Storage: types.Storage{ 161 Disks: []types.Disk{ 162 { 163 Device: "/dev/disk/azure/scsi1/lun0", 164 Partitions: []types.Partition{{}}, 165 WipeTable: true, 166 }, 167 }, 168 Files: []types.File{ 169 { 170 Node: types.Node{ 171 Filesystem: "root", 172 Path: "/etc/sudoers.d/foo", 173 }, 174 FileEmbedded1: types.FileEmbedded1{ 175 Contents: types.FileContents{ 176 Source: "data:,foo%20ALL%3D(ALL)%20NOPASSWD%3AALL%0A", 177 }, 178 Mode: ptr.To(384), 179 }, 180 }, 181 { 182 Node: types.Node{ 183 Filesystem: "root", 184 Path: "/etc/testfile.yaml", 185 User: &types.NodeUser{Name: "nobody"}, 186 Group: &types.NodeGroup{Name: "nobody"}, 187 }, 188 FileEmbedded1: types.FileEmbedded1{ 189 Contents: types.FileContents{ 190 Source: "data:,foo%0A", 191 }, 192 Mode: ptr.To(384), 193 }, 194 }, 195 { 196 Node: types.Node{ 197 Filesystem: "root", 198 Path: "/etc/kubeadm.sh", 199 }, 200 FileEmbedded1: types.FileEmbedded1{ 201 Contents: types.FileContents{ 202 Source: "data:,%23!%2Fbin%2Fbash%0Aset%20-e%0A%0Apre-command%0Aanother-pre-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A%0A%0Akubeadm%20join%0Amkdir%20-p%20%2Frun%2Fcluster-api%20%26%26%20echo%20success%20%3E%20%2Frun%2Fcluster-api%2Fbootstrap-success.complete%0Amv%20%2Fetc%2Fkubeadm.yml%20%2Ftmp%2F%0A%0Apost-kubeadm-command%0Aanother-post-kubeamd-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A", 203 }, 204 Mode: ptr.To(448), 205 }, 206 }, 207 { 208 Node: types.Node{ 209 Filesystem: "root", 210 Path: "/etc/kubeadm.yml", 211 }, 212 FileEmbedded1: types.FileEmbedded1{ 213 Contents: types.FileContents{ 214 Source: "data:,---%0Afoo%0A", 215 }, 216 Mode: ptr.To(384), 217 }, 218 }, 219 { 220 Node: types.Node{ 221 Filesystem: "root", 222 Path: "/etc/ntp.conf", 223 }, 224 FileEmbedded1: types.FileEmbedded1{ 225 Contents: types.FileContents{ 226 Source: "data:,%23%20Common%20pool%0Aserver%20foo.bar%0Aserver%20baz%0A%0A%23%20Warning%3A%20Using%20default%20NTP%20settings%20will%20leave%20your%20NTP%0A%23%20server%20accessible%20to%20all%20hosts%20on%20the%20Internet.%0A%0A%23%20If%20you%20want%20to%20deny%20all%20machines%20(including%20your%20own)%0A%23%20from%20accessing%20the%20NTP%20server%2C%20uncomment%3A%0A%23restrict%20default%20ignore%0A%0A%23%20Default%20configuration%3A%0A%23%20-%20Allow%20only%20time%20queries%2C%20at%20a%20limited%20rate%2C%20sending%20KoD%20when%20in%20excess.%0A%23%20-%20Allow%20all%20local%20queries%20(IPv4%2C%20IPv6)%0Arestrict%20default%20nomodify%20nopeer%20noquery%20notrap%20limited%20kod%0Arestrict%20127.0.0.1%0Arestrict%20%5B%3A%3A1%5D%0A", 227 }, 228 Mode: ptr.To(420), 229 }, 230 }, 231 }, 232 Filesystems: []types.Filesystem{ 233 { 234 Mount: &types.Mount{ 235 Device: "/dev/disk/azure/scsi1/lun0", 236 Format: "ext4", 237 Label: ptr.To("test_disk"), 238 Options: []types.MountOption{ 239 "-F", 240 "-E", 241 "lazy_itable_init=1,lazy_journal_init=1", 242 }, 243 WipeFilesystem: true, 244 }, 245 Name: "test_disk", 246 }, 247 }, 248 }, 249 Systemd: types.Systemd{ 250 Units: []types.Unit{ 251 { 252 Contents: "[Unit]\nDescription=kubeadm\n# Run only once. After successful run, this file is moved to /tmp/.\nConditionPathExists=/etc/kubeadm.yml\nAfter=network.target\n[Service]\n# To not restart the unit when it exits, as it is expected.\nType=oneshot\nExecStart=/etc/kubeadm.sh\n[Install]\nWantedBy=multi-user.target\n", 253 Enabled: ptr.To(true), 254 Name: "kubeadm.service", 255 }, 256 { 257 Enabled: ptr.To(true), 258 Name: "ntpd.service", 259 }, 260 { 261 Contents: "[Unit]\nDescription = Mount test_disk\n\n[Mount]\nWhat=/dev/disk/azure/scsi1/lun0\nWhere=/var/lib/testdir\nOptions=foo\n\n[Install]\nWantedBy=multi-user.target\n", 262 Enabled: ptr.To(true), 263 Name: "var-lib-testdir.mount", 264 }, 265 }, 266 }, 267 }, 268 }, 269 { 270 desc: "multiple users with password auth", 271 input: &cloudinit.BaseUserData{ 272 PreKubeadmCommands: preKubeadmCommands, 273 PostKubeadmCommands: postKubeadmCommands, 274 KubeadmCommand: "kubeadm join", 275 Users: []bootstrapv1.User{ 276 { 277 Name: "foo", 278 LockPassword: ptr.To(false), 279 }, 280 { 281 Name: "bar", 282 LockPassword: ptr.To(false), 283 }, 284 }, 285 }, 286 wantIgnition: types.Config{ 287 Ignition: types.Ignition{ 288 Version: "2.3.0", 289 }, 290 Passwd: types.Passwd{ 291 Users: []types.PasswdUser{ 292 { 293 Name: "foo", 294 }, 295 { 296 Name: "bar", 297 }, 298 }, 299 }, 300 Storage: types.Storage{ 301 Files: []types.File{ 302 { 303 Node: types.Node{ 304 Filesystem: "root", 305 Path: "/etc/ssh/sshd_config", 306 }, 307 FileEmbedded1: types.FileEmbedded1{ 308 Contents: types.FileContents{ 309 Source: "data:,%23%20Use%20most%20defaults%20for%20sshd%20configuration.%0ASubsystem%20sftp%20internal-sftp%0AClientAliveInterval%20180%0AUseDNS%20no%0AUsePAM%20yes%0APrintLastLog%20no%20%23%20handled%20by%20PAM%0APrintMotd%20no%20%23%20handled%20by%20PAM%0A%0AMatch%20User%20foo%2Cbar%0A%20%20PasswordAuthentication%20yes%0A", 310 }, 311 Mode: ptr.To(384), 312 }, 313 }, 314 { 315 Node: types.Node{ 316 Filesystem: "root", 317 Path: "/etc/kubeadm.sh", 318 }, 319 FileEmbedded1: types.FileEmbedded1{ 320 Contents: types.FileContents{ 321 Source: "data:,%23!%2Fbin%2Fbash%0Aset%20-e%0A%0Apre-command%0Aanother-pre-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A%0A%0Akubeadm%20join%0Amkdir%20-p%20%2Frun%2Fcluster-api%20%26%26%20echo%20success%20%3E%20%2Frun%2Fcluster-api%2Fbootstrap-success.complete%0Amv%20%2Fetc%2Fkubeadm.yml%20%2Ftmp%2F%0A%0Apost-kubeadm-command%0Aanother-post-kubeamd-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A", 322 }, 323 Mode: ptr.To(448), 324 }, 325 }, 326 { 327 Node: types.Node{ 328 Filesystem: "root", 329 Path: "/etc/kubeadm.yml", 330 }, 331 FileEmbedded1: types.FileEmbedded1{ 332 Contents: types.FileContents{ 333 Source: "data:,---%0Afoo%0A", 334 }, 335 Mode: ptr.To(384), 336 }, 337 }, 338 }, 339 }, 340 Systemd: types.Systemd{ 341 Units: []types.Unit{ 342 { 343 Contents: "[Unit]\nDescription=kubeadm\n# Run only once. After successful run, this file is moved to /tmp/.\nConditionPathExists=/etc/kubeadm.yml\nAfter=network.target\n[Service]\n# To not restart the unit when it exits, as it is expected.\nType=oneshot\nExecStart=/etc/kubeadm.sh\n[Install]\nWantedBy=multi-user.target\n", 344 Enabled: ptr.To(true), 345 Name: "kubeadm.service", 346 }, 347 }, 348 }, 349 }, 350 }, 351 { 352 desc: "base64 encoded content", 353 input: &cloudinit.BaseUserData{ 354 PreKubeadmCommands: preKubeadmCommands, 355 PostKubeadmCommands: postKubeadmCommands, 356 KubeadmCommand: "kubeadm join", 357 WriteFiles: []bootstrapv1.File{ 358 { 359 Path: "/etc/base64encodedcontent.yaml", 360 Encoding: bootstrapv1.Base64, 361 Content: "Zm9vCg==", 362 Permissions: "0600", 363 }, 364 { 365 Path: "/etc/plaincontent.yaml", 366 Content: "foo", 367 Permissions: "0600", 368 }, 369 }, 370 }, 371 wantIgnition: types.Config{ 372 Ignition: types.Ignition{ 373 Version: "2.3.0", 374 }, 375 Storage: types.Storage{ 376 Files: []types.File{ 377 { 378 Node: types.Node{ 379 Filesystem: "root", 380 Path: "/etc/base64encodedcontent.yaml", 381 }, 382 FileEmbedded1: types.FileEmbedded1{ 383 Contents: types.FileContents{Source: "data:,foo%0A"}, 384 Mode: ptr.To(384), 385 }, 386 }, 387 { 388 Node: types.Node{ 389 Filesystem: "root", 390 Path: "/etc/plaincontent.yaml", 391 }, 392 FileEmbedded1: types.FileEmbedded1{ 393 Contents: types.FileContents{Source: "data:,foo%0A"}, 394 Mode: ptr.To(384), 395 }, 396 }, 397 { 398 Node: types.Node{ 399 Filesystem: "root", 400 Path: "/etc/kubeadm.sh", 401 }, 402 FileEmbedded1: types.FileEmbedded1{ 403 Contents: types.FileContents{ 404 Source: "data:,%23!%2Fbin%2Fbash%0Aset%20-e%0A%0Apre-command%0Aanother-pre-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A%0A%0Akubeadm%20join%0Amkdir%20-p%20%2Frun%2Fcluster-api%20%26%26%20echo%20success%20%3E%20%2Frun%2Fcluster-api%2Fbootstrap-success.complete%0Amv%20%2Fetc%2Fkubeadm.yml%20%2Ftmp%2F%0A%0Apost-kubeadm-command%0Aanother-post-kubeamd-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A", 405 }, 406 Mode: ptr.To(448), 407 }, 408 }, 409 { 410 Node: types.Node{ 411 Filesystem: "root", 412 Path: "/etc/kubeadm.yml", 413 }, 414 FileEmbedded1: types.FileEmbedded1{ 415 Contents: types.FileContents{ 416 Source: "data:,---%0Afoo%0A", 417 }, 418 Mode: ptr.To(384), 419 }, 420 }, 421 }, 422 }, 423 Systemd: types.Systemd{ 424 Units: []types.Unit{ 425 { 426 Contents: "[Unit]\nDescription=kubeadm\n# Run only once. After successful run, this file is moved to /tmp/.\nConditionPathExists=/etc/kubeadm.yml\nAfter=network.target\n[Service]\n# To not restart the unit when it exits, as it is expected.\nType=oneshot\nExecStart=/etc/kubeadm.sh\n[Install]\nWantedBy=multi-user.target\n", 427 Enabled: ptr.To(true), 428 Name: "kubeadm.service", 429 }, 430 }, 431 }, 432 }, 433 }, 434 { 435 desc: "all file ownership combinations", 436 input: &cloudinit.BaseUserData{ 437 PreKubeadmCommands: preKubeadmCommands, 438 PostKubeadmCommands: postKubeadmCommands, 439 KubeadmCommand: "kubeadm join", 440 WriteFiles: []bootstrapv1.File{ 441 { 442 Path: "/etc/username-group-name-owner.yaml", 443 Owner: "nobody:nobody", 444 Permissions: "0600", 445 }, 446 { 447 Path: "/etc/user-only-owner.yaml", 448 Owner: "nobody", 449 Permissions: "0600", 450 }, 451 { 452 Path: "/etc/user-only-with-colon-owner.yaml", 453 Owner: "nobody:", 454 Permissions: "0600", 455 }, 456 { 457 Path: "/etc/group-only-owner.yaml", 458 Owner: ":nobody", 459 Permissions: "0600", 460 }, 461 }, 462 }, 463 wantIgnition: types.Config{ 464 Ignition: types.Ignition{ 465 Version: "2.3.0", 466 }, 467 Storage: types.Storage{ 468 Files: []types.File{ 469 { 470 Node: types.Node{ 471 Filesystem: "root", 472 Path: "/etc/username-group-name-owner.yaml", 473 User: &types.NodeUser{ 474 Name: "nobody", 475 }, 476 Group: &types.NodeGroup{ 477 Name: "nobody", 478 }, 479 }, 480 FileEmbedded1: types.FileEmbedded1{ 481 Contents: types.FileContents{Source: "data:,"}, 482 Mode: ptr.To(384), 483 }, 484 }, 485 { 486 Node: types.Node{ 487 Filesystem: "root", 488 Path: "/etc/user-only-owner.yaml", 489 User: &types.NodeUser{ 490 Name: "nobody", 491 }, 492 }, 493 FileEmbedded1: types.FileEmbedded1{ 494 Contents: types.FileContents{Source: "data:,"}, 495 Mode: ptr.To(384), 496 }, 497 }, 498 { 499 Node: types.Node{ 500 Filesystem: "root", 501 Path: "/etc/user-only-with-colon-owner.yaml", 502 User: &types.NodeUser{ 503 Name: "nobody", 504 }, 505 }, 506 FileEmbedded1: types.FileEmbedded1{ 507 Contents: types.FileContents{Source: "data:,"}, 508 Mode: ptr.To(384), 509 }, 510 }, 511 { 512 Node: types.Node{ 513 Filesystem: "root", 514 Path: "/etc/group-only-owner.yaml", 515 Group: &types.NodeGroup{ 516 Name: "nobody", 517 }, 518 }, 519 FileEmbedded1: types.FileEmbedded1{ 520 Contents: types.FileContents{Source: "data:,"}, 521 Mode: ptr.To(384), 522 }, 523 }, 524 { 525 Node: types.Node{ 526 Filesystem: "root", 527 Path: "/etc/kubeadm.sh", 528 }, 529 FileEmbedded1: types.FileEmbedded1{ 530 Contents: types.FileContents{ 531 Source: "data:,%23!%2Fbin%2Fbash%0Aset%20-e%0A%0Apre-command%0Aanother-pre-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A%0A%0Akubeadm%20join%0Amkdir%20-p%20%2Frun%2Fcluster-api%20%26%26%20echo%20success%20%3E%20%2Frun%2Fcluster-api%2Fbootstrap-success.complete%0Amv%20%2Fetc%2Fkubeadm.yml%20%2Ftmp%2F%0A%0Apost-kubeadm-command%0Aanother-post-kubeamd-command%0Acat%20%3C%3CEOF%20%3E%20%2Fetc%2Fmodules-load.d%2Fcontainerd.conf%0Aoverlay%0Abr_netfilter%0AEOF%0A", 532 }, 533 Mode: ptr.To(448), 534 }, 535 }, 536 { 537 Node: types.Node{ 538 Filesystem: "root", 539 Path: "/etc/kubeadm.yml", 540 }, 541 FileEmbedded1: types.FileEmbedded1{ 542 Contents: types.FileContents{ 543 Source: "data:,---%0Afoo%0A", 544 }, 545 Mode: ptr.To(384), 546 }, 547 }, 548 }, 549 }, 550 Systemd: types.Systemd{ 551 Units: []types.Unit{ 552 { 553 Contents: "[Unit]\nDescription=kubeadm\n# Run only once. After successful run, this file is moved to /tmp/.\nConditionPathExists=/etc/kubeadm.yml\nAfter=network.target\n[Service]\n# To not restart the unit when it exits, as it is expected.\nType=oneshot\nExecStart=/etc/kubeadm.sh\n[Install]\nWantedBy=multi-user.target\n", 554 Enabled: ptr.To(true), 555 Name: "kubeadm.service", 556 }, 557 }, 558 }, 559 }, 560 }, 561 } 562 563 for _, tt := range tc { 564 tt := tt 565 566 t.Run(tt.desc, func(t *testing.T) { 567 t.Parallel() 568 569 ignitionBytes, _, err := clc.Render(tt.input, &bootstrapv1.ContainerLinuxConfig{}, "foo") 570 if err != nil { 571 t.Fatalf("rendering: %v", err) 572 } 573 574 ign, reports, err := ignition.Parse(ignitionBytes) 575 if err != nil { 576 t.Fatalf("Parsing generated Ignition: %v", err) 577 } 578 579 if reports.IsFatal() { 580 t.Fatalf("Generated Ignition has fatal reports: %s", reports) 581 } 582 583 if diff := cmp.Diff(tt.wantIgnition, ign); diff != "" { 584 t.Fatalf("Ignition mismatch (-want +got):\n%s", diff) 585 } 586 }) 587 } 588 589 t.Run("validates input parameter", func(t *testing.T) { 590 t.Parallel() 591 592 if _, _, err := clc.Render(nil, &bootstrapv1.ContainerLinuxConfig{}, "foo"); err == nil { 593 t.Fatal("expected error when passing empty input data") 594 } 595 }) 596 597 t.Run("accepts empty clc parameter", func(t *testing.T) { 598 t.Parallel() 599 600 if _, _, err := clc.Render(&cloudinit.BaseUserData{}, nil, "bar"); err != nil { 601 t.Fatalf("unexpected error while rendering: %v", err) 602 } 603 }) 604 605 t.Run("treats warnings as errors in strict mode", func(t *testing.T) { 606 config := &bootstrapv1.ContainerLinuxConfig{ 607 Strict: true, 608 AdditionalConfig: configWithWarning, 609 } 610 611 if _, _, err := clc.Render(&cloudinit.BaseUserData{}, config, "foo"); err == nil { 612 t.Fatalf("expected error") 613 } 614 }) 615 616 t.Run("returns warnings", func(t *testing.T) { 617 config := &bootstrapv1.ContainerLinuxConfig{ 618 AdditionalConfig: configWithWarning, 619 } 620 621 data, warnings, err := clc.Render(&cloudinit.BaseUserData{}, config, "foo") 622 if err != nil { 623 t.Fatalf("unexpected error: %v", err) 624 } 625 626 if warnings == "" { 627 t.Errorf("expected warnings to be not empty") 628 } 629 630 if len(data) == 0 { 631 t.Errorf("expected data to be returned on config with warnings") 632 } 633 }) 634 635 t.Run("returns Ignition warnings", func(t *testing.T) { 636 config := &bootstrapv1.ContainerLinuxConfig{ 637 AdditionalConfig: configWithIgnitionWarning, 638 } 639 640 data, warnings, err := clc.Render(&cloudinit.BaseUserData{}, config, "foo") 641 if err != nil { 642 t.Fatalf("unexpected error: %v", err) 643 } 644 645 if warnings == "" { 646 t.Errorf("expected warnings to be not empty") 647 } 648 649 if len(data) == 0 { 650 t.Errorf("expected data to be returned on config with warnings") 651 } 652 }) 653 }