Merge pull request #190 from Danil-Grigorev/arbitrary-cloud-init
Add arbitrary data field
This commit is contained in:
commit
8af997563f
|
|
@ -164,13 +164,21 @@ type RKE2AgentConfig struct {
|
||||||
AdditionalUserData AdditionalUserData `json:"additionalUserData,omitempty"`
|
AdditionalUserData AdditionalUserData `json:"additionalUserData,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdditionalUserData is a field that allows users to specify additional cloud-init configuration .
|
// AdditionalUserData is a field that allows users to specify additional
|
||||||
|
// cloud-init configuration .
|
||||||
|
// +kubebuilder:validation:XValidation:rule="!has(self.data) || !has(self.config)", message="Only config or data could be populated at once"
|
||||||
type AdditionalUserData struct {
|
type AdditionalUserData struct {
|
||||||
// In case of using ignition, the data format is documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
// In case of using ignition, the data format is documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
||||||
// NOTE: All fields of the UserData that are managed by the RKE2Config controller will be ignored, this include "write_files", "runcmd", "ntp".
|
// NOTE: All fields of the UserData that are managed by the RKE2Config controller will be ignored, this include "write_files", "runcmd", "ntp".
|
||||||
// +optional
|
// +optional
|
||||||
|
// Deprecated: Data is reserved for the arbitrary cloud-init data
|
||||||
Config string `json:"config,omitempty"`
|
Config string `json:"config,omitempty"`
|
||||||
|
|
||||||
|
// Data allows to pass arbitrary set of key/value pairs consistent with
|
||||||
|
// https://cloudinit.readthedocs.io/en/latest/reference/modules.html
|
||||||
|
// to extend existing cloud-init configuration
|
||||||
|
Data map[string]string `json:"data,omitempty"`
|
||||||
|
|
||||||
// Strict controls if Config should be strictly parsed. If so, warnings are treated as errors.
|
// Strict controls if Config should be strictly parsed. If so, warnings are treated as errors.
|
||||||
// +optional
|
// +optional
|
||||||
Strict bool `json:"strict,omitempty"`
|
Strict bool `json:"strict,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,13 @@ import (
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *AdditionalUserData) DeepCopyInto(out *AdditionalUserData) {
|
func (in *AdditionalUserData) DeepCopyInto(out *AdditionalUserData) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Data != nil {
|
||||||
|
in, out := &in.Data, &out.Data
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalUserData.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalUserData.
|
||||||
|
|
@ -209,7 +216,7 @@ func (in *RKE2AgentConfig) DeepCopyInto(out *RKE2AgentConfig) {
|
||||||
*out = new(ComponentConfig)
|
*out = new(ComponentConfig)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
out.AdditionalUserData = in.AdditionalUserData
|
in.AdditionalUserData.DeepCopyInto(&out.AdditionalUserData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RKE2AgentConfig.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RKE2AgentConfig.
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,24 @@ spec:
|
||||||
documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
||||||
NOTE: All fields of the UserData that are managed by the
|
NOTE: All fields of the UserData that are managed by the
|
||||||
RKE2Config controller will be ignored, this include "write_files",
|
RKE2Config controller will be ignored, this include "write_files",
|
||||||
"runcmd", "ntp".'
|
"runcmd", "ntp". Deprecated: Data is reserved for the arbitrary
|
||||||
|
cloud-init data'
|
||||||
type: string
|
type: string
|
||||||
|
data:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Data allows to pass arbitrary set of key/value
|
||||||
|
pairs consistent with https://cloudinit.readthedocs.io/en/latest/reference/modules.html
|
||||||
|
to extend existing cloud-init configuration
|
||||||
|
type: object
|
||||||
strict:
|
strict:
|
||||||
description: Strict controls if Config should be strictly
|
description: Strict controls if Config should be strictly
|
||||||
parsed. If so, warnings are treated as errors.
|
parsed. If so, warnings are treated as errors.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Only config or data could be populated at once
|
||||||
|
rule: '!has(self.data) || !has(self.config)'
|
||||||
airGapped:
|
airGapped:
|
||||||
description: AirGapped is a boolean value to define if the bootstrapping
|
description: AirGapped is a boolean value to define if the bootstrapping
|
||||||
should be air-gapped, basically supposing that online container
|
should be air-gapped, basically supposing that online container
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,24 @@ spec:
|
||||||
format is documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
format is documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
||||||
NOTE: All fields of the UserData that are managed
|
NOTE: All fields of the UserData that are managed
|
||||||
by the RKE2Config controller will be ignored, this
|
by the RKE2Config controller will be ignored, this
|
||||||
include "write_files", "runcmd", "ntp".'
|
include "write_files", "runcmd", "ntp". Deprecated:
|
||||||
|
Data is reserved for the arbitrary cloud-init data'
|
||||||
type: string
|
type: string
|
||||||
|
data:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Data allows to pass arbitrary set of
|
||||||
|
key/value pairs consistent with https://cloudinit.readthedocs.io/en/latest/reference/modules.html
|
||||||
|
to extend existing cloud-init configuration
|
||||||
|
type: object
|
||||||
strict:
|
strict:
|
||||||
description: Strict controls if Config should be strictly
|
description: Strict controls if Config should be strictly
|
||||||
parsed. If so, warnings are treated as errors.
|
parsed. If so, warnings are treated as errors.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Only config or data could be populated at once
|
||||||
|
rule: '!has(self.data) || !has(self.config)'
|
||||||
airGapped:
|
airGapped:
|
||||||
description: AirGapped is a boolean value to define if
|
description: AirGapped is a boolean value to define if
|
||||||
the bootstrapping should be air-gapped, basically supposing
|
the bootstrapping should be air-gapped, basically supposing
|
||||||
|
|
|
||||||
|
|
@ -86,23 +86,29 @@ ntp:
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
`
|
||||||
|
arbitraryTemplate = `{{- define "arbitrary" -}}{{- range $key, $value := . }}
|
||||||
|
{{ $key -}}: {{ $value -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseUserData is shared across all the various types of files written to disk.
|
// BaseUserData is shared across all the various types of files written to disk.
|
||||||
type BaseUserData struct {
|
type BaseUserData struct {
|
||||||
Header string
|
Header string
|
||||||
PreRKE2Commands []string
|
PreRKE2Commands []string
|
||||||
DeployRKE2Commands []string
|
DeployRKE2Commands []string
|
||||||
PostRKE2Commands []string
|
PostRKE2Commands []string
|
||||||
WriteFiles []bootstrapv1.File
|
WriteFiles []bootstrapv1.File
|
||||||
ConfigFile bootstrapv1.File
|
ConfigFile bootstrapv1.File
|
||||||
RKE2Version string
|
RKE2Version string
|
||||||
SentinelFileCommand string
|
SentinelFileCommand string
|
||||||
AirGapped bool
|
AirGapped bool
|
||||||
NTPServers []string
|
NTPServers []string
|
||||||
CISEnabled bool
|
CISEnabled bool
|
||||||
AdditionalCloudInit string
|
AdditionalCloudInit string
|
||||||
|
AdditionalArbitraryData map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func generate(kind string, tpl string, data interface{}) ([]byte, error) {
|
func generate(kind string, tpl string, data interface{}) ([]byte, error) {
|
||||||
|
|
@ -119,6 +125,10 @@ func generate(kind string, tpl string, data interface{}) ([]byte, error) {
|
||||||
return nil, errors.Wrap(err, "failed to parse ntp template")
|
return nil, errors.Wrap(err, "failed to parse ntp template")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, err := tm.Parse(arbitraryTemplate); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to parse arbitrary template")
|
||||||
|
}
|
||||||
|
|
||||||
t, err := tm.Parse(tpl)
|
t, err := tm.Parse(tpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to parse %s template", kind)
|
return nil, errors.Wrapf(err, "failed to parse %s template", kind)
|
||||||
|
|
@ -159,3 +169,41 @@ func cleanupAdditionalCloudInit(cloudInitData string) (string, error) {
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanupArbitraryData(arbitraryData map[string]string) error {
|
||||||
|
// Remove ignored fields from the map
|
||||||
|
for _, field := range ignoredCloudInitFields {
|
||||||
|
delete(arbitraryData, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arbitraryData) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
|
||||||
|
kind := "arbitrary_prepare"
|
||||||
|
tm := template.New(kind).Funcs(defaultTemplateFuncMap)
|
||||||
|
|
||||||
|
if _, err := tm.Parse(arbitraryTemplate); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to parse arbitrary keys template")
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := tm.Parse(`{{template "arbitrary" .AdditionalArbitraryData}}`)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to parse arbitrary template")
|
||||||
|
}
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
if err := t.Execute(&out, BaseUserData{
|
||||||
|
AdditionalArbitraryData: arbitraryData,
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to generate %s template", kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(out.Bytes(), m); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal arbitrary cloud-init data: %w, please check if you put valid yaml data: %s", err, out.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ write_files:
|
||||||
content: |
|
content: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts INSTALL_RKE2_TYPE="agent" sh /opt/install.sh'
|
- 'INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts INSTALL_RKE2_TYPE="agent" sh /opt/install.sh'
|
||||||
- 'systemctl enable rke2-agent.service'
|
- 'systemctl enable rke2-agent.service'
|
||||||
|
|
@ -76,6 +77,7 @@ write_files:
|
||||||
content: |
|
content: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
||||||
- 'systemctl enable rke2-agent.service'
|
- 'systemctl enable rke2-agent.service'
|
||||||
|
|
@ -111,6 +113,7 @@ ntp:
|
||||||
enabled: true
|
enabled: true
|
||||||
servers:
|
servers:
|
||||||
- "test.ntp.org"
|
- "test.ntp.org"
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION= INSTALL_RKE2_TYPE="agent" sh -s -'
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION= INSTALL_RKE2_TYPE="agent" sh -s -'
|
||||||
- 'systemctl enable rke2-agent.service'
|
- 'systemctl enable rke2-agent.service'
|
||||||
|
|
@ -145,6 +148,7 @@ write_files:
|
||||||
content: |
|
content: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
||||||
- '/opt/rke2-cis-script.sh'
|
- '/opt/rke2-cis-script.sh'
|
||||||
|
|
@ -166,6 +170,7 @@ write_files:
|
||||||
- path:
|
- path:
|
||||||
content: |
|
content: |
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION= INSTALL_RKE2_TYPE=\"agent\" sh -s -'
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION= INSTALL_RKE2_TYPE=\"agent\" sh -s -'
|
||||||
- 'systemctl enable rke2-agent.service'
|
- 'systemctl enable rke2-agent.service'
|
||||||
|
|
@ -186,8 +191,11 @@ users:
|
||||||
|
|
||||||
var _ = Describe("CloudInit with custom entries", func() {
|
var _ = Describe("CloudInit with custom entries", func() {
|
||||||
var input *BaseUserData
|
var input *BaseUserData
|
||||||
|
var cloudInitData string
|
||||||
|
var arbitraryData map[string]string
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
cloudInitData := `## template: jinja
|
cloudInitData = `## template: jinja
|
||||||
#cloud-config
|
#cloud-config
|
||||||
device_aliases: {'ephemeral0': '/dev/vdb'}
|
device_aliases: {'ephemeral0': '/dev/vdb'}
|
||||||
disk_setup:
|
disk_setup:
|
||||||
|
|
@ -206,18 +214,29 @@ write_files:
|
||||||
content: |
|
content: |
|
||||||
192.168.0.1 test
|
192.168.0.1 test
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'print hello world'
|
- 'print hello world'
|
||||||
`
|
`
|
||||||
input = &BaseUserData{
|
arbitraryData = map[string]string{
|
||||||
AirGapped: false,
|
"disk_setup": `
|
||||||
CISEnabled: true,
|
ephemeral0:
|
||||||
RKE2Version: "v1.25.6+rke2r1",
|
table_type: mbr
|
||||||
AdditionalCloudInit: cloudInitData,
|
layout: False
|
||||||
|
overwrite: False`,
|
||||||
|
"device_aliases": "{'ephemeral0': '/dev/vdb'}",
|
||||||
|
"runcmd": `
|
||||||
|
- 'print hello world'`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Should remove the runcmd, write_files and ntp lines", func() {
|
It("Should apply the arbitrary data and cleanup the input values", func() {
|
||||||
|
input = &BaseUserData{
|
||||||
|
AirGapped: false,
|
||||||
|
CISEnabled: true,
|
||||||
|
RKE2Version: "v1.25.6+rke2r1",
|
||||||
|
AdditionalArbitraryData: arbitraryData,
|
||||||
|
}
|
||||||
workerCloudInitData, err := NewJoinWorker(input)
|
workerCloudInitData, err := NewJoinWorker(input)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
workerCloudInitString := string(workerCloudInitData)
|
workerCloudInitString := string(workerCloudInitData)
|
||||||
|
|
@ -232,6 +251,45 @@ write_files:
|
||||||
content: |
|
content: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
device_aliases: {'ephemeral0': '/dev/vdb'}
|
||||||
|
disk_setup:
|
||||||
|
ephemeral0:
|
||||||
|
table_type: mbr
|
||||||
|
layout: False
|
||||||
|
overwrite: False
|
||||||
|
runcmd:
|
||||||
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
||||||
|
- '/opt/rke2-cis-script.sh'
|
||||||
|
- 'systemctl enable rke2-agent.service'
|
||||||
|
- 'systemctl start rke2-agent.service'
|
||||||
|
- 'mkdir /run/cluster-api'
|
||||||
|
- 'echo success > /run/cluster-api/bootstrap-success.complete'
|
||||||
|
`))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Should remove the runcmd, write_files and ntp lines", func() {
|
||||||
|
input = &BaseUserData{
|
||||||
|
AirGapped: false,
|
||||||
|
CISEnabled: true,
|
||||||
|
RKE2Version: "v1.25.6+rke2r1",
|
||||||
|
AdditionalCloudInit: cloudInitData,
|
||||||
|
}
|
||||||
|
workerCloudInitData, err := NewJoinWorker(input)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
workerCloudInitString := string(workerCloudInitData)
|
||||||
|
_, err = GinkgoWriter.Write(workerCloudInitData)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(workerCloudInitString).To(Equal(`## template: jinja
|
||||||
|
#cloud-config
|
||||||
|
|
||||||
|
write_files:
|
||||||
|
- path:
|
||||||
|
content: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
runcmd:
|
runcmd:
|
||||||
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
- 'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.25.6+rke2r1 INSTALL_RKE2_TYPE="agent" sh -s -'
|
||||||
- '/opt/rke2-cis-script.sh'
|
- '/opt/rke2-cis-script.sh'
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ const (
|
||||||
controlPlaneCloudInit = `{{.Header}}
|
controlPlaneCloudInit = `{{.Header}}
|
||||||
{{template "files" .WriteFiles}}
|
{{template "files" .WriteFiles}}
|
||||||
{{template "ntp" .NTPServers}}
|
{{template "ntp" .NTPServers}}
|
||||||
|
{{template "arbitrary" .AdditionalArbitraryData}}
|
||||||
runcmd:
|
runcmd:
|
||||||
{{- template "commands" .PreRKE2Commands }}
|
{{- template "commands" .PreRKE2Commands }}
|
||||||
- {{ if .AirGapped }}INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts sh /opt/install.sh{{ else }}'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=%[1]s sh -s - server'{{ end }}
|
- {{ if .AirGapped }}INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts sh /opt/install.sh{{ else }}'curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=%[1]s sh -s - server'{{ end }}
|
||||||
|
|
@ -63,6 +64,10 @@ func NewInitControlPlane(input *ControlPlaneInput) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cleanupArbitraryData(input.AdditionalArbitraryData); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
controlPlaneCloudJoinWithVersion := fmt.Sprintf(controlPlaneCloudInit, input.RKE2Version)
|
controlPlaneCloudJoinWithVersion := fmt.Sprintf(controlPlaneCloudInit, input.RKE2Version)
|
||||||
userData, err := generate("InitControlplane", controlPlaneCloudJoinWithVersion, input)
|
userData, err := generate("InitControlplane", controlPlaneCloudJoinWithVersion, input)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@ func NewJoinControlPlane(input *ControlPlaneInput) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cleanupArbitraryData(input.AdditionalArbitraryData); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
controlPlaneCloudJoinWithVersion := fmt.Sprintf(controlPlaneCloudInit, input.RKE2Version)
|
controlPlaneCloudJoinWithVersion := fmt.Sprintf(controlPlaneCloudInit, input.RKE2Version)
|
||||||
userData, err := generate("JoinControlplane", controlPlaneCloudJoinWithVersion, input)
|
userData, err := generate("JoinControlplane", controlPlaneCloudJoinWithVersion, input)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ const (
|
||||||
workerCloudInit = `{{.Header}}
|
workerCloudInit = `{{.Header}}
|
||||||
{{template "files" .WriteFiles}}
|
{{template "files" .WriteFiles}}
|
||||||
{{template "ntp" .NTPServers}}
|
{{template "ntp" .NTPServers}}
|
||||||
|
{{template "arbitrary" .AdditionalArbitraryData}}
|
||||||
runcmd:
|
runcmd:
|
||||||
{{- template "commands" .PreRKE2Commands }}
|
{{- template "commands" .PreRKE2Commands }}
|
||||||
- '{{ if .AirGapped }}INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts INSTALL_RKE2_TYPE="agent" sh /opt/install.sh{{ else }}curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=%[1]s INSTALL_RKE2_TYPE="agent" sh -s -{{end}}'
|
- '{{ if .AirGapped }}INSTALL_RKE2_ARTIFACT_PATH=/opt/rke2-artifacts INSTALL_RKE2_TYPE="agent" sh /opt/install.sh{{ else }}curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=%[1]s INSTALL_RKE2_TYPE="agent" sh -s -{{end}}'
|
||||||
|
|
@ -54,6 +55,10 @@ func NewJoinWorker(input *BaseUserData) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cleanupArbitraryData(input.AdditionalArbitraryData); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
workerCloudJoinWithVersion := fmt.Sprintf(workerCloudInit, input.RKE2Version)
|
workerCloudJoinWithVersion := fmt.Sprintf(workerCloudInit, input.RKE2Version)
|
||||||
userData, err := generate("JoinWorker", workerCloudJoinWithVersion, input)
|
userData, err := generate("JoinWorker", workerCloudJoinWithVersion, input)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -402,15 +402,16 @@ func (r *RKE2ConfigReconciler) handleClusterNotInitialized(ctx context.Context,
|
||||||
|
|
||||||
cpinput := &cloudinit.ControlPlaneInput{
|
cpinput := &cloudinit.ControlPlaneInput{
|
||||||
BaseUserData: cloudinit.BaseUserData{
|
BaseUserData: cloudinit.BaseUserData{
|
||||||
AirGapped: scope.Config.Spec.AgentConfig.AirGapped,
|
AirGapped: scope.Config.Spec.AgentConfig.AirGapped,
|
||||||
CISEnabled: scope.Config.Spec.AgentConfig.CISProfile != "",
|
CISEnabled: scope.Config.Spec.AgentConfig.CISProfile != "",
|
||||||
PreRKE2Commands: scope.Config.Spec.PreRKE2Commands,
|
PreRKE2Commands: scope.Config.Spec.PreRKE2Commands,
|
||||||
PostRKE2Commands: scope.Config.Spec.PostRKE2Commands,
|
PostRKE2Commands: scope.Config.Spec.PostRKE2Commands,
|
||||||
ConfigFile: initConfigFile,
|
ConfigFile: initConfigFile,
|
||||||
RKE2Version: scope.Config.Spec.AgentConfig.Version,
|
RKE2Version: scope.Config.Spec.AgentConfig.Version,
|
||||||
WriteFiles: files,
|
WriteFiles: files,
|
||||||
NTPServers: ntpServers,
|
NTPServers: ntpServers,
|
||||||
AdditionalCloudInit: scope.Config.Spec.AgentConfig.AdditionalUserData.Config,
|
AdditionalCloudInit: scope.Config.Spec.AgentConfig.AdditionalUserData.Config,
|
||||||
|
AdditionalArbitraryData: scope.Config.Spec.AgentConfig.AdditionalUserData.Data,
|
||||||
},
|
},
|
||||||
Certificates: certificates,
|
Certificates: certificates,
|
||||||
}
|
}
|
||||||
|
|
@ -694,15 +695,16 @@ func (r *RKE2ConfigReconciler) joinWorker(ctx context.Context, scope *Scope) (re
|
||||||
}
|
}
|
||||||
|
|
||||||
wkInput := &cloudinit.BaseUserData{
|
wkInput := &cloudinit.BaseUserData{
|
||||||
PreRKE2Commands: scope.Config.Spec.PreRKE2Commands,
|
PreRKE2Commands: scope.Config.Spec.PreRKE2Commands,
|
||||||
AirGapped: scope.Config.Spec.AgentConfig.AirGapped,
|
AirGapped: scope.Config.Spec.AgentConfig.AirGapped,
|
||||||
CISEnabled: scope.Config.Spec.AgentConfig.CISProfile != "",
|
CISEnabled: scope.Config.Spec.AgentConfig.CISProfile != "",
|
||||||
PostRKE2Commands: scope.Config.Spec.PostRKE2Commands,
|
PostRKE2Commands: scope.Config.Spec.PostRKE2Commands,
|
||||||
ConfigFile: wkJoinConfigFile,
|
ConfigFile: wkJoinConfigFile,
|
||||||
RKE2Version: scope.Config.Spec.AgentConfig.Version,
|
RKE2Version: scope.Config.Spec.AgentConfig.Version,
|
||||||
WriteFiles: files,
|
WriteFiles: files,
|
||||||
NTPServers: ntpServers,
|
NTPServers: ntpServers,
|
||||||
AdditionalCloudInit: scope.Config.Spec.AgentConfig.AdditionalUserData.Config,
|
AdditionalCloudInit: scope.Config.Spec.AgentConfig.AdditionalUserData.Config,
|
||||||
|
AdditionalArbitraryData: scope.Config.Spec.AgentConfig.AdditionalUserData.Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
var userData []byte
|
var userData []byte
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,24 @@ spec:
|
||||||
documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
documented here: https://kinvolk.io/docs/flatcar-container-linux/latest/provisioning/cl-config/
|
||||||
NOTE: All fields of the UserData that are managed by the
|
NOTE: All fields of the UserData that are managed by the
|
||||||
RKE2Config controller will be ignored, this include "write_files",
|
RKE2Config controller will be ignored, this include "write_files",
|
||||||
"runcmd", "ntp".'
|
"runcmd", "ntp". Deprecated: Data is reserved for the arbitrary
|
||||||
|
cloud-init data'
|
||||||
type: string
|
type: string
|
||||||
|
data:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Data allows to pass arbitrary set of key/value
|
||||||
|
pairs consistent with https://cloudinit.readthedocs.io/en/latest/reference/modules.html
|
||||||
|
to extend existing cloud-init configuration
|
||||||
|
type: object
|
||||||
strict:
|
strict:
|
||||||
description: Strict controls if Config should be strictly
|
description: Strict controls if Config should be strictly
|
||||||
parsed. If so, warnings are treated as errors.
|
parsed. If so, warnings are treated as errors.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Only config or data could be populated at once
|
||||||
|
rule: '!has(self.data) || !has(self.config)'
|
||||||
airGapped:
|
airGapped:
|
||||||
description: AirGapped is a boolean value to define if the bootstrapping
|
description: AirGapped is a boolean value to define if the bootstrapping
|
||||||
should be air-gapped, basically supposing that online container
|
should be air-gapped, basically supposing that online container
|
||||||
|
|
|
||||||
|
|
@ -158,3 +158,35 @@ var _ = Describe("Node metadata propagation", func() {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var _ = Describe("Cloud-init fields validation", func() {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
ns *corev1.Namespace
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
ns, err = testEnv.CreateNamespace(ctx, "ns")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
testEnv.Cleanup(ctx, ns)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should prevent populating config and data fields", func() {
|
||||||
|
Expect(testEnv.Create(ctx, &bootstrapv1.RKE2Config{ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "config",
|
||||||
|
Namespace: ns.Name,
|
||||||
|
}, Spec: bootstrapv1.RKE2ConfigSpec{
|
||||||
|
AgentConfig: bootstrapv1.RKE2AgentConfig{
|
||||||
|
AdditionalUserData: bootstrapv1.AdditionalUserData{
|
||||||
|
Config: "some",
|
||||||
|
Data: map[string]string{
|
||||||
|
"no": "way",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}})).ToNot(Succeed())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue