FORGE: Added including script
[myslice.git] / forge / script / request.py
1 #!/usr/bin/python
2
3 import xmlrpclib
4 import Auth
5 import sys
6 import paramiko
7 import subprocess
8 import time
9 import geopy
10 import geopy.distance
11 import argparse
12 import os
13 import socket
14 import urllib2
15 import csv
16 from openvswitch import TransformXml
17 from exceptionDefinition import FailToConnect, NodeConstraintError
18 from scp import SCPClient
19
20
21 yumOpt =  "sudo -S yum -y --nogpgcheck "
22
23 class TransformRawXml:
24         def __init__(self, confFile = "", linkFile = "", subnet = "", prefix = "", sliceName = "", nbEnv = 1, mainKeyPriv = None, mainKeyPub = None, sliceUrl = 'http://onelab.eu', sliceDescription = 'Slice used for educationnal purpose', country = False):
25                 # Definition of the api used for the actions on planetlab
26                 plc_host='www.planet-lab.eu'
27                 api_url='https://%s:443/PLCAPI/'%plc_host
28                 self.plc_api=xmlrpclib.ServerProxy(api_url, allow_none=True)
29                 # Prefix used for the slice name
30                 slice_pref='upmc_'
31
32                 self.sliceUrl = sliceUrl
33                 self.sliceDescription = sliceDescription
34
35                 myOpsPLC = urllib2.urlopen('http://monitor.planet-lab.org/monitor/query?hostname=on&tg_format=plain&object=nodes&nodehistory_hostname=&observed_status=on&rpmvalue=')
36                 self.myOpsPLCCsv = list(csv.reader(myOpsPLC))
37                 myOpsPLE = urllib2.urlopen('http://monitor.planet-lab.eu/monitor/query?hostname=on&tg_format=plain&object=nodes&nodehistory_hostname=&observed_status=on&rpmvalue=')
38                 self.myOpsPLECsv = list(csv.reader(myOpsPLE))
39
40                 self.subnet = subnet
41                 if prefix != "":
42                         self.xmlFileConf = prefix+'Conf.xml'
43                         self.xmlFileLink = prefix+'Link.xml'
44                 else:
45                         self.xmlFileConf = confFile
46                         self.xmlFileLink = linkFile
47                 if 'upmc_' not in sliceName:
48                         self.slice_name = slice_pref+sliceName
49                 else:
50                         self.slice_name = sliceName
51
52                 self.nbEnv = int(nbEnv)
53                 
54                 self.country = country
55
56                 # Attribute for ssh key
57                 self.mainKeyPriv = mainKeyPriv
58                 self.mainKeyPub = mainKeyPub
59                 self.envKeyPriv = []
60                 self.envKeyPub = []
61
62                 # Attribute that will contain the list of environment
63                 self.envList = []
64
65                 self.envConfFile = []
66                 self.envLinkFile = []
67                 
68         # Delete the slice
69         def deleteSlice(self):
70                 errorCode = self.plc_api.DeleteSlice(Auth.auth, self.slice_name)
71                 if errorCode != 1:
72                         print "An error occured unable to delete the slice"
73                         print errorCode
74                         print self.slice_name
75
76         # Add 15 days to the expiration date
77         def renewSlice(self, day = 15):
78                 print self.slice_name
79                 expiration = self.plc_api.GetSlices(Auth.auth, self.slice_name, ['expires'])[0]['expires']
80                 print expiration
81                 newExpiration = expiration + (3600*24*day)
82                 self.plc_api.UpdateSlice(Auth.auth, self.slice_name, {'expires': newExpiration})
83                 expiration = self.plc_api.GetSlices(Auth.auth, self.slice_name, ['expires'])[0]['expires']
84                 print expiration
85
86         # Generate a ssh key pair
87         def generateKeyPair(self,pref = "", bit = 1024):
88                 key = paramiko.RSAKey.generate(bit)
89                 # Save the private key file
90                 keyFilePriv = pref+"id_rsa.priv"
91                 key.write_private_key_file(keyFilePriv)
92                 # Save the public key file
93                 keyFilePub = pref+"id_rsa.pub"
94                 openedFile = open(keyFilePub, 'w')
95                 openedFile.write("%s %s \n" % (key.get_name(), key.get_base64()))
96                 return keyFilePriv, keyFilePub
97
98         # press any key to continue function
99         def anykey(self, prompt="Press enter to continue...", failChars=""):
100                 char = raw_input(prompt)
101                 return (char not in failChars)
102
103         def checkSSH(self, node):
104                 countFailSSH = 9
105                 ssh = paramiko.SSHClient()
106                 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
107                 connected = False
108                 error = None
109                 i = 0
110                 while(connected == False):
111                         print "\n"+self.mainKeyPriv+" -> "+self.slice_name+"@"+node['hostname']
112                         try:
113                                 ssh.connect(node['hostname'], username = self.slice_name, key_filename = self.mainKeyPriv)
114                                 connected = True
115                         except paramiko.PasswordRequiredException, why:
116                                 print "Password required exception"
117                                 print "Error: ", why
118
119                         except paramiko.SSHException, why:
120                                 print "An SSH exception occured"
121                                 print "Error: ", why
122
123                         except socket.error, why:
124                                 print "A soccket error occured"
125                                 print why
126                                 failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
127                                 print 'FailingNode node_id -> '+str(failingNode['node_id'])
128                                 raise FailToConnect(failingNode['node_id'], failingNode['hostname'])
129
130                         except Exception, why:
131                                 print "An error occured for host "+str(node['hostname'])+" on slice "+str(self.slice_name)
132                                 print type(why)
133                                 print why
134                                 sys.exit(2)
135                                 if str(why)!=error:
136                                         print why
137                                         error=str(why)
138
139                         if i > countFailSSH and connected==False:
140                                 print error
141                                 failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
142                                 raise Exception(failingNode['hostname'])
143                         try:
144                                 if connected == False:
145                                         print "Now waiting 5 minutes for an update of the node"
146                                         time.sleep(300)
147                         except KeyboardInterrupt, why:
148                                 print "You interrupt the wait"
149                         i += 1
150                 print "I make",i,"iteration before getting connection"
151                 copied = False
152                 i=0
153                 while(copied == False):
154                         try:
155                                 SCPClient(ssh.get_transport()).put('configService/fedora.repo')
156                                 SCPClient(ssh.get_transport()).put('configService/fedora-updates.repo')
157                                 SCPClient(ssh.get_transport()).put('configService/fedora-updates-testing.repo')
158                                 self.execute("sudo -S mv *.repo /etc/yum.repos.d/", ssh)
159                                 self.execute("sudo -S chown root:root /etc/yum.repos.d/*.repo", ssh)
160                                 copied = True
161                         except Exception, why:
162                                 print "An error occured while configuring yum"
163                                 print "Error: ",why
164                                 if i > 4 and copied == False:
165                                         failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
166                                         raise Exception(failingNode['hostname'])
167                         if copied == False:
168                                 time.sleep(60)
169                         i+=1
170
171                 return ssh
172
173
174         # Install an alternate ssh server
175         def installSSH(self, userKeyFile, node):
176                 ssh = self.checkSSH(node)
177                 returnCode = -1
178                 i = 0
179                 while(returnCode != 0):
180                         if i > 3:
181                                 failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
182                                 raise Exception(failingNode['hostname'])
183                         returnCode = self.execute(yumOpt+"install openssh-server", ssh, display= True)
184                         print "Return Code is ->", returnCode
185                         time.sleep(5)
186                         i += 1
187                 self.execute("mkdir .ssh", ssh, display= True)
188                 if node['type'] == 'private':
189                         SCPClient(ssh.get_transport()).put(userKeyFile, ".ssh/id_rsa.pub")
190                         SCPClient(ssh.get_transport()).put("configService/sshd_config", "./")
191                 elif node['type'] == 'public':
192                         SCPClient(ssh.get_transport()).put(userKeyFile, ".ssh/id_rsa.pub.tmp")
193                         SCPClient(ssh.get_transport()).put("configService/sshd_config", "./")
194                         self.execute("cat .ssh/id_rsa.pub.tmp >> .ssh/id_rsa.pub", ssh)
195                 self.execute("sudo -S mv ./sshd_config /etc/ssh/", ssh)
196                 self.execute("sudo -S sh -c \"echo \\\"Port 2222\\\" >> /etc/ssh/sshd_config\"", ssh)
197                 port = 2222
198                 returnCode = -1
199                 while (returnCode != 0):
200                         time.sleep(2)
201                         returnCode = self.execute("sudo -S service sshd restart", ssh, display = True)
202                         if returnCode != 0:
203                                 self.execute("sudo -S sed -i -e \"s/Port "+str(port)+"/Port "+str(port+1)+"/g\" /etc/ssh/sshd_config", ssh)
204                                 port +=1
205                 return port
206
207         # Execute a command on a remote machine
208         def execute(self, command, ssh, display= False, retour= False):
209                 print "# "+command
210                 stdin, stdout, stderr = ssh.exec_command(command)
211                 stdin.close()
212                 while not stdout.channel.exit_status_ready():
213                         time.sleep(2)
214         
215                 err = stderr.read()
216                 if err != None:
217                         splitted = err.splitlines()
218                         if len(splitted) > 0:
219                                 print "Error in execution"
220                                 for line in splitted:
221                                         print "> "+line
222                 if display:
223                         for line in stdout.read().splitlines():
224                                 print "> "+line
225                 elif retour:
226                         return stdout.read()
227                 return stdout.channel.recv_exit_status()
228
229         # Create the xml file corresponding to each environment
230         def createXmlFile(self, hostList, idEnv):
231                 from xml.dom.minidom import parse
232                 conf = parse(self.xmlFileConf)
233                 link = parse(self.xmlFileLink)
234                 sliceNames = link.getElementsByTagName('slice')
235                 for value in sliceNames:
236                         value.firstChild.nodeValue = self.slice_name
237                 sliceNames = conf.getElementsByTagName('slice_name')
238                 for value in sliceNames:
239                         value.firstChild.nodeValue = self.slice_name
240                 urlList = conf.getElementsByTagName('url')
241                 if len(hostList) < len(urlList):
242                         print "hostlist -> "+str(len(hostList))
243                         print "urllist -> "+str(len(urlList))
244                         for host in hostList:
245                                 print host
246                 for i in range(len(urlList)):
247                         urlList[i].firstChild.nodeValue = hostList[i]
248                 subnetIP, subnetMask = self.subnet.split('/')
249                 subnetMask = int(subnetMask)
250                 subnetIP = subnetIP.split('.')
251                 ipList = conf.getElementsByTagName('ip')
252                 for ipWithMask in ipList:
253                         ip, mask = str(ipWithMask.firstChild.nodeValue).split('/')
254                         ip = ip.split('.')
255                         mask = int(mask)
256                         newIP = ''
257                         if subnetMask > mask:
258                                 sys.exit(2)
259                                 # TODO define SubnetException
260                                 pass
261                                 #raise SubnetException()
262                         else:
263                                 subnetRange = subnetMask/8
264                                 for i in range(len(ip)):
265                                         if i < subnetRange:
266                                                 newIP+=subnetIP[i]
267                                         else:
268                                                 if ip[i] == 'N':
269                                                         newIP+=str(idEnv)
270                                                 else:
271                                                         newIP+=ip[i]
272                                         if i < 3:
273                                                 newIP+='.'
274                                 newIP+='/'+str(mask)
275                         ipWithMask.firstChild.nodeValue = newIP
276                 confFileName = 'requ'+str(idEnv)+'Conf.xml'
277                 confFile = open(confFileName, 'w')
278                 conf.writexml(confFile)
279                 confFile.close()
280                 self.envConfFile.append(confFileName)
281                 linkFileName = 'requ'+str(idEnv)+'Link.xml'
282                 linkFile = open(linkFileName, 'w')
283                 link.writexml(linkFile)
284                 linkFile.close()
285                 self.envLinkFile.append(linkFileName)
286
287         def getNodeAvailable(self, site, nodeUsed = []):
288                 nodes = self.plc_api.GetNodes(Auth.auth, site['node_ids'])
289                 if site['peer_id'] == 1:
290                         myOpsCsv = self.myOpsPLCCsv
291                 else:
292                         myOpsCsv = self.myOpsPLECsv
293                 for node in nodes:
294                         for row in myOpsCsv:
295                                 if node['hostname'] == row[0]:
296                                         node['myOpsStatus'] = row[1]
297                                         break
298                 nodeAvailable = []
299                 for node in nodes:
300                         if (node['myOpsStatus'] == 'BOOT' and node['boot_state'] == 'boot' and node['run_level'] == 'boot' and node['node_id'] not in nodeUsed):
301                                 nodeAvailable.append(node)
302                 return nodeAvailable
303
304         def getEnvironmentWithCountryConstraint(self, countryListPrivate, contryListCommon, sites, siteBanned):
305                 print "Now looking for the environment using the country constraint"
306                 sitesTmp = []
307                 for site in sites:
308                         if len(site['address_ids']) == 1:
309                                 sitesTmp.append(site)
310                 sites = sitesTmp
311                 sitesEnv = sitesCommon = []
312         
313                 # Getting the private allowed address
314                 try:
315                         privateAddrAuth = structToArray(self.plc_api.GetAddresses(Auth.auth, {'country': countryListPrivate}, ['address_id']), 'address_id')
316                 except Exception, why:
317                         print why
318                         sys.exit(2)
319
320                 privateAddresses = []
321                 i = 0
322                 for site in sites:
323                         if site['address_ids'][0] in privateAddrAuth and i < self.nbEnv:
324                                 privateAddresses.append(site['address_ids'][0])
325                                 i += 1
326                 # Getting the private Node
327                 print "Getting the private node matching with the requirement"
328                 i = 0
329                 for site in sites:
330                         if len(site['address_ids']) == 1 and site['address_ids'][0] in privateAddrAuth:
331                                 nodeEnv = []
332                                 if i < self.nbEnv:
333                                         j = 0
334                                         nodeSite = self.plc_api.GetNodes(Auth.auth, site['node_ids'], ['hostname', 'run_level', 'node_id', 'boot_state', 'hostname'])
335                                         for node in nodeSite:
336                                                 if i < self.nbEnv:
337                                                         if node['boot_state'] == 'boot':
338                                                                 j+=1
339                                                                 nodeEnv.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname']})
340                                                         if j>=nbNodeByEnv:
341                                                                 i += 1
342                                                                 nodeStructList.append(nodeEnv)
343                                                                 sitesEnv.append(site)
344                                                                 nodeIdList = structToArray(nodeEnv, 'id')
345                                                                 nodeEnv = []
346                                                                 j = 0
347         
348                 print nodeIdList
349                 print "List of site for environment :"
350                 if len(nodeStructList) < self.nbEnv:
351                         print "Error we are not able to find enough environment"
352                         sys.exit(2)
353                 for site in sitesEnv:
354                         print "\t"+str(site)
355         
356                 # Getting the addresse wanted for common node
357                 commonAddresses = []
358                 for country in countryListCommon:
359                         address = self.plc_api.GetAddresses(Auth.auth, {'country': country}, ['address_id'])[0]['address_id']
360                         if address not in privateAddresses:
361                                 commonAddresses.append(address)
362
363                 # Getting the common node
364                 commonNodes = []
365                 for site in sites:
366                         if site['address_ids'][0] in commonAddresses:
367                                 nodeSite = self.plc_api.GetNodes(Auth.auth, site['node_ids'], ['hostname', 'run_level', 'node_id', 'boot_state'])
368                                 for node in nodeSite:
369                                         if node['boot_state'] == 'boot' and node['node_id'] not in nodeIdList:
370                                                 commonNodes.append({'type': 'common','id': node['node_id'], 'hostname': node['hostname']})
371                                                 nodeIdList.append(node['node_id'])
372                                                 break
373         
374                 for env in nodeStructList:
375                         for node in commonNodes:
376                                 env.append(node)
377
378
379                 print "Address list :"
380                 #for addresse in commonAddresses:
381                 #       print "\t"+str(addresse)
382                 print privateAddresses
383                 print commonAddresses
384
385                 return nodeStructList
386
387         def getEnvironmentWithDistanceConstraint(self, constraintList, sitesList, siteBanned, nodeBanned):
388                 print "Now looking for the environment using the distance constraint"
389                 envList = []
390                 nbPrivate = nbCommon = 0
391                 nbInitPrivate = nbInitCommon = 0
392                 # Counting the number of private and common node
393                 # Also counting the number of node located at the same point
394                 for node in constraintList:
395                         if node['type'] == 'private':
396                                 nbPrivate += 1
397                                 if node['max'] == 0 and node['min'] == 0:
398                                         nbInitPrivate += 1
399                         elif node['type'] == 'common' or node['type'] == 'public':
400                                 nbCommon += 1
401                                 if node['max'] == 0 and node['min'] == 0:
402                                         nbInitCommon += 1
403         
404                 print "Common "+str(nbCommon)+" "+str(nbInitCommon), " Private "+str(nbPrivate)+" "+str(nbInitPrivate)
405                 nbReservedEnvironment = 0
406                 siteUsed = []
407                 nodePrivate = []
408                 nodeShared = []
409                 while nbReservedEnvironment < self.nbEnv:
410                         tmpListEnv = []
411                         maxNode = []
412                         for site in sitesList:
413                                 if site['site_id'] not in siteUsed and site['site_id'] not in siteBanned:
414                                         try:
415                                                 nodeAvailable = self.getNodeAvailable(site, nodeBanned)
416                                                 if len(nodeAvailable) > len(maxNode):
417                                                         maxNode = nodeAvailable
418                                                         siteInit = site
419                                         except Exception, why:
420                                                 print 'Couldn\'t get the node available'
421                                                 print site['name']
422                                                 print why
423                                                 sys.exit(2)
424                         siteUsed.append(siteInit['site_id'])
425                         newEnv = []
426                         print "Site used -> "+str(siteUsed)
427                         print siteInit['name']
428                         for i in range(len(maxNode)-nbInitCommon):
429                                 node = maxNode[i]
430                                 if nbReservedEnvironment < self.nbEnv:
431                                         newEnv.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname'], 'distance': 0, 'latitude': siteInit['latitude'], 'longitude': siteInit['longitude']})
432                                         nodePrivate.append(node['node_id'])
433                                         if len(newEnv) == nbInitPrivate:
434                                                 tmpListEnv.append(newEnv)
435                                                 newEnv = []
436                                                 nbReservedEnvironment += 1
437                                 else:
438                                         break
439                         commonNode = []
440                         for i in range(nbInitPrivate,len(constraintList)):
441                                 nodeAdded = False
442                                 print constraintList[i]
443                                 if constraintList[i]['type'] in ['common', 'public']:
444                                         for site in sitesList:
445                                                 if site['site_id'] not in siteBanned:
446                                                         initPoint = geopy.Point(siteInit['latitude'], siteInit['longitude'])
447                                                         distPoint = geopy.Point(site['latitude'], site['longitude'])
448                                                         distance = geopy.distance.distance(initPoint, distPoint).km
449                                                         if distance >= constraintList[i]['min'] and distance <= constraintList[i]['max']:
450                                                                 nodeAvailable = self.getNodeAvailable(site, nodePrivate+nodeBanned)
451                                                                 if len(nodeAvailable) > 0:
452                                                                         print distance
453                                                                         print site['name']
454                                                                         siteUsed.append(site['site_id'])
455                                                                         node = nodeAvailable[0]
456                                                                         nodeShared.append(node['node_id'])
457                                                                         commonNode.append({'type': constraintList[i]['type'], 'id': node['node_id'], 'hostname': node['hostname'], 'distance': int(distance), 'latitude': site['latitude'], 'longitude': site['longitude']})
458                                                                         nodeAdded = True
459                                                                         break
460                                         if not(nodeAdded) and constraintList[i]['type'] in ['common', 'public']:
461                                                 print 'Error no node added for constraint -> '+str(constraintList[i])
462                                                 raise NodeConstraintError(constraintList[i], envList)
463                                 elif constraintList[i]['type'] == 'private':
464                                         nodeToAdd = []
465                                         for env in tmpListEnv:
466                                                 if len(nodeToAdd) == 0:
467                                                         for site in sitesList:
468                                                                 if site['site_id'] not in siteBanned:
469                                                                         initPoint = geopy.Point(siteInit['latitude'], siteInit['longitude'])
470                                                                         distPoint = geopy.Point(site['latitude'], site['longitude'])
471                                                                         distance = geopy.distance.distance(initPoint, distPoint).km
472                                                                         if distance >= constraintList[i]['min'] and distance <= constraintList[i]['max']:
473                                                                                 nodeAvailable = self.getNodeAvailable(site, nodePrivate+nodeShared+nodeBanned)
474                                                                                 if len(nodeAvailable) > 0:
475                                                                                         nodeToAdd = nodeAvailable
476                                                 node = nodeToAdd.pop(0)
477                                                 env.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname'], 'distance': int(distance), 'latitude': site['latitude'], 'longitude': site['longitude']})
478
479                         for env in tmpListEnv:
480                                 for node in commonNode:
481                                         env.append(node)
482                                         
483                         envList.extend(tmpListEnv)
484         
485                 return envList
486
487         # Reading the raw xml file to get information
488         # Return an array of array of struct containing the information concerning each environment requested
489         def readRawXml(self, siteBanned, nodeBanned):
490                 print "Banned Site ->",siteBanned
491                 print "Node banned ->",nodeBanned
492                 from xml.dom.minidom import parse
493                 conf = parse(self.xmlFileConf)
494                 nbNodeByEnv = nbCommonNode = 0
495                 nodeStructList = []
496                 nodeIdList = []
497                 countryListCommon = []
498                 countryListPrivate = []
499                 constraintList = []
500                 for host_i in conf.getElementsByTagName('host'):
501                         hostType = ""
502                         try:
503                                 hostType = host_i.getElementsByTagName('type')[0].firstChild.nodeValue
504                         except Exception, why:
505                                 print why
506                         if hostType == 'private' or hostType == "":
507                                 nbNodeByEnv += 1
508                         elif hostType == 'common' or hostType == 'public':
509                                 nbCommonNode += 1
510                         else:
511                                 print "Error the host type "+hostType+" doesn't exist"
512                                 sys.exit(2)
513                         if self.country:
514                                 try:
515                                         hostCountry = host_i.getElementsByTagName('country')[0].firstChild.nodeValue
516                                         if hostType == 'common':
517                                                 countryListCommon.append(hostCountry)
518                                         elif hostType == 'private':
519                                                 countryListPrivate.append(hostCountry)
520                                 except Exception, why:
521                                         print "An error occured"
522                                         print why
523                                         sys.exit(2)
524                         else:
525                                 try:
526                                         distance = host_i.getElementsByTagName('distances')[0]
527                                         distMin = int(distance.getElementsByTagName('min')[0].firstChild.nodeValue)
528                                         distMax = int(distance.getElementsByTagName('max')[0].firstChild.nodeValue)
529                                         constraintList.append({'type': hostType, 'min': distMin, 'max': distMax})
530                                 except Exception, why:
531                                         print "An error occured"
532                                         print why
533                                         sys.exit(2)
534
535
536                 print "Getting all the site available"
537                 sites = self.plc_api.GetSites(Auth.auth, ['*'])
538         
539                 if self.country:
540                         nodeStructList = self.getEnvironmentWithCountryConstraint(countryListPrivate, contryListCommon, sites, siteBanned, nodeBanned)
541                 else:
542                         try:
543                                 nodeStructList = self.getEnvironmentWithDistanceConstraint(constraintList, sites, siteBanned, nodeBanned)
544                         except NodeConstraintError as error:
545                                 self.nbEnv = len(error.getEnvList())
546                                 nodeStructList = error.getEnvList()
547         
548
549                 # Creating a file containing all the information about the slice created
550                 origStdout = sys.stdout
551                 sys.stdout = open('Test', 'w')
552                 i = 0
553                 print "Slice name : "+self.slice_name
554                 for env in nodeStructList:
555                         i+=1
556                         print "\tEnv %i"%i
557                         for node in env:
558                                 strNode = '\t'
559                                 for key in node.keys():
560                                         strNode += "\t"+str(key)+" : "+str(node[key])
561                                 print strNode
562                 sys.stdout.close()
563                 sys.stdout = origStdout
564         
565                 return(nodeStructList)
566
567         def structToArray(self, requestAnswer, key):
568                 #return  [i[key] for i in requestAnswer]
569                 array = []
570                 for i in requestAnswer:
571                         array.append(i[key])
572                 return array
573
574         def addSliceTag(self, sliceId, tagName, tagValue):
575                 try:
576                         returnCode = self.plc_api.AddSliceTag(Auth.auth, sliceId, tagName, tagValue)
577                         if returnCode == 0:
578                                 print "An error Occured while adding the tag %s -> %s"% tagName, tagValue
579                 except xmlrpclib.Fault as fault:
580                         if fault.faultCode != 102:
581                                 print "An error occured"
582                                 print fault
583                                 sys.exit(2)
584
585         def getSlice(self):
586                 try:
587                         sliceId = self.plc_api.GetSlices(Auth.auth, self.slice_name)[0]['slice_id']
588                 except xmlrpclib.Fault, why:
589                         print "An error while getting the slice already existing"
590                         print why
591                         sys.exit(2)
592                 return sliceId
593         
594         def createSlice(self):
595                 sliceId = 0
596                 print "Creating a new slice called : "+self.slice_name
597                 try:
598                         sliceId = self.plc_api.AddSlice(Auth.auth, {'description': self.sliceDescription, 'name':self.slice_name, 'url': self.sliceUrl})
599                 except xmlrpclib.Fault, why:
600                         print "An error occured while creating the slice "+self.slice_name
601                         print why
602                 except Exception, why:
603                         print "An error occured while createing the slice "+self.slice_name
604                         print type(why)
605                         print why
606                 return sliceId
607         
608         def setSlice(self):
609                 sliceId = self.createSlice()
610                 if (sliceId == 0):
611                         print 'Slice exist'
612                         sliceId = self.getSlice()
613                 print "Adding user to the slice"
614                 returnCode = self.plc_api.AddPersonToSlice(Auth.auth, Auth.auth['Username'], sliceId)
615                 
616                 if type(self.nbEnv) != int:
617                         print "You must enter a number"
618                         sys.exit(2)
619
620                 print "Generating and adding the main ssh key"
621                 print os.getcwd()
622                 if self.mainKeyPriv == None:
623                         self.mainKeyPriv, self.mainKeyPub = self.generateKeyPair(pref = "./key/"+self.slice_name+"main", bit = 1024)
624                 f = open(self.mainKeyPub)
625                 keyString = f.read()
626                 try:
627                         keyId = self.plc_api.AddPersonKey(Auth.auth, Auth.auth['Username'], {'key_type': 'ssh', 'key': keyString})
628                         if returnCode == 0:
629                                 print "An error occured while adding the key to the user"
630                                 sys.exit(2)
631                 except xmlrpclib.Fault as fault:
632                         print fault
633                         sys.exit(2)
634
635                 success = False
636                 #TODO Ban failing site, waiting for fix
637                 #FU Berlin || Reykjavik University || FOKUS || University of Goettingen
638                 siteBanned = [7341, 7336, 443, 7059]
639                 # TODO banned new lip6 node + FUNDP Site + DSCHINI
640                 nodeBanned = [15953, 15954, 15955, 15956, 14810]
641                 while success == False:
642                         nodeList = self.readRawXml(siteBanned[:], nodeBanned)
643                 
644                         print "Adding node to the slice"
645                         i = 0
646                         for env in nodeList:
647                                 for node in env:
648                                         failToAdd = True
649                                         j = 0
650                                         while failToAdd:
651                                                 try:
652                                                         if node['type'] == 'private' or ((node['type'] == 'common' or node['type'] == 'public') and i == 0):
653                                                                 returnCode = self.plc_api.AddSliceToNodes(Auth.auth, sliceId, [node['id']])
654                                                         if returnCode != 1:
655                                                                 print "An error occured while adding a node to the slice"
656                                                                 time.sleep(30)
657                                                         else:
658                                                                 failToAdd = False
659                                                 except xmlrpclib.Fault as fault:
660                                                         print fault
661                                                         time.sleep(30)
662                                                 if j > 2 and failToAdd:
663                                                         raise FailToConnect(node['id'], node['hostname'])
664                                                 j+=1
665                                 i = 1
666         
667
668
669                         i=0
670                         # Set additional ssh server using generated key file and port 2222
671                         try:
672                                 for envList in nodeList:
673                                         envKeyPriv, envKeyPub = self.generateKeyPair(pref = "./key/"+self.slice_name+"group"+str(i+1), bit = 1024)
674                                         self.envKeyPriv.append(envKeyPriv)
675                                         self.envKeyPub.append(envKeyPub)
676                                         for node in envList:
677                                                 print node['hostname']
678                                                 if node['type'] != 'common':
679                                                         self.installSSH(self.envKeyPub[i], node)
680                                                         pass
681                                                 else:
682                                                         self.checkSSH(node)
683                                                         pass
684                                         i+=1
685                                 success = True
686                         except FailToConnect as error:
687                                 print "Not able to get the ssh connection for node", error.getNodeUrl()
688                                 print 'Error node id -> '+str(error.getNodeId())
689                                 print 'Before adding failing node -> '+str(nodeBanned)
690                                 nodeBanned.append(error.getNodeId())
691                                 print 'After adding failing node -> '+str(nodeBanned)
692                         except Exception, why:
693                                 print "Not able to get the ssh connection", why
694
695
696
697                 print "Adding requested tag to the slice"
698                 # Adding the tag needed :
699                 #       - TAG -> VALUE : DEF
700                 #       - vsys -> vif_up 
701                 #       - vsys -> vif_down 
702                 #       - vsys -> fd_tuntap : Allow to create tun/tap interface
703                 #       - vsys -> vroute : Allow to define new route
704                 #       - vsys_vnet -> SUBNET : Define the subnet allowed for tun/tap device
705
706                 self.addSliceTag(sliceId, 'vsys', 'vif_up')
707                 self.addSliceTag(sliceId, 'vsys', 'vif_down')
708                 self.addSliceTag(sliceId, 'vsys', 'fd_tuntap')
709                 self.addSliceTag(sliceId, 'vsys', 'vroute')
710                 self.addSliceTag(sliceId, 'vsys_vnet', self.subnet)
711
712                 # Configuring the node using the openvswitch.py script
713                 # Command used to execute the script
714                 i = 0
715                 for env in nodeList:
716                         i+=1
717                         print "Env ",i
718                         hostnameList = self.structToArray(env, 'hostname')
719                         self.createXmlFile(hostnameList, i)
720                         try:
721                                 x = None
722                                 x = TransformXml(prefix = 'requ'+str(i), keyFile = self.mainKeyPriv)
723                                 x.setSliceConf()
724                                 x.setLinks()
725                                 x.setRoutes()
726                                 x.setServices()
727                                 self.envList.append(x.getSliceList())
728                         except Exception, why:
729                                 print "An error occured while configuring the environment number "+str(i-1)
730                                 print Exception
731                                 print ''
732                                 print why
733                                 sys.exit(2)
734
735         
736 if __name__ == "__main__":
737         parser = argparse.ArgumentParser()
738         parser.add_argument("-s", "--subnet", help="The subnet reserved for the slice, it must include at least all the ip address used by the tp. The syntax is SUBNET/PREFIX (e.g 10.1.0.0/16 which is the default value)", default='10.1.0.0/16')
739         parser.add_argument("-n", "--name", help="Name of the slice", default='tp')
740         parser.add_argument("-nb", "--number", help="Number of the environment you want", type=int, default=1)
741         groupInput = parser.add_mutually_exclusive_group()
742         groupInput.add_argument('-f', '--file', help="The xml file that will be used, Link xml file then Configuration xml file", type=str, default='', nargs=2)
743         groupInput.add_argument("-p", "--prefix", help="A prefix used to find the xml file, the script will look at prefix+Conf.xml and prefix+Link.xml", type=str, dest='prefix')
744
745         try:
746                 args = parser.parse_args()
747         except Exception, why:
748                 print "An error occured while parsing the argument"
749                 parser.print_help()
750                 print why
751                 sys.exit(2)
752         
753         if args.file != '':
754                 x = TransformRawXml(confFile = args.file[0], linkFile = args.file[1], subnet = args.subnet, sliceName = args.name, nbEnv = args.number)
755                 x.setSlice()
756         else:
757                 x = TransformRawXml(prefix = args.prefix, subnet = args.subnet, sliceName = args.name, nbEnv = args.number)
758                 x.setSlice()
759