-
Notifications
You must be signed in to change notification settings - Fork 5
test: precreate cvi for e2e tests #2103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
829a1cd
dd6e6a6
0a59872
6b4371c
3905c13
af5aaf7
a69696c
bf93fa3
9863ef0
89b4c33
4543616
1de4180
ddfbca0
b59c389
6a3a437
c8e70b6
caa77f5
789460e
406c207
391e7be
35220af
bea156b
e7e66d2
e5e0c1a
8e270a8
46e2cdd
c07d389
9d781c0
3555920
f9065c3
2f8064f
b8f5888
7c8040f
27b27d8
4eebd55
376e190
ff8c238
cb78bd9
22f93c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,3 +27,7 @@ func Slow() Labels { | |
| func TPM() Labels { | ||
| return Label("TPM") | ||
| } | ||
|
|
||
| func Legacy() Labels { | ||
| return Label("Legacy") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| /* | ||
| Copyright 2026 Flant JSC | ||
|
|
||
| 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 object | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "k8s.io/utils/ptr" | ||
| "sigs.k8s.io/yaml" | ||
| ) | ||
|
|
||
| // CloudConfig mirrors the cloud-init cloud-config YAML schema. | ||
| // Only the keys used by e2e tests are included. | ||
| // See https://cloudinit.readthedocs.io/en/latest/reference/modules.html | ||
| type CloudConfig struct { | ||
| PackageUpdate bool `json:"package_update,omitempty"` | ||
| Packages []string `json:"packages,omitempty"` | ||
| WriteFiles []WriteFile `json:"write_files,omitempty"` | ||
| Users []CloudConfigUser `json:"users,omitempty"` | ||
| Runcmd []string `json:"runcmd,omitempty"` | ||
| SSHPwauth *bool `json:"ssh_pwauth,omitempty"` | ||
| } | ||
|
|
||
| type CloudConfigUser struct { | ||
| Name string `json:"name"` | ||
| Passwd string `json:"passwd,omitempty"` | ||
| Shell string `json:"shell,omitempty"` | ||
| Sudo string `json:"sudo,omitempty"` | ||
| LockPasswd *bool `json:"lock_passwd,omitempty"` | ||
| SSHAuthorizedKeys []string `json:"ssh_authorized_keys,omitempty"` | ||
| } | ||
|
|
||
| type WriteFile struct { | ||
| Path string `json:"path"` | ||
| Permissions string `json:"permissions,omitempty"` | ||
| Content string `json:"content,omitempty"` | ||
| Append bool `json:"append,omitempty"` | ||
| } | ||
|
|
||
| const defaultSSHPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxcXHmwaGnJ8scJaEN5RzklBPZpVSic4GdaAsKjQoeA your_email@example.com" | ||
|
|
||
| // DefaultCloudUser returns the standard e2e test user (cloud/cloud) with SSH key. | ||
| func DefaultCloudUser() CloudConfigUser { | ||
| return CloudConfigUser{ | ||
| Name: DefaultUser, | ||
| Passwd: "$6$rounds=4096$vln/.aPHBOI7BMYR$bBMkqQvuGs5Gyd/1H5DP4m9HjQSy.kgrxpaGEHwkX7KEFV8BS.HZWPitAtZ2Vd8ZqIZRqmlykRCagTgPejt1i.", | ||
| Shell: "/bin/bash", | ||
| Sudo: "ALL=(ALL) NOPASSWD:ALL", | ||
| LockPasswd: ptr.To(false), | ||
| SSHAuthorizedKeys: []string{defaultSSHPublicKey}, | ||
| } | ||
| } | ||
|
|
||
| var basePackages = []string{ | ||
| "qemu-guest-agent", | ||
| "curl", | ||
| "bash", | ||
| "sudo", | ||
| "util-linux", | ||
| "iperf3", | ||
| "jq", | ||
| } | ||
|
|
||
| // Render serializes the CloudConfig to a valid cloud-init user-data string | ||
| // with the required #cloud-config header. | ||
| func (c CloudConfig) Render() string { | ||
| data, err := yaml.Marshal(c) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("cloud-config marshal: %v", err)) | ||
| } | ||
| return "#cloud-config\n" + string(data) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| /* | ||
| Copyright 2026 Flant JSC | ||
|
|
||
| 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 object | ||
|
|
||
| import ( | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| "sigs.k8s.io/yaml" | ||
| ) | ||
|
|
||
| func TestCloudConfigRender(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| rendered string | ||
| }{ | ||
| {"AlpineCloudInit", AlpineCloudInit}, | ||
| {"UbuntuCloudInit", UbuntuCloudInit}, | ||
| {"PerfCloudInit", PerfCloudInit}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| require.True(t, strings.HasPrefix(tt.rendered, "#cloud-config\n"), | ||
| "cloud-init must start with #cloud-config header") | ||
|
|
||
| var parsed map[string]interface{} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should it be parsed into the CloudConfig structure?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We intentionally parse into map[string]interface{} to verify actual YAML key names (which are controlled by the struct's json: tags via sigs.k8s.io/yaml). A round-trip through CloudConfig would always be self-consistent and wouldn't catch a tag typo that breaks the cloud-init contract. |
||
| err := yaml.Unmarshal([]byte(tt.rendered), &parsed) | ||
| require.NoError(t, err, "cloud-init must be valid YAML") | ||
|
|
||
| assert.Equal(t, true, parsed["package_update"]) | ||
|
|
||
| users, ok := parsed["users"].([]interface{}) | ||
| require.True(t, ok, "users must be a list") | ||
| require.Len(t, users, 1) | ||
|
|
||
| user := users[0].(map[string]interface{}) | ||
| assert.Equal(t, DefaultUser, user["name"]) | ||
| assert.Equal(t, false, user["lock_passwd"]) | ||
|
|
||
| keys, ok := user["ssh_authorized_keys"].([]interface{}) | ||
| require.True(t, ok) | ||
| require.Len(t, keys, 1) | ||
|
|
||
| runcmd, ok := parsed["runcmd"].([]interface{}) | ||
| require.True(t, ok, "runcmd must be a list") | ||
| assert.NotEmpty(t, runcmd) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestPerfCloudInitHasWriteFiles(t *testing.T) { | ||
| var parsed map[string]interface{} | ||
| err := yaml.Unmarshal([]byte(PerfCloudInit), &parsed) | ||
| require.NoError(t, err) | ||
|
|
||
| writeFiles, ok := parsed["write_files"].([]interface{}) | ||
| require.True(t, ok, "PerfCloudInit must have write_files") | ||
| require.Len(t, writeFiles, 1) | ||
|
|
||
| wf := writeFiles[0].(map[string]interface{}) | ||
| assert.Equal(t, "/usr/scripts/iperf3.sh", wf["path"]) | ||
| assert.Equal(t, "0755", wf["permissions"]) | ||
|
|
||
| content, ok := wf["content"].(string) | ||
| require.True(t, ok) | ||
| assert.Contains(t, content, "#!/bin/bash") | ||
| assert.Contains(t, content, "iperf3") | ||
| } | ||
|
|
||
| func TestPerfCloudInitGolden(t *testing.T) { | ||
| expected := `#cloud-config | ||
| package_update: true | ||
| packages: | ||
| - qemu-guest-agent | ||
| - curl | ||
| - bash | ||
| - sudo | ||
| - util-linux | ||
| - iperf3 | ||
| - jq | ||
| - iputils | ||
| runcmd: | ||
| - /usr/scripts/iperf3.sh | ||
| - rc-update add qemu-guest-agent && rc-service qemu-guest-agent start | ||
| - rc-update add iperf3 && rc-service iperf3 start | ||
| - rc-update add sshd && rc-service sshd start | ||
| users: | ||
| - lock_passwd: false | ||
| name: cloud | ||
| passwd: $6$rounds=4096$vln/.aPHBOI7BMYR$bBMkqQvuGs5Gyd/1H5DP4m9HjQSy.kgrxpaGEHwkX7KEFV8BS.HZWPitAtZ2Vd8ZqIZRqmlykRCagTgPejt1i. | ||
| shell: /bin/bash | ||
| ssh_authorized_keys: | ||
| - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxcXHmwaGnJ8scJaEN5RzklBPZpVSic4GdaAsKjQoeA | ||
| your_email@example.com | ||
| sudo: ALL=(ALL) NOPASSWD:ALL | ||
| write_files: | ||
| - content: | | ||
| #!/bin/bash | ||
| cat > /etc/init.d/iperf3 <<-"EOF" | ||
| #!/sbin/openrc-run | ||
|
|
||
| name="iperf3" | ||
| description="iperf3 server" | ||
| command="/usr/bin/iperf3" | ||
| command_args="-s" | ||
| pidfile="/run/${name}.pid" | ||
| supervisor="supervise-daemon" | ||
| supervise_daemon_args="--respawn-delay 2 --stdout /var/log/iperf3.log --stderr /var/log/iperf3.log" | ||
|
|
||
| depend() { | ||
| need net | ||
| } | ||
|
|
||
| start_pre() { | ||
| checkpath --directory --owner root:root --mode 0755 /run | ||
| touch /var/log/iperf3.log | ||
| chmod 644 /var/log/iperf3.log | ||
| } | ||
|
|
||
| stop_post() { | ||
| logger -t iperf3 "Stopped by $(whoami) at $(date)" | ||
| rm -f "$pidfile" | ||
| } | ||
| EOF | ||
| chmod +x /etc/init.d/iperf3 | ||
| rc-update add iperf3 default | ||
| path: /usr/scripts/iperf3.sh | ||
| permissions: "0755" | ||
| ` | ||
|
|
||
| assert.Equal(t, expected, PerfCloudInit) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be a validation method of CloudConfig. But not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The #cloud-config header is a property of the rendered string, not the CloudConfig struct itself — Render() always prepends it. A Validate() method on the struct wouldn't have access to it. This check is purely a test-level assertion that the pre-rendered constants are well-formed, so I think it fits better here as is.