1 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
2 # Copyright (C) 2010 INRIA
7 from datetime import datetime, timedelta
12 from TestNode import TestNode
13 from TestUser import TestUser
14 from TestBoxQemu import TestBoxQemu
16 from Completer import Completer, CompleterTask
17 from TestSlice import CompleterTaskSliceSsh
21 def __init__ (self, test_auth_sfa, slice_spec):
22 self.test_auth_sfa = test_auth_sfa
23 self.slice_spec = slice_spec
25 self.test_plc = self.test_auth_sfa.test_plc
28 return self.test_auth_sfa.obj_hrn(self.slice_spec['name'])
30 return self.test_auth_sfa.sfi_path()
32 # send back up to the TestAuthSfa
33 def sfi_path (self): return self.test_auth_sfa.sfi_path()
34 def rspec_style (self): return self.test_auth_sfa.rspec_style()
35 def sfi_pi(self,*args,**kwds): return self.test_auth_sfa.sfi_pi(*args, **kwds)
36 def sfi_user(self,*args,**kwds): return self.test_auth_sfa.sfi_user(*args, **kwds)
38 def discover_option(self):
39 if self.rspec_style() == 'pg':
44 # those are step names exposed as methods of TestPlc, hence the _sfa
46 # needs to be run as pi
47 def sfa_register_slice(self,options):
48 "run sfi register (on Registry)"
49 sfi_command = "register"
50 sfi_command += " --type slice"
51 sfi_command += " --xrn {}".format(self.hrn())
52 for opt in self.slice_spec['register_options']:
53 sfi_command += " {}".format(opt)
54 return self.test_plc.run_in_guest(self.sfi_pi(sfi_command))==0
56 def sfa_renew_slice(self, options):
57 "run sfi renew (on Aggregates)"
58 # too_late = (datetime.now() + timedelta(weeks=52)).strftime("%Y-%m-%d")
59 one_month = (datetime.now() + timedelta(weeks=4)).strftime("%Y-%m-%d")
62 # we expect this to fail on too long term attemps, but to succeed otherwise
64 for ( renew_until, expected) in [ (too_late, False), (one_month, True) ] :
66 sfi_command += " {}".format(self.hrn())
67 sfi_command += " {}".format(renew_until)
68 succeeded = self.test_plc.run_in_guest(self.sfi_user(sfi_command))==0
69 if succeeded != expected:
70 utils.header ("Expecting success={}, got {}".format(expected, succeeded))
71 # however it turns out sfi renew always returns fine....
73 # so for helping manual checks:
74 # xxx this should use sfa_get_expires below and actually check the expected result
75 sfi_command = "show -k hrn -k expires {}".format(self.hrn())
76 self.test_plc.run_in_guest(self.sfi_user(sfi_command))
79 def sfa_get_expires (self, options):
80 filename = "{}.json".format(self.hrn())
82 inplc_filename = os.path.join(self.sfi_path(),filename)
83 # /vservers/<>/root/sfi/... - cannot use os.path
84 inbox_filename = "{}{}".format(self.test_plc.vm_root_in_host(), inplc_filename)
86 sfi_command += "-R {} --rawformat json".format(inplc_filename)
87 sfi_command += " status"
88 sfi_command += " {}".format(self.hrn())
89 # cannot find it if sfi status returns an error
90 if self.test_plc.run_in_guest (self.sfi_user(sfi_command)) !=0: return
91 if self.test_plc.test_ssh.fetch(inbox_filename,filename)!=0: return
93 with open(filename) as f:
94 status = json.loads(f.read())
95 value = status['value']
96 sliver = value['geni_slivers'][0]
97 expires = sliver['geni_expires']
98 print(" * expiration for {} (first sliver) -> {}".format(self.hrn(), expires))
101 traceback.print_exc()
103 # helper - filename to store a given result
104 def _resname (self,name,ext): return "{}.{}".format(name, ext)
105 def adfile (self): return self._resname("ad","rspec")
106 def reqfile (self): return self._resname("req","rspec")
107 def empty_reqfile (self): return "empty-rspec.xml"
108 def nodefile (self): return self._resname("nodes","txt")
111 def sfa_discover(self,options):
112 "discover resources into resouces_in.rspec"
113 return self.test_plc.run_in_guest(self.sfi_user(\
114 "resources {} -o {}/{}"\
115 .format(self.discover_option(),self.sfi_path(),self.adfile()))) == 0
117 def sfa_rspec(self,options):
118 "invoke sfiListNodes and sfiAddSlivers to prepare a rspec"
120 "sfiListNodes.py -i {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
121 self.sfi_path(), self.nodefile()),
122 "sfiAddSliver.py -i {}/{} -n {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
123 self.sfi_path(), self.nodefile(),
124 self.sfi_path(), self.reqfile()),
126 for command in commands:
127 if self.test_plc.run_in_guest(command) != 0: return False
130 def _sfa_allocate(self,file,options):
131 command = self.sfi_user("allocate {} {}".format(self.hrn(), file))
132 return self.test_plc.run_in_guest(command) == 0
134 def sfa_allocate(self,options):
135 "invoke run sfi allocate (on SM)"
136 return self._sfa_allocate(self.reqfile(),options)
137 def sfa_allocate_empty(self,options):
138 "invoke run sfi allocate (on SM) with an empty rspec"
139 return self._sfa_allocate(self.empty_reqfile(),options)
141 def sfa_provision(self,options):
142 "invoke run sfi provision (on SM)"
143 command = self.sfi_user("provision {}".format(self.hrn()))
144 return self.test_plc.run_in_guest(command) == 0
146 sfa_provision_empty = sfa_provision
149 return "{}_{}".format(self.test_auth_sfa.login_base, self.slice_spec['name'])
151 # all local nodes in slice ?
152 def sfa_check_slice_plc (self,options):
153 "check the slice has been created at the plc - all local nodes should be in slice"
154 slice = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(), self.plc_name())[0]
155 nodes = self.test_plc.apiserver.GetNodes(self.test_plc.auth_root(), {'peer_id':None})
158 if node['node_id'] in slice['node_ids']:
159 utils.header("local node {} found in slice {}".format(node['hostname'], slice['name']))
161 utils.header("ERROR - local node {} NOT FOUND in slice {}"\
162 .format(node['hostname'], slice['name']))
166 # no node left in slice ?
167 def sfa_check_slice_plc_empty (self,options):
168 "check the slice have been emptied at the plcs - no node should be in slice"
169 slices = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(),
172 return not slices[0]['node_ids']
174 # xxx historically this used to do the same as sfa-create-slice
175 # which was later on split into 3 distinct steps,
176 # and we can ignore the first that is about setting up the rspec
177 def sfa_update_slice(self,options):
178 "re-run sfi allocate and provision (on SM) on existing object"
179 return self.sfa_allocate(options) and self.sfa_provision(options)
182 def sfa_delete_slice(self,options):
184 self.test_plc.run_in_guest(self.sfi_pi("delete {}".format(self.hrn())))
185 return self.test_plc.run_in_guest(self.sfi_pi("remove -t slice {}".format(self.hrn()))) == 0
187 def locate_private_key(self):
188 return self.test_plc.locate_private_key_from_key_names ( [ self.slice_spec['key_name'] ] )
190 # check the resulting sliver
191 def ssh_slice_sfa(self, options, timeout_minutes=40, silent_minutes=0, period_seconds=15):
192 "tries to ssh-enter the SFA slice"
193 timeout = timedelta(minutes=timeout_minutes)
194 graceout = timedelta(minutes=silent_minutes)
195 period = timedelta(seconds=period_seconds)
197 private_key=self.locate_private_key()
199 utils.header("WARNING: Cannot find a valid key for slice {}".format(self.name()))
201 command="echo hostname ; hostname; echo id; id; echo uname -a ; uname -a"
204 slicename=self.plc_name()
205 dry_run = getattr(options,'dry_run',False)
206 for nodename in self.slice_spec['nodenames']:
207 (site_spec,node_spec) = self.test_plc.locate_node(nodename)
208 tasks.append( CompleterTaskSliceSsh(self.test_plc, node_spec['node_fields']['hostname'],
209 slicename, private_key, command,
210 expected=True, dry_run=dry_run))
211 return Completer (tasks, message='ssh_slice_sfa').run(timeout, graceout, period)