Skip to content
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

CI test for flavor-name syntax in scs-0103 yaml file #438

Merged
merged 6 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions Tests/iaas/flavor-naming/check-yaml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""Check flavor names in the YAML files used for scs-0103-v1 with respect to scs-0100-vX.
mbuechse marked this conversation as resolved.
Show resolved Hide resolved

For reference, see

- </Standards/scs-0100-v3-flavor-naming.md>
- </Standards/scs-0103-v1-standard-flavors.md>

Also check that the flavor properties encoded in the YAML match those encoded in the name.
"""
import importlib
import os
import os.path
import sys

import yaml

flavor_name_check = importlib.import_module("flavor-name-check")
flavor_name_check.disallow_old = True


REQUIRED_FIELDS = ['name-v1', 'name-v2', 'name', 'cpus', 'ram', 'cpu-type']
DEFAULTS = {'disk0-type': 'network'}
CPUTYPE_KEY = {'L': 'crowded-core', 'V': 'shared-core', 'T': 'dedicated-thread', 'C': 'dedicated-core'}
DISKTYPE_KEY = {'n': 'network', 'h': 'hdd', 's': 'ssd', 'p': 'nvme'}


class Undefined:
def __repr__(self):
return 'undefined'


class Checker:
mbuechse marked this conversation as resolved.
Show resolved Hide resolved
"""
Auxiliary class that contains the logic for checking a single flavor spec
as well as emitting error messages to stderr.

