Skip to content

Commit 491e655

Browse files
committed
Merge branch 'automation-v2.2.0.0' into automation-v2.2.0.0
2 parents 0dd7b41 + aebc71f commit 491e655

162 files changed

Lines changed: 24777 additions & 5058 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,3 @@ reports/
1717

1818
# PXE mapping backup (generated by delete node tests)
1919
.backup/
20-
omnia_test_config.yml

README.md

Lines changed: 216 additions & 340 deletions
Large diffs are not rendered by default.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2026 Dell Inc. or its subsidiaries. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Additional Cloud-Init Module
17+
18+
This module provides functions for additional cloud-init configuration verification.
19+
Uses core module utilities for SSH, PXE mapping, and config reading.
20+
21+
Test Categories:
22+
- Configuration: File validation, YAML parsing, prohibited key checks
23+
- SMD Groups: Common and per-FG group creation, idempotency
24+
- Templates: Cloud-init rendering with merge_how behavior
25+
- BSS Integration: Group registration and boot management
26+
- End-to-End: Full provisioning with write_files and runcmd
27+
"""
28+
29+
from .functions import (
30+
# Common functions
31+
get_functional_groups_from_config,
32+
load_additional_cloud_init_config,
33+
skip_if_additional_cloud_init_disabled,
34+
# Validation functions
35+
validate_cloud_init_config,
36+
validate_functional_groups,
37+
check_prohibited_keys,
38+
validate_write_files,
39+
validate_runcmd,
40+
# SMD functions
41+
verify_smd_group_creation,
42+
verify_smd_group_deletion,
43+
verify_bss_group_registration,
44+
# Node verification functions
45+
verify_cloud_init_files_on_nodes,
46+
verify_runcmd_execution_on_nodes,
47+
verify_additional_cloud_init_integration,
48+
)
49+
from .vars import (
50+
ADDITIONAL_CLOUD_INIT_CONFIG_PATH,
51+
ADDITIONAL_CLOUD_INIT_RETRY_COUNT,
52+
ADDITIONAL_CLOUD_INIT_RETRY_INTERVAL,
53+
PROHIBITED_CLOUD_INIT_KEYS,
54+
ALLOWED_CLOUD_INIT_KEYS,
55+
SMD_GROUP_PREFIX,
56+
COMMON_SMD_GROUP_NAME,
57+
)
58+
from .messages import (
59+
TEST_NAMES,
60+
TEST_LOG_MSGS,
61+
TEST_ASSERT_MSGS,
62+
SKIP_MSGS,
63+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2026 Dell Inc. or its subsidiaries. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Additional Cloud-Init Module - Function Exports.
17+
18+
Re-exports functions from sub-files for external use.
19+
"""
20+
21+
from .common_func import (
22+
get_functional_groups_from_config,
23+
load_additional_cloud_init_config,
24+
skip_if_additional_cloud_init_disabled,
25+
get_nodes_by_functional_group,
26+
get_all_nodes_for_common,
27+
)
28+
from .validation_func import (
29+
validate_cloud_init_config,
30+
validate_functional_groups,
31+
check_prohibited_keys,
32+
validate_write_files,
33+
validate_runcmd,
34+
run_omnia_validation_playbook,
35+
)
36+
from .smd_func import (
37+
verify_smd_group_creation,
38+
verify_smd_group_deletion,
39+
verify_bss_group_registration,
40+
get_xnames_for_fg,
41+
get_all_xnames,
42+
)
43+
from .node_verification_func import (
44+
verify_cloud_init_files_on_nodes,
45+
verify_runcmd_execution_on_nodes,
46+
verify_additional_cloud_init_integration,
47+
)
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Copyright 2026 Dell Inc. or its subsidiaries. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Additional Cloud-Init Module - Common Functions.
17+
18+
Common utilities for additional cloud-init configuration handling.
19+
"""
20+
21+
import os
22+
import pytest
23+
from typing import Dict, Any, List, Optional
24+
25+
from automation_library.core import (
26+
TestLogger,
27+
load_input_file,
28+
get_input_value,
29+
get_functional_groups_from_pxe_mapping,
30+
get_nodes_info,
31+
)
32+
from ..vars.common_vars import ADDITIONAL_CLOUD_INIT_CONFIG_PATH
33+
34+
35+
# Configuration cache
36+
_config_cache: Dict[str, Any] = {}
37+
38+
39+
def clear_cache():
40+
"""Clear all caches. Call at start of test run."""
41+
_config_cache.clear()
42+
43+
44+
def load_additional_cloud_init_config(host) -> Dict[str, Any]:
45+
"""
46+
Load and parse the additional_cloud_init configuration file.
47+
48+
Args:
49+
host: Testinfra host object
50+
51+
Returns:
52+
Dict containing:
53+
- success (bool): True if config loaded successfully
54+
- error (str): Error message if failed
55+
- config (dict): Parsed configuration data
56+
- enabled (bool): True if feature is enabled
57+
"""
58+
cache_key = "additional_cloud_init_config"
59+
if cache_key in _config_cache:
60+
return _config_cache[cache_key]
61+
62+
try:
63+
# Get the config file path from provision_config.yml
64+
config_file_path = get_input_value(
65+
host,
66+
"provision_config.yml",
67+
"additional_cloud_init_config_file",
68+
""
69+
)
70+
71+
if not config_file_path or config_file_path.strip() == "":
72+
result = {
73+
"success": True,
74+
"error": "",
75+
"config": {},
76+
"enabled": False,
77+
}
78+
_config_cache[cache_key] = result
79+
return result
80+
81+
# Load the actual config file
82+
# Extract just the filename since load_input_file prepends INPUT_BASE_PATH
83+
config_filename = os.path.basename(config_file_path)
84+
config_data = load_input_file(host, config_filename)
85+
86+
if not config_data:
87+
config_data = {}
88+
89+
result = {
90+
"success": True,
91+
"error": "",
92+
"config": config_data,
93+
"enabled": bool(config_data),
94+
}
95+
96+
except Exception as e:
97+
result = {
98+
"success": False,
99+
"error": f"Failed to load additional_cloud_init config: {str(e)}",
100+
"config": {},
101+
"enabled": False,
102+
}
103+
104+
_config_cache[cache_key] = result
105+
return result
106+
107+
108+
def get_functional_groups_from_config(host, config: Dict[str, Any]) -> Dict[str, Any]:
109+
"""
110+
Get functional groups from additional cloud-init config and validate against PXE mapping.
111+
112+
Args:
113+
host: Testinfra host object
114+
config: Additional cloud-init configuration
115+
116+
Returns:
117+
Dict containing:
118+
- success (bool): True if successful
119+
- error (str): Error message if failed
120+
- common_groups (list): Functional groups for common section
121+
- per_fg_groups (list): Per-FG functional groups
122+
- all_groups (set): All functional groups referenced
123+
- available_groups (set): Available groups in PXE mapping
124+
"""
125+
try:
126+
# Get available functional groups from PXE mapping
127+
available_groups = get_functional_groups_from_pxe_mapping(host)
128+
129+
# Get groups from config
130+
common_groups = []
131+
per_fg_groups = []
132+
all_groups = set()
133+
134+
# If common section exists, applies to ALL groups in PXE mapping
135+
if config.get("common"):
136+
common_groups = list(available_groups)
137+
all_groups.update(available_groups)
138+
139+
# Get per-FG groups
140+
groups_section = config.get("groups", {})
141+
if groups_section:
142+
per_fg_groups = list(groups_section.keys())
143+
all_groups.update(per_fg_groups)
144+
145+
return {
146+
"success": True,
147+
"error": "",
148+
"common_groups": common_groups,
149+
"per_fg_groups": per_fg_groups,
150+
"all_groups": all_groups,
151+
"available_groups": available_groups,
152+
}
153+
154+
except Exception as e:
155+
return {
156+
"success": False,
157+
"error": f"Failed to get functional groups: {str(e)}",
158+
"common_groups": [],
159+
"per_fg_groups": [],
160+
"all_groups": set(),
161+
"available_groups": set(),
162+
}
163+
164+
165+
def skip_if_additional_cloud_init_disabled(host, log: TestLogger = None):
166+
"""Skip test if additional cloud-init is not enabled."""
167+
config_result = load_additional_cloud_init_config(host)
168+
169+
if not config_result["success"]:
170+
reason = f"Failed to load config: {config_result['error']}"
171+
if log:
172+
log.skipped(reason, "Test skipped")
173+
pytest.skip(reason)
174+
175+
if not config_result["enabled"]:
176+
reason = "Additional cloud-init is not enabled (empty or no config file)"
177+
if log:
178+
log.skipped(reason, "Test skipped")
179+
pytest.skip(reason)
180+
181+
182+
def get_nodes_by_functional_group(host, functional_group: str) -> List[Dict[str, Any]]:
183+
"""
184+
Get nodes for a specific functional group.
185+
186+
Args:
187+
host: Testinfra host object
188+
functional_group: Functional group name
189+
190+
Returns:
191+
List of node dictionaries from PXE mapping
192+
"""
193+
try:
194+
return get_nodes_info(host, search_by="functional_group", search_value=functional_group)
195+
except Exception:
196+
return []
197+
198+
199+
def get_all_nodes_for_common(host) -> List[Dict[str, Any]]:
200+
"""
201+
Get all nodes from PXE mapping for common cloud-init section.
202+
203+
Args:
204+
host: Testinfra host object
205+
206+
Returns:
207+
List of all node dictionaries from PXE mapping
208+
"""
209+
try:
210+
available_groups = get_functional_groups_from_pxe_mapping(host)
211+
all_nodes = []
212+
213+
for fg in available_groups:
214+
nodes = get_nodes_info(host, search_by="functional_group", search_value=fg)
215+
all_nodes.extend(nodes)
216+
217+
return all_nodes
218+
except Exception:
219+
return []

0 commit comments

Comments
 (0)