1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
"""Tests for `cloud-init status`"""
from textwrap import dedent
import pytest
from cloudinit import lifecycle
from tests.integration_tests.instances import IntegrationInstance
from tests.integration_tests.util import (
get_feature_flag_value,
has_netplanlib,
verify_clean_boot,
verify_clean_log,
)
USER_DATA = """\
#cloud-config
apt_update: false
apt_upgrade: false
apt_reboot_if_required: false
"""
NET_CFG_V1 = """\
network:
version: 1
config:
- type: physical
name: eth0
subnets:
- type: dhcp
"""
NET_CFG_V1_INVALID = NET_CFG_V1.replace("config", "junk")
NET_V1_ANNOTATED = """\
network: # E1,E2
version: 1
junk:
- type: physical
name: eth0
subnets:
- type: dhcp
# Errors: -------------
# E1: 'config' is a required property
# E2: Additional properties are not allowed ('junk' was unexpected)"""
NET_CFG_V2 = """\
version: 2
ethernets:
eth0:
dhcp4: true
"""
NET_CFG_V2_INVALID = NET_CFG_V2.replace("true", "bogus")
NET_V2_ANNOTATED = """\
---
network:
ethernets:
eth0:
dhcp4: bogus # E1
version: 2
...
# Errors: -------------
# E1: Invalid netplan schema. Error in network definition: invalid boolean value 'bogus'""" # noqa: E501
@pytest.mark.user_data(USER_DATA)
class TestSchemaDeprecations:
def test_clean_log(self, class_client: IntegrationInstance):
log = class_client.read_from_file("/var/log/cloud-init.log")
verify_clean_log(log, ignore_deprecations=True)
version_boundary = get_feature_flag_value(
class_client, "DEPRECATION_INFO_BOUNDARY"
)
boundary_message = "Deprecated cloud-config provided:"
messages = [
"apt_reboot_if_required: Deprecated ",
"apt_update: Deprecated in version",
"apt_upgrade: Deprecated in version",
]
# the deprecation_version is 22.2 in schema for apt_* keys in
# user-data. Pass 22.2 in against the client's version_boundary.
if lifecycle.should_log_deprecation("22.2", version_boundary):
messages += boundary_message
verify_clean_boot(class_client, require_deprecations=messages)
else:
verify_clean_boot(class_client)
assert f"INFO]: {boundary_message}" in log
assert "apt_reboot_if_required: Deprecated " in log
assert "apt_update: Deprecated in version" in log
assert "apt_upgrade: Deprecated in version" in log
def test_network_config_schema_validation(
self, class_client: IntegrationInstance
):
content_responses = {
NET_CFG_V1: {"out": "Valid schema /root/net.yaml"},
NET_CFG_V1_INVALID: {
"out": "Invalid network-config /root/net.yaml",
"err": (
"network: Additional properties are not allowed"
" ('junk' was unexpected)"
),
"annotate": NET_V1_ANNOTATED,
},
}
if has_netplanlib(class_client):
# Support for netplan API available
content_responses[NET_CFG_V2] = {
"out": "Valid schema /root/net.yaml"
}
content_responses[NET_CFG_V2_INVALID] = {
"out": "Invalid network-config /root/net.yaml",
"err": (
"Cloud config schema errors: format-l5.c20:"
" Invalid netplan schema. Error in network definition:"
" invalid boolean value 'bogus'"
),
"annotate": NET_V2_ANNOTATED,
}
else:
# No netplan API available skips validation
content_responses[NET_CFG_V2] = {
"out": (
"Skipping network-config schema validation for version: 2."
" No netplan API available."
)
}
content_responses[NET_CFG_V2_INVALID] = {
"out": (
"Skipping network-config schema validation for version: 2."
" No netplan API available."
)
}
for content, responses in content_responses.items():
class_client.write_to_file("/root/net.yaml", content)
result = class_client.execute(
"cloud-init schema --schema-type network-config"
" --config-file /root/net.yaml"
)
assert responses["out"] == result.stdout
if responses.get("err"):
assert responses["err"] in result.stderr
if responses.get("annotate"):
result = class_client.execute(
"cloud-init schema --schema-type network-config"
" --config-file /root/net.yaml --annotate"
)
assert responses["annotate"] in result.stdout
def test_schema_deprecations(self, class_client: IntegrationInstance):
"""Test schema behavior with deprecated configs."""
user_data_fn = "/root/user-data"
class_client.write_to_file(user_data_fn, USER_DATA)
result = class_client.execute(
f"cloud-init schema --config-file {user_data_fn}"
)
assert (
result.ok
), "`schema` cmd must return 0 even with deprecated configs"
assert not result.stderr
assert "Cloud config schema deprecations:" in result.stdout
assert "apt_update: Deprecated in version" in result.stdout
assert "apt_upgrade: Deprecated in version" in result.stdout
assert (
"apt_reboot_if_required: Deprecated in version" in result.stdout
)
annotated_result = class_client.execute(
f"cloud-init schema --annotate --config-file {user_data_fn}"
)
assert (
annotated_result.ok
), "`schema` cmd must return 0 even with deprecated configs"
assert not annotated_result.stderr
expected_output = dedent(
"""\
#cloud-config
apt_update: false\t\t# D1
apt_upgrade: false\t\t# D2
apt_reboot_if_required: false\t\t# D3
# Deprecations: -------------
# D1: Deprecated in version 22.2. Use **package_update** instead.
# D2: Deprecated in version 22.2. Use **package_upgrade** instead.
# D3: Deprecated in version 22.2. Use **package_reboot_if_required** instead.
Valid schema /root/user-data""" # noqa: E501
)
assert expected_output in annotated_result.stdout
|