Once this program grows (significantly), this class should actually be split
in two in order to follow the single-responsibility principle.
"""
def __init__(self):
self.errors = 0

def emit(self, s):
print(f"ERROR: {s}", file=sys.stderr)
self.errors += 1

def check_spec(self, flavor_spec):
missing = [key for key in REQUIRED_FIELDS if key not in flavor_spec]
if missing:
self.emit(f"flavor spec missing keys {', '.join(missing)}: {flavor_spec}")
return
name = flavor_spec['name']
name_v2 = flavor_spec['name-v2']
parsed = flavor_name_check.parsename(name_v2)
if not parsed:
self.emit(f"flavor {name}: name-v2 '{name_v2}' could not be parsed")
return
cpu, disk, hype, hvirt, cpubrand, gpu, ibd = parsed
undefined = Undefined()
expected = {
'cpus': cpu.cpus,
'cpu-type': CPUTYPE_KEY[cpu.cputype],
'ram': cpu.ram,
'name-v1': flavor_name_check.new_to_old(name_v2),
'disk': undefined,
}
if disk.parsed:
if disk.nrdisks != 1:
self.emit(f"flavor '{name}': name-v2 using multiple disks")
expected['disk'] = disk.disksize
expected['disk0-type'] = DISKTYPE_KEY[disk.disktype or 'n']
for key, exp_val in expected.items():
val = flavor_spec.get(key, DEFAULTS.get(key, undefined))
if val != exp_val:
self.emit(
f"flavor '{name}': field '{key}' contradicting name-v2 '{name_v2}'; "
f"found {val!r}, expected {exp_val!r}"
)


def main(argv):
if len(argv) != 2:
raise RuntimeError("must specify exactly one argument, PATH to the yaml directory")
yaml_path = argv[1]
yaml_files = sorted([
filename
for filename in os.listdir(yaml_path)
if filename.startswith("scs-0103-") and filename.endswith(".yaml")
])
main_checker = Checker()
if not yaml_files:
main_checker.emit("no yaml files found!")
for filename in yaml_files:
with open(os.path.join(yaml_path, filename), "rb") as fileobj:
flavor_spec_data = yaml.safe_load(fileobj)
if 'flavor_groups' not in flavor_spec_data:
main_checker.emit(f"file '{filename}': missing field 'flavor_groups'")
continue
checker = Checker()
for group in flavor_spec_data['flavor_groups']:
for flavor_spec in group['list']:
checker.check_spec(flavor_spec)
if checker.errors:
main_checker.emit(f"file '{filename}': found {checker.errors} errors")
return main_checker.errors


if __name__ == "__main__":
try:
sys.exit(main(sys.argv))
except Exception as e:
print(f"CRITICAL: {e!s}", file=sys.stderr)
sys.exit(1)
195 changes: 195 additions & 0 deletions Tests/testing/scs-0103-v1-flavors-wrong.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
meta:
name_key: name-v2
flavor_groups:
- status: mandatory
list:
- name: SCS-1V-4
cpus: 1
cpu-type: crowded-core # wrong: name suggests shared-core
ram: 4
name-v1: SCS-1V:4
name-v2: SCS-1V-4
- name: SCS-2V-8
cpus: 2
cpu-type: shared-core
ram: 8
name-v1: SCS-2V-8 # wrong: not a v1 name
name-v2: SCS-2V-8
- name: SCS-4V-16
cpus: 4
cpu-type: shared-core
ram: 12 # wrong: name suggests 16
name-v1: SCS-4V:16
name-v2: SCS-4V-16
- name: SCS-8V-32
cpus: 8
cpu-type: shared-core
ram: 32
disk: 128 # wrong: no disk in name
name-v1: SCS-8V:32
name-v2: SCS-8V-32
- name: SCS-1V-2
cpus: 2 # wrong: name suggests 1 cpu
cpu-type: shared-core
ram: 2
name-v1: SCS-1V:2
name-v2: SCS-1V-2
- name: SCS-2V-4
cpus: 2
cpu-type: shared-core
ram: 4
name-v1: SCS-2V:4
name-v2: SCS-2V-4
- name: SCS-4V-8
cpus: 4
cpu-type: shared-core
ram: 8
name-v1: SCS-4V:8
name-v2: SCS-4V-8
- name: SCS-8V-16
cpus: 8
cpu-type: shared-core
ram: 16
name-v1: SCS-8V:16
name-v2: SCS-8V-16
- name: SCS-16V-32
cpus: 16
cpu-type: shared-core
ram: 32
name-v1: SCS-16V:32
name-v2: SCS-16V-32
- name: SCS-1V-8
cpus: 1
cpu-type: shared-core
ram: 8
name-v1: SCS-1V:8
name-v2: SCS-1V-8
- name: SCS-2V-16
cpus: 2
cpu-type: shared-core
ram: 16
name-v1: SCS-2V:16
name-v2: SCS-2V-16
- name: SCS-4V-32
cpus: 4
cpu-type: shared-core
ram: 32
name-v1: SCS-4V:32
name-v2: SCS-4V-32
- name: SCS-1L-1
cpus: 1
cpu-type: crowded-core
ram: 1
name-v1: SCS-1L:1
name-v2: SCS-1L-1
- status: mandatory
list:
- name: SCS-2V-4-20s
cpus: 2
cpu-type: shared-core
ram: 4
disk: 20
# wrong: name suggests disk-type ssd
name-v1: SCS-2V:4:20s
name-v2: SCS-2V-4-20s
- name: SCS-4V-16-100s
cpus: 4
cpu-type: shared-core
ram: 16
disk: 10 # wrong: name suggests 100
disk0-type: ssd
name-v1: SCS-4V:16:100s
name-v2: SCS-4V-16-100s
- status: recommended
list:
- name: SCS-1V-4-10
cpus: 1
cpu-type: shared-core
ram: 4
disk: 10
name-v1: SCS-1V:4:10
name-v2: SCS-1V-4-10
- name: SCS-2V-8-20
cpus: 2
cpu-type: shared-core
ram: 8
disk: 20
name-v1: SCS-2V:8:20
name-v2: SCS-2V-8-20
- name: SCS-4V-16-50
cpus: 4
cpu-type: shared-core
ram: 16
disk: 50
name-v1: SCS-4V:16:50
name-v2: SCS-4V-16-50
- name: SCS-8V-32-100
cpus: 8
cpu-type: shared-core
ram: 32
disk: 100
name-v1: SCS-8V:32:100
name-v2: SCS-8V-32-100
- name: SCS-1V-2-5
cpus: 1
cpu-type: shared-core
ram: 2
disk: 5
name-v1: SCS-1V:2:5
name-v2: SCS-1V-2-5
- name: SCS-2V-4-10
cpus: 2
cpu-type: shared-core
ram: 4
disk: 10
name-v1: SCS-2V:4:10
name-v2: SCS-2V-4-10
- name: SCS-4V-8-20
cpus: 4
cpu-type: shared-core
ram: 8
disk: 20
name-v1: SCS-4V:8:20
name-v2: SCS-4V-8-20
- name: SCS-8V-16-50
cpus: 8
cpu-type: shared-core
ram: 16
disk: 50
name-v1: SCS-8V:16:50
name-v2: SCS-8V-16-50
- name: SCS-16V-32-100
cpus: 16
cpu-type: shared-core
ram: 32
disk: 100
name-v1: SCS-16V:32:100
name-v2: SCS-16V-32-100
- name: SCS-1V-8-20
cpus: 1
cpu-type: shared-core
ram: 8
disk: 20
name-v1: SCS-1V:8:20
name-v2: SCS-1V-8-20
- name: SCS-2V-16-50
cpus: 2
cpu-type: shared-core
ram: 16
disk: 50
name-v1: SCS-2V:16:50
name-v2: SCS-2V-16-50
- name: SCS-4V-32-100
cpus: 4
cpu-type: shared-core
ram: 32
disk: 100
name-v1: SCS-4V:32:100
name-v2: SCS-4V-32-100
- name: SCS-1L-1-5
cpus: 1
cpu-type: crowded-core
ram: 1
disk: 5
name-v1: SCS-1L:1:5
name-v2: SCS-1L-1-5
11 changes: 9 additions & 2 deletions playbooks/adr_syntax.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- name: Run ADR syntax check tool
- name: Run ADR syntax check tool and test script consistency check tool
hosts: all
roles:
- role: ensure-pip # https://zuul-ci.org/docs/zuul-jobs/latest/python-roles.html#role-ensure-pip
Expand All @@ -22,12 +22,19 @@
ansible.builtin.pip:
requirements: /home/ubuntu/Tests/requirements.txt

- name: Run check script
- name: Run ADR syntax check script
ansible.builtin.command:
cmd: python3 /home/ubuntu/Tests/chk_adrs.py /home/ubuntu/Standards
register: result
changed_when: true
failed_when: result.rc != 0

- name: Run test script consistency check script
ansible.builtin.command:
cmd: python3 /home/ubuntu/Tests/iaas/flavor-naming/check-yaml.py /home/ubuntu/Tests/iaas
register: result
changed_when: true
failed_when: result.rc != 0

- ansible.builtin.debug:
msg: "{{ result.stdout }} {{ result.stderr }}"