Bug 806, System test exception handled!
[osm/devops.git] / descriptor-packages / tools / validate_descriptor.py
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
3
4 ##
5 # All Rights Reserved.
6 #
7 # Licensed under the Apache License, Version 2.0 (the "License"); you may
8 # not use this file except in compliance with the License. You may obtain
9 # a copy of the License at
10 #
11 # http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 # License for the specific language governing permissions and limitations
17 # under the License.
18 #
19 ##
20 from __future__ import print_function
21 import json
22 import yaml
23 import sys
24 import getopt
25 import os
26
27 """
28 Tests the format of OSM VNFD and NSD descriptors
29 """
30 __author__ = "Alfonso Tierno, Guillermo Calvino"
31 __date__ = "2018-04-16"
32 __version__ = "0.0.1"
33 version_date = "Apr 2018"
34
35
36 class ArgumentParserError(Exception):
37 pass
38
39
40 def usage():
41 print("Usage: {} [options] FILE".format(sys.argv[0]))
42 print(" Validates vnfd, nsd and nst descriptors format")
43 print(" FILE: a yaml or json vnfd-catalog, nsd-catalog or nst descriptor")
44 print(" OPTIONS:")
45 print(" -v|--version: prints current version")
46 print(" -h|--help: shows this help")
47 print(" -i|--input FILE: (same as param FILE) descriptor file to be upgraded")
48 return
49
50
51 def remove_prefix(desc, prefix):
52 """
53 Recursively removes prefix from keys
54 :param desc: dictionary or list to change
55 :param prefix: prefix to remove. Must
56 :return: None, param desc is changed
57 """
58 prefix_len = len(prefix)
59 if isinstance(desc, dict):
60 prefixed_list=[]
61 for k,v in desc.items():
62 if isinstance(v, (list, tuple, dict)):
63 remove_prefix(v, prefix)
64 if isinstance(k, str) and k.startswith(prefix) and k != prefix:
65 prefixed_list.append(k)
66 for k in prefixed_list:
67 desc[k[prefix_len:]] = desc.pop(k)
68 elif isinstance(desc, (list, tuple)):
69 for i in desc:
70 if isinstance(desc, (list, tuple, dict)):
71 remove_prefix(i, prefix)
72
73
74 # Mrityunjay Yadav: Function to verify charm included in VNF Package
75 def validate_charm(charm, desc_file):
76 """
77 Verify charm included in VNF Package and raised error if invalid
78 :param charm: vnf-configuration/vdu-configuration
79 :param desc_file: descriptor file
80 :return: None
81 """
82 check_list = ['layer.yaml', 'metadata.yaml', 'actions.yaml', 'actions', 'hooks']
83 charm_name = charm['juju']['charm']
84 charm_dir = os.path.join(os.path.abspath(os.path.dirname(desc_file)), 'charms', charm_name)
85
86 config_primitive = charm.get('config-primitive', [])
87 initial_config_primitive = charm.get('initial-config-primitive', [])
88
89 if charm.get('metrics'):
90 check_list.append('metrics.yaml')
91
92 if os.path.exists(charm_dir):
93 if not all(item in os.listdir(charm_dir) for item in check_list):
94 raise KeyError("Invalid charm {}".format(charm_name))
95 else:
96 raise KeyError("Provided charm:{} does not exist in descriptor.".format(charm_name))
97
98
99 if __name__ == "__main__":
100 error_position = []
101 format_output_yaml = True
102 input_file_name = None
103 test_file = None
104 file_name = None
105 try:
106 # load parameters and configuration
107 opts, args = getopt.getopt(sys.argv[1:], "hvi:o:", ["input=", "help", "version",])
108
109 for o, a in opts:
110 if o in ("-v", "--version"):
111 print ("test descriptor version THREE " + __version__ + ' ' + version_date)
112 sys.exit()
113 elif o in ("-h", "--help"):
114 usage()
115 sys.exit()
116 elif o in ("-i", "--input"):
117 input_file_name = a
118 else:
119 assert False, "Unhandled option"
120 if not input_file_name:
121 if not args:
122 raise ArgumentParserError("missing DESCRIPTOR_FILE parameter. Type --help for more info")
123 input_file_name = args[0]
124
125 # Open files
126 file_name = input_file_name
127 with open(file_name, 'r') as f:
128 descriptor_str = f.read()
129 file_name = None
130
131 if input_file_name.endswith('.yaml') or input_file_name.endswith('.yml') or not \
132 (input_file_name.endswith('.json') or '\t' in descriptor_str):
133 data = yaml.load(descriptor_str)
134 else: # json
135 data = json.loads(descriptor_str)
136 format_output_yaml = False
137
138 import osm_im.vnfd as vnfd_catalog
139 import osm_im.nsd as nsd_catalog
140 import osm_im.nst as nst_catalog
141 from pyangbind.lib.serialise import pybindJSONDecoder
142
143 if "vnfd:vnfd-catalog" in data or "vnfd-catalog" in data:
144 descriptor = "VNF"
145 # Check if mgmt-interface is defined:
146 remove_prefix(data, "vnfd:")
147 vnfd_descriptor = data["vnfd-catalog"]
148 vnfd_list = vnfd_descriptor["vnfd"]
149 mgmt_iface = False
150 for vnfd in vnfd_list:
151 vdu_list = vnfd["vdu"]
152 for vdu in vdu_list:
153 interface_list = []
154 external_interface_list = vdu.pop("external-interface", ())
155 for external_interface in external_interface_list:
156 if external_interface.get("virtual-interface", {}).get("type") == "OM-MGMT":
157 raise KeyError(
158 "Wrong 'Virtual-interface type': Deprecated 'OM-MGMT' value. Please, use 'PARAVIRT' instead")
159 interface_list = vdu.get("interface", ())
160 for interface in interface_list:
161 if interface.get("virtual-interface", {}).get("type") == "OM-MGMT":
162 raise KeyError(
163 "Wrong 'Virtual-interface type': Deprecated 'OM-MGMT' value. Please, use 'PARAVIRT' instead")
164 # Mrityunjay yadav: Verify charm if included in vdu
165 if vdu.get("vdu-configuration", False):
166 validate_charm(vdu["vdu-configuration"], input_file_name)
167 if vnfd.get("mgmt-interface"):
168 mgmt_iface = True
169 if vnfd["mgmt-interface"].get("vdu-id"):
170 raise KeyError("'mgmt-iface': Deprecated 'vdu-id' field. Please, use 'cp' field instead")
171 # Mrityunjay yadav: Verify charm if included in vnf
172 if vnfd.get("vnf-configuration", False):
173 validate_charm(vnfd["vnf-configuration"], input_file_name)
174
175 if not mgmt_iface:
176 raise KeyError("'mgmt-interface' is a mandatory field and it is not defined")
177 myvnfd = vnfd_catalog.vnfd()
178 pybindJSONDecoder.load_ietf_json(data, None, None, obj=myvnfd)
179 elif "nsd:nsd-catalog" in data or "nsd-catalog" in data:
180 descriptor = "NS"
181 mynsd = nsd_catalog.nsd()
182 pybindJSONDecoder.load_ietf_json(data, None, None, obj=mynsd)
183 elif "nst:nst" in data or "nst" in data:
184 descriptor = "NST"
185 mynst = nst_catalog.nst()
186 pybindJSONDecoder.load_ietf_json(data, None, None, obj=mynst)
187 else:
188 descriptor = None
189 raise KeyError("This is not neither nsd-catalog nor vnfd-catalog descriptor")
190 exit(0)
191
192 except yaml.YAMLError as exc:
193 error_pos = ""
194 if hasattr(exc, 'problem_mark'):
195 mark = exc.problem_mark
196 error_pos = "at line:%s column:%s" % (mark.line + 1, mark.column + 1)
197 print("Error loading file '{}'. yaml format error {}".format(input_file_name, error_pos), file=sys.stderr)
198 except ArgumentParserError as e:
199 print(str(e), file=sys.stderr)
200 except IOError as e:
201 print("Error loading file '{}': {}".format(file_name, e), file=sys.stderr)
202 except ImportError as e:
203 print ("Package python-osm-im not installed: {}".format(e), file=sys.stderr)
204 except Exception as e:
205 if file_name:
206 print("Error loading file '{}': {}".format(file_name, str(e)), file=sys.stderr)
207 else:
208 if descriptor:
209 print("Error. Invalid {} descriptor format in '{}': {}".format(descriptor, input_file_name, str(e)), file=sys.stderr)
210 else:
211 print("Error. Invalid descriptor format in '{}': {}".format(input_file_name, str(e)), file=sys.stderr)
212 exit(1)