Merge "edit activity workflow plan for NS INIT"
[vfc/nfvo/lcm.git] / lcm / pub / utils / toscaparser / basemodel.py
1 # Copyright 2017 ZTE Corporation.
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 import copy
16 import ftplib
17 import json
18 import logging
19 import os
20 import re
21 import shutil
22 import urllib
23
24 import paramiko
25 from toscaparser.functions import GetInput
26 from toscaparser.tosca_template import ToscaTemplate
27
28 from lcm.pub.utils.toscaparser.dataentityext import DataEntityExt
29
30 logger = logging.getLogger(__name__)
31
32
33 class BaseInfoModel(object):
34
35     def buildToscaTemplate(self, path, params):
36         file_name = None
37         try:
38             file_name = self._check_download_file(path)
39             valid_params = self._validate_input_params(file_name, params)
40             return self._create_tosca_template(file_name, valid_params)
41         finally:
42             if file_name is not None and file_name != path and os.path.exists(file_name):
43                 try:
44                     os.remove(file_name)
45                 except Exception as e:
46                     logger.error("Failed to parse package, error: %s", e.message)
47
48     def _validate_input_params(self, path, params):
49         valid_params = {}
50         if params and len(params) > 0:
51             tmp = self._create_tosca_template(path, None)
52             for key, value in params.items():
53                 if hasattr(tmp, 'inputs') and len(tmp.inputs) > 0:
54                     for input_def in tmp.inputs:
55                         if (input_def.name == key):
56                             valid_params[key] = DataEntityExt.validate_datatype(input_def.type, value)
57
58         return valid_params
59
60     def _create_tosca_template(self, file_name, valid_params):
61         tosca_tpl = None
62         try:
63             tosca_tpl = ToscaTemplate(file_name, valid_params)
64             print "-----------------------------"
65             print '\n'.join(['%s:%s' % item for item in tosca_tpl.__dict__.items()])
66             print "-----------------------------"
67             return tosca_tpl
68         finally:
69             if tosca_tpl is not None and hasattr(tosca_tpl, "temp_dir") and os.path.exists(tosca_tpl.temp_dir):
70                 try:
71                     shutil.rmtree(tosca_tpl.temp_dir)
72                 except Exception as e:
73                     logger.error("Failed to create tosca template, error: %s", e.message)
74
75     def _check_download_file(self, path):
76         if (path.startswith("ftp") or path.startswith("sftp")):
77             return self.downloadFileFromFtpServer(path)
78         elif (path.startswith("http")):
79             return self.download_file_from_httpserver(path)
80         return path
81
82     def download_file_from_httpserver(self, path):
83         path = path.encode("utf-8")
84         tmps = str.split(path, '/')
85         localFileName = tmps[len(tmps) - 1]
86         urllib.urlretrieve(path, localFileName)
87         return localFileName
88
89     def downloadFileFromFtpServer(self, path):
90         path = path.encode("utf-8")
91         tmp = str.split(path, '://')
92         protocol = tmp[0]
93         tmp = str.split(tmp[1], ':')
94         if len(tmp) == 2:
95             userName = tmp[0]
96             tmp = str.split(tmp[1], '@')
97             userPwd = tmp[0]
98             index = tmp[1].index('/')
99             hostIp = tmp[1][0:index]
100             remoteFileName = tmp[1][index:len(tmp[1])]
101             if protocol.lower() == 'ftp':
102                 hostPort = 21
103             else:
104                 hostPort = 22
105
106         if len(tmp) == 3:
107             userName = tmp[0]
108             userPwd = str.split(tmp[1], '@')[0]
109             hostIp = str.split(tmp[1], '@')[1]
110             index = tmp[2].index('/')
111             hostPort = tmp[2][0:index]
112             remoteFileName = tmp[2][index:len(tmp[2])]
113
114         localFileName = str.split(remoteFileName, '/')
115         localFileName = localFileName[len(localFileName) - 1]
116
117         if protocol.lower() == 'sftp':
118             self.sftp_get(userName, userPwd, hostIp, hostPort, remoteFileName, localFileName)
119         else:
120             self.ftp_get(userName, userPwd, hostIp, hostPort, remoteFileName, localFileName)
121         return localFileName
122
123     def sftp_get(self, userName, userPwd, hostIp, hostPort, remoteFileName, localFileName):
124         # return
125         t = None
126         try:
127             t = paramiko.Transport(hostIp, int(hostPort))
128             t.connect(username=userName, password=userPwd)
129             sftp = paramiko.SFTPClient.from_transport(t)
130             sftp.get(remoteFileName, localFileName)
131         finally:
132             if t is not None:
133                 t.close()
134
135     def ftp_get(self, userName, userPwd, hostIp, hostPort, remoteFileName, localFileName):
136         f = None
137         try:
138             ftp = ftplib.FTP()
139             ftp.connect(hostIp, hostPort)
140             ftp.login(userName, userPwd)
141             f = open(localFileName, 'wb')
142             ftp.retrbinary('RETR ' + remoteFileName, f.write, 1024)
143             f.close()
144         finally:
145             if f is not None:
146                 f.close()
147
148     def buidMetadata(self, tosca):
149         if 'metadata' in tosca.tpl:
150             self.metadata = copy.deepcopy(tosca.tpl['metadata'])
151
152     def buildProperties(self, nodeTemplate, parsed_params):
153         properties = {}
154         isMappingParams = parsed_params and len(parsed_params) > 0
155         for k, item in nodeTemplate.get_properties().items():
156             properties[k] = item.value
157             if isinstance(item.value, GetInput):
158                 if item.value.result() and isMappingParams:
159                     properties[k] = DataEntityExt.validate_datatype(item.type, item.value.result())
160                 else:
161                     tmp = {}
162                     tmp[item.value.name] = item.value.input_name
163                     properties[k] = tmp
164         if 'attributes' in nodeTemplate.entity_tpl:
165             for k, item in nodeTemplate.entity_tpl['attributes'].items():
166                 properties[k] = str(item)
167         return properties
168
169     def verify_properties(self, props, inputs, parsed_params):
170         ret_props = {}
171         if (props and len(props) > 0):
172             for key, value in props.items():
173                 ret_props[key] = self._verify_value(value, inputs, parsed_params)
174                 #                 if isinstance(value, str):
175                 #                     ret_props[key] = self._verify_string(inputs, parsed_params, value);
176                 #                     continue
177                 #                 if isinstance(value, list):
178                 #                     ret_props[key] = map(lambda x: self._verify_dict(inputs, parsed_params, x), value)
179                 #                     continue
180                 #                 if isinstance(value, dict):
181                 #                     ret_props[key] = self._verify_map(inputs, parsed_params, value)
182                 #                     continue
183                 #                 ret_props[key] = value
184         return ret_props
185
186     def build_requirements(self, node_template):
187         rets = []
188         for req in node_template.requirements:
189             for req_name, req_value in req.items():
190                 if (isinstance(req_value, dict)):
191                     if ('node' in req_value and req_value['node'] not in node_template.templates):
192                         continue  # No target requirement for aria parser, not add to result.
193                 rets.append({req_name: req_value})
194         return rets
195
196     def buildCapabilities(self, nodeTemplate, inputs, ret):
197         capabilities = json.dumps(nodeTemplate.entity_tpl.get('capabilities', None))
198         match = re.findall(r'\{"get_input":\s*"([\w|\-]+)"\}', capabilities)
199         for m in match:
200             aa = [input_def for input_def in inputs if m == input_def.name][0]
201             capabilities = re.sub(r'\{"get_input":\s*"([\w|\-]+)"\}', json.dumps(aa.default), capabilities, 1)
202         if capabilities != 'null':
203             ret['capabilities'] = json.loads(capabilities)
204
205     def buildArtifacts(self, nodeTemplate, inputs, ret):
206         artifacts = json.dumps(nodeTemplate.entity_tpl.get('artifacts', None))
207         match = re.findall(r'\{"get_input":\s*"([\w|\-]+)"\}', artifacts)
208         for m in match:
209             aa = [input_def for input_def in inputs if m == input_def.name][0]
210             artifacts = re.sub(r'\{"get_input":\s*"([\w|\-]+)"\}', json.dumps(aa.default), artifacts, 1)
211         if artifacts != 'null':
212             ret['artifacts'] = json.loads(artifacts)
213
214     def build_interfaces(self, node_template):
215         if 'interfaces' in node_template.entity_tpl:
216             return node_template.entity_tpl['interfaces']
217         return None
218
219     def isVnf(self, node):
220         return node['nodeType'].upper().find('.VNF.') >= 0 or node['nodeType'].upper().endswith('.VNF')
221
222     def isPnf(self, node):
223         return node['nodeType'].upper().find('.PNF.') >= 0 or node['nodeType'].upper().endswith('.PNF')
224
225     def isCp(self, node):
226         return node['nodeType'].upper().find('.CP.') >= 0 or node['nodeType'].upper().endswith('.CP')
227
228     def isVl(self, node):
229         isvl = node['nodeType'].upper().find('.VIRTUALLINK.') >= 0 or node['nodeType'].upper().find('.VL.') >= 0
230         isvl = isvl or node['nodeType'].upper().endswith('.VIRTUALLINK') or node['nodeType'].upper().endswith('.VL')
231         return isvl
232
233     def isService(self, node):
234         return node['nodeType'].upper().find('.SERVICE.') >= 0 or node['nodeType'].upper().endswith('.SERVICE')
235
236     def get_requirement_node_name(self, req_value):
237         return self.get_prop_from_obj(req_value, 'node')
238
239     def get_prop_from_obj(self, obj, prop):
240         if isinstance(obj, str):
241             return obj
242         if (isinstance(obj, dict) and prop in obj):
243             return obj[prop]
244         return None
245
246     def getNodeDependencys(self, node):
247         return self.getRequirementByName(node, 'dependency')
248
249     def getVirtualLinks(self, node):
250         return self.getRequirementByName(node, 'virtualLink')
251
252     def getVirtualbindings(self, node):
253         return self.getRequirementByName(node, 'virtualbinding')
254
255     def getRequirementByName(self, node, requirementName):
256         requirements = []
257         if 'requirements' in node:
258             for item in node['requirements']:
259                 for key, value in item.items():
260                     if key == requirementName:
261                         requirements.append(value)
262         return requirements
263
264     def get_networks(self, node):
265         rets = []
266         if 'requirements' in node:
267             for item in node['requirements']:
268                 for key, value in item.items():
269                     if key.upper().find('VIRTUALLINK') >= 0:
270                         rets.append({"key_name": key, "vl_id": self.get_requirement_node_name(value)})
271         return rets
272
273     def _verify_value(self, value, inputs, parsed_params):
274         if isinstance(value, str):
275             return self._verify_string(inputs, parsed_params, value)
276         if isinstance(value, list) or isinstance(value, dict):
277             return self._verify_object(value, inputs, parsed_params)
278         return value
279
280     def _verify_object(self, value, inputs, parsed_params):
281         s = self._verify_string(inputs, parsed_params, json.dumps(value))
282         return json.loads(s)
283
284     def _get_input_name(self, getInput):
285         input_name = getInput.split(':')[1]
286         input_name = input_name.strip()
287         return input_name.replace('"', '').replace('}', '')
288
289     def _verify_string(self, inputs, parsed_params, value):
290         getInputs = re.findall(r'{"get_input": "[a-zA-Z_0-9]+"}', value)
291         for getInput in getInputs:
292             input_name = self._get_input_name(getInput)
293             if parsed_params and input_name in parsed_params:
294                 value = value.replace(getInput, json.dumps(parsed_params[input_name]))
295             else:
296                 for input_def in inputs:
297                     if input_def.default and input_name == input_def.name:
298                         value = value.replace(getInput, json.dumps(input_def.default))
299         return value
300
301     def get_node_vl_id(self, node):
302         vl_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualLinks(node))
303         if len(vl_ids) > 0:
304             return vl_ids[0]
305         return ""
306
307     def get_node_by_name(self, node_templates, name):
308         for node in node_templates:
309             if node['name'] == name:
310                 return node
311         return None
312
313     def get_all_nested_ns(self, nodes):
314         nss = []
315         for node in nodes:
316             if self.is_nested_ns(node):
317                 ns = {}
318                 ns['ns_id'] = node['name']
319                 ns['description'] = node['description']
320                 ns['properties'] = node['properties']
321                 ns['networks'] = self.get_networks(node)
322
323                 nss.append(ns)
324         return nss
325
326     def is_nested_ns(self, node):
327         return node['nodeType'].upper().find('.NS.') >= 0 or node['nodeType'].upper().endswith('.NS')
328
329     def isVdu(self, node):
330         return node['nodeType'].upper().find('.VDU.') >= 0 or node['nodeType'].upper().endswith('.VDU')
331
332     def getCapabilityByName(self, node, capabilityName):
333         if 'capabilities' in node and capabilityName in node['capabilities']:
334             return node['capabilities'][capabilityName]
335         return None
336
337     def get_node_vdu_id(self, node):
338         vdu_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualbindings(node))
339         if len(vdu_ids) > 0:
340             return vdu_ids[0]
341         return ""