Commit 0c68b065 authored by Rémi Duraffort's avatar Rémi Duraffort Committed by stevanradakovic

schema: add a device schema into lava_common

Use this schema validator in lava_dispatcher. lava_dispatcher tests does not
depends anymore on lava_scheduler_app.

This will be usefull when lava_scheduler_app,schema depends on the settings.
Signed-off-by: default avatarRémi Duraffort <remi.duraffort@linaro.org>
parent 1ac122ef
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 Linaro Limited
#
# Author: Rémi Duraffort <remi.duraffort@linaro.org>
#
# This file is part of LAVA.
#
# LAVA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LAVA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along
# with this program; if not, see <http://www.gnu.org/licenses>.
import contextlib
from voluptuous import All, Any, Invalid, Length, Optional, Required, Schema
from . import timeout
def device():
timeout_schema = timeout()
return {
Optional("character_delays"): dict,
Optional("commands"): {
Optional("connect"): str,
Optional("connections"): {
str: {Required("connect"): str, Optional("tags"): [str]}
},
Optional("hard_reset"): Any(str, [str]),
Optional("soft_reset"): Any(str, [str]),
Optional("soft_reboot"): Any(str, [str]),
Optional("power_off"): Any(str, [str]),
Optional("power_on"): Any(str, [str]),
Optional("pre_power_command"): Any(str, [str]),
Optional("pre_os_command"): Any(str, [str]),
Optional("users"): {str: {Required("do"): str, Optional("undo"): str}},
},
Optional("constants"): dict,
Optional("adb_serial_number"): str,
Optional("fastboot_serial_number"): str,
Optional("fastboot_options"): [str],
Optional("fastboot_via_uboot"): bool,
Optional("device_info"): [dict],
Optional("static_info"): [dict],
Optional("storage_info"): [dict],
Optional("flash_cmds_order"): list,
Optional("parameters"): dict,
Optional("board_id"): str,
Optional("usb_vendor_id"): All(
str, Length(min=4, max=4)
), # monitor type like arduino
Optional("usb_product_id"): All(
str, Length(min=4, max=4)
), # monitor type like arduino
Optional("usb_sleep"): int,
Optional("usb_filesystem_label"): str,
Optional("usb_serial_driver"): str,
Optional("actions"): {
Required("deploy"): {
Required("methods"): dict,
Optional("connections"): dict,
Optional("parameters"): dict,
},
Required("boot"): {
Required("connections"): dict,
Required("methods"): dict,
},
},
Optional("timeouts"): {
Required("actions"): {str: timeout_schema},
Required("connections"): {str: timeout_schema},
},
Optional("available_architectures"): [str],
}
def extra_checks(data):
power_control_commands = ["power_off", "power_on", "hard_reset"]
with contextlib.suppress(KeyError):
ssh_host = data["actions"]["deploy"]["methods"]["ssh"]["host"]
if ssh_host and "commands" in data:
for command in power_control_commands:
if command in data["commands"]:
raise Invalid(
"When primary connection is used, power control commands (%s) should not be specified."
% ", ".join(power_control_commands)
)
def validate(data):
schema = Schema(All(device(), extra_checks), extra=True)
schema(data)
......@@ -22,6 +22,7 @@ import os
import sys
import time
import jinja2
import voluptuous
import unittest
import logging
import yaml
......@@ -34,14 +35,11 @@ from lava_common.exceptions import (
LAVAError,
ConfigurationError,
)
from lava_common.schemas import validate as validate_job
from lava_common.schemas.device import validate as validate_device
from lava_dispatcher.parser import JobParser
from lava_dispatcher.job import Job
from lava_dispatcher.device import NewDevice
from lava_scheduler_app.schema import (
validate_device,
validate_submission,
SubmissionException,
)
from lava_dispatcher.actions.deploy.image import DeployImages
from lava_dispatcher.tests.utils import DummyLogger
......@@ -216,11 +214,11 @@ class Factory:
rendered = self.render_device_dictionary(hostname, data, job_ctx)
try:
ret = validate_device(yaml.safe_load(rendered))
except (SubmissionException, ConfigurationError) as exc:
except (voluptuous.Invalid, ConfigurationError) as exc:
print("#######")
print(rendered)
print("#######")
self.fail(exc)
raise exc
return ret
def create_device(self, template, job_ctx=None):
......@@ -244,9 +242,9 @@ class Factory:
rendered = self.render_device_dictionary(hostname, data, job_ctx)
return (rendered, data)
def create_custom_job(self, template, job_data, job_ctx=None, validate_job=True):
if validate_job:
validate_submission(job_data)
def create_custom_job(self, template, job_data, job_ctx=None, validate=True):
if validate:
validate_job(job_data, strict=False)
if job_ctx:
job_data["context"] = job_ctx
else:
......@@ -268,16 +266,16 @@ class Factory:
job.logger = DummyLogger()
return job
def create_job(self, template, filename, job_ctx=None, validate_job=True):
def create_job(self, template, filename, job_ctx=None, validate=True):
y_file = os.path.join(os.path.dirname(__file__), filename)
with open(y_file) as sample_job_data:
job_data = yaml.safe_load(sample_job_data.read())
return self.create_custom_job(template, job_data, job_ctx, validate_job)
return self.create_custom_job(template, job_data, job_ctx, validate)
def create_fake_qemu_job(self):
return self.create_job("qemu01.jinja2", "sample_jobs/basics.yaml")
def create_kvm_job(self, filename, validate_job=False):
def create_kvm_job(self, filename, validate=False):
"""
Custom function to allow for extra exception handling.
"""
......@@ -299,8 +297,8 @@ class Factory:
job_data = yaml.safe_load(sample_job_data.read())
if self.debug:
print("########## Test Job Submission validation #######")
if validate_job:
validate_submission(job_data)
if validate:
validate_job(job_data, strict=False)
try:
job = parser.parse(yaml.dump(job_data), device, 4212, None, "")
job.logger = DummyLogger()
......
......@@ -40,10 +40,10 @@ class ConnectionFactory(Factory): # pylint: disable=too-few-public-methods
"""
def create_ssh_job(self, filename):
return self.create_job("ssh-host-01.jinja2", filename, validate_job=False)
return self.create_job("ssh-host-01.jinja2", filename, validate=False)
def create_bbb_job(self, filename):
return self.create_job("bbb-02.jinja2", filename, validate_job=False)
return self.create_job("bbb-02.jinja2", filename, validate=False)
class TestConnection(StdoutTestCase): # pylint: disable=too-many-public-methods
......@@ -646,7 +646,7 @@ class TestDisconnect(StdoutTestCase):
def test_handled_disconnect(self):
factory = ConnectionFactory()
job = factory.create_job(
"mps2plus-01.jinja2", "sample_jobs/mps2plus.yaml", validate_job=False
"mps2plus-01.jinja2", "sample_jobs/mps2plus.yaml", validate=False
)
job.validate()
deploy = [
......@@ -657,7 +657,7 @@ class TestDisconnect(StdoutTestCase):
def test_disconnect_with_plain_connection_command(self):
factory = ConnectionFactory()
job = factory.create_job(
"mps2plus-02.jinja2", "sample_jobs/mps2plus.yaml", validate_job=False
"mps2plus-02.jinja2", "sample_jobs/mps2plus.yaml", validate=False
)
# mps2plus-02.jinja2 does not use tags for it's connection
with self.assertRaises(JobError):
......@@ -666,7 +666,7 @@ class TestDisconnect(StdoutTestCase):
def test_unhandled_disconnect(self):
factory = ConnectionFactory()
job = factory.create_job(
"mps2plus-03.jinja2", "sample_jobs/mps2plus.yaml", validate_job=False
"mps2plus-03.jinja2", "sample_jobs/mps2plus.yaml", validate=False
)
try:
job.validate()
......
......@@ -97,8 +97,8 @@ class TestDefinitionHandlers(StdoutTestCase): # pylint: disable=too-many-public
class X86Factory(Factory):
def create_x86_job(self, filename, device, validate_job=True):
return self.create_job(device, filename, validate_job=validate_job)
def create_x86_job(self, filename, device, validate=True):
return self.create_job(device, filename, validate=validate)
class TestMultiNodeOverlay(StdoutTestCase): # pylint: disable=too-many-public-methods
......@@ -106,14 +106,10 @@ class TestMultiNodeOverlay(StdoutTestCase): # pylint: disable=too-many-public-m
super().setUp()
factory = X86Factory()
self.server_job = factory.create_x86_job(
"sample_jobs/test_action-1.yaml",
"lng-generator-01.jinja2",
validate_job=False,
"sample_jobs/test_action-1.yaml", "lng-generator-01.jinja2", validate=False
)
self.client_job = factory.create_x86_job(
"sample_jobs/test_action-2.yaml",
"lng-generator-02.jinja2",
validate_job=False,
"sample_jobs/test_action-2.yaml", "lng-generator-02.jinja2", validate=False
)
def test_action_namespaces(self):
......
......@@ -42,9 +42,7 @@ class TestSkipTimeouts(StdoutTestCase):
os.path.dirname(__file__), "testdefs", "result-data.txt"
)
factory = Factory()
self.job = factory.create_kvm_job(
"sample_jobs/qemu-reboot.yaml", validate_job=True
)
self.job = factory.create_kvm_job("sample_jobs/qemu-reboot.yaml", validate=True)
self.job.logger = DummyLogger()
self.job.validate()
self.ret = False
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment