Merge "[UI] UI enhancements"
[validation.git] / bluval / bluval.py
1 #!/usr/bin/python3
2 ##############################################################################
3 # Copyright (c) 2019 AT&T Intellectual Property.                             #
4 # Copyright (c) 2019 Nokia.                                                  #
5 #                                                                            #
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may    #
7 # not use this file except in compliance with the License.                   #
8 #                                                                            #
9 # You may obtain a copy of the License at                                    #
10 #       http://www.apache.org/licenses/LICENSE-2.0                           #
11 #                                                                            #
12 # Unless required by applicable law or agreed to in writing, software        #
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT  #
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.           #
15 # See the License for the specific language governing permissions and        #
16 # limitations under the License.                                             #
17 ##############################################################################
18 """This module parses yaml file, reads layers, testcases and executes each
19 testcase
20 """
21
22 import subprocess
23 from pathlib import Path
24 import sys
25 import traceback
26 import click
27 import yaml
28
29 class BluvalError(Exception):
30     """Base class for exceptions in this module."""
31     pass
32
33
34 class ShowStopperError(Exception):
35     """Showstopper test case failed"""
36     pass
37
38
39 def run_testcase(testcase):
40     """Runs a single testcase
41     """
42     name = testcase.get('name')
43     skip = testcase.get('skip', "False")
44     if skip.lower() == "true":
45         # skip is mentioned and true.
46         print('Skipping {}'.format(name))
47         return
48     show_stopper = testcase.get('show_stopper', "False")
49     what = testcase.get('what')
50     mypath = Path(__file__).absolute()
51     results_path = mypath.parents[2].joinpath("results/"+testcase.get('layer')+"/"+what)
52     test_path = mypath.parents[1].joinpath("tests/"+testcase.get('layer')+"/"+what)
53
54     # add to the variables file the path to where to sotre the logs
55     variables_file = mypath.parents[1].joinpath("tests/variables.yaml")
56     variables_dict = yaml.safe_load(variables_file.open())
57     variables_dict['log_path'] = str(results_path)
58     variables_file.write_text(str(variables_dict))
59
60     # run the test
61     args = ["robot", "-V", str(variables_file), "-d", str(results_path), str(test_path)]
62
63     print('Executing testcase {}'.format(name))
64     print('show_stopper {}'.format(show_stopper))
65     print('Invoking {}'.format(args))
66     try:
67         status = subprocess.call(args, shell=False)
68         if status != 0 and show_stopper.lower() == "true":
69             raise ShowStopperError(name)
70     except OSError:
71         #print('Error while executing {}'.format(args))
72         raise BluvalError(OSError)
73
74 def validate_layer(blueprint, layer):
75     """validates a layer by validating all testcases under that layer
76     """
77     print('## Layer {}'.format(layer))
78     for testcase in blueprint[layer]:
79         testcase['layer'] = layer
80         run_testcase(testcase)
81
82
83 def validate_blueprint(yaml_loc, layer):
84     """Parse yaml file and validates given layer. If no layer given all layers
85     validated
86     """
87     with open(str(yaml_loc)) as yaml_file:
88         yamldoc = yaml.safe_load(yaml_file)
89     blueprint = yamldoc['blueprint']
90     if layer is None or layer == "all":
91         for each_layer in blueprint['layers']:
92             validate_layer(blueprint, each_layer)
93     else:
94         validate_layer(blueprint, layer)
95
96
97 def invoke_docker(bluprint, layer):
98     """Start docker container for given layer
99     """
100     cmd = ("docker run"
101            " -v $HOME/.ssh:/root/.ssh"
102            " -v $HOME/.kube/config:/root/.kube/config"
103            " -v $VALIDATION_HOME/tests/variables.yaml:"
104            "/opt/akraino/validation/tests/variables.yaml"
105            " -v $AKRAINO_HOME/results:/opt/akraino/results"
106            " akraino/validation:{0}-latest"
107            " bin/sh -c"
108            " 'cd /opt/akraino/validation "
109            "&& python bluval/bluval.py -l {0} {1}'").format(layer, bluprint)
110     args = [cmd]
111     try:
112         print('Invoking {}'.format(args))
113         subprocess.call(args, shell=True)
114     except OSError:
115         #print('Error while executing {}'.format(args))
116         raise BluvalError(OSError)
117
118
119 def invoke_dockers(yaml_loc, layer, blueprint_name):
120     """Parses yaml file and starts docker container for one/all layers
121     """
122     with open(str(yaml_loc)) as yaml_file:
123         yamldoc = yaml.safe_load(yaml_file)
124     blueprint = yamldoc['blueprint']
125     if layer is None or layer == "all":
126         for each_layer in blueprint['layers']:
127             invoke_docker(blueprint_name, each_layer)
128     else:
129         invoke_docker(blueprint_name, layer)
130
131
132 @click.command()
133 @click.argument('blueprint')
134 @click.option('--layer', '-l')
135 @click.option('--delegate', '-d', is_flag=True)
136 def main(blueprint, layer, delegate):
137     """Takes blueprint name and optional layer. Validates inputs and derives
138     yaml location from blueprint name. Invokes validate on blue print.
139     """
140     mypath = Path(__file__).absolute()
141     yaml_loc = mypath.parents[0].joinpath('bluval-{}.yaml'.format(blueprint))
142     if layer is not None:
143         layer = layer.lower()
144     try:
145         if delegate is not None:
146             invoke_dockers(yaml_loc, layer, blueprint)
147         else:
148             validate_blueprint(yaml_loc, layer)
149     except ShowStopperError as err:
150         print('ShowStopperError:', err)
151     except BluvalError as err:
152         print('Unexpected BluvalError', err)
153         raise
154     except:
155         print("Exception in user code:")
156         print("-"*60)
157         traceback.print_exc(file=sys.stdout)
158         print("-"*60)
159         raise
160
161 if __name__ == "__main__":
162     # pylint: disable=no-value-for-parameter
163     main()