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
34 return self.test_auth_sfa.sfi_path()
35 def sfi_pi(self, *args, **kwds):
36 return self.test_auth_sfa.sfi_pi(*args, **kwds)
37 def sfi_user(self, *args, **kwds):
38 return self.test_auth_sfa.sfi_user(*args, **kwds)
40 def discover_option(self):
43 # those are step names exposed as methods of TestPlc, hence the _sfa
45 # needs to be run as pi
46 def sfa_register_slice(self, options):
47 "run sfi register (on Registry)"
48 sfi_command = "register"
49 sfi_command += " --type slice"
50 sfi_command += " --xrn {}".format(self.hrn())
51 for opt in self.slice_spec['register_options']:
52 sfi_command += " {}".format(opt)
53 return self.test_plc.run_in_guest(self.sfi_pi(sfi_command))==0
55 def sfa_renew_slice(self, options):
56 "run sfi renew (on Aggregates)"
57 # too_late = (datetime.now() + timedelta(weeks=52)).strftime("%Y-%m-%d")
58 one_month = (datetime.now() + timedelta(weeks=4)).strftime("%Y-%m-%d")
61 # we expect this to fail on too long term attemps, but to succeed otherwise
63 for ( renew_until, expected) in [ (too_late, False), (one_month, True) ] :
65 sfi_command += " {}".format(self.hrn())
66 sfi_command += " {}".format(renew_until)
67 succeeded = self.test_plc.run_in_guest(self.sfi_user(sfi_command))==0
68 if succeeded != expected:
69 utils.header ("Expecting success={}, got {}".format(expected, succeeded))
70 # however it turns out sfi renew always returns fine....
72 # so for helping manual checks:
73 # xxx this should use sfa_get_expires below and actually check the expected result
74 sfi_command = "show -k hrn -k expires {}".format(self.hrn())
75 self.test_plc.run_in_guest(self.sfi_user(sfi_command))
78 def sfa_get_expires (self, options):
79 filename = "{}.json".format(self.hrn())
81 inplc_filename = os.path.join(self.sfi_path(), filename)
82 # /vservers/<>/root/sfi/... - cannot use os.path
83 inbox_filename = "{}{}".format(self.test_plc.vm_root_in_host(), inplc_filename)
85 sfi_command += "-R {} --rawformat json".format(inplc_filename)
86 sfi_command += " status"
87 sfi_command += " {}".format(self.hrn())
88 # cannot find it if sfi status returns an error
89 if self.test_plc.run_in_guest (self.sfi_user(sfi_command)) !=0: return
90 if self.test_plc.test_ssh.fetch(inbox_filename, filename)!=0: return
92 with open(filename) as f:
93 status = json.loads(f.read())
94 value = status['value']
95 sliver = value['geni_slivers'][0]
96 expires = sliver['geni_expires']
97 print(" * expiration for {} (first sliver) -> {}".format(self.hrn(), expires))
100 traceback.print_exc()
102 # helper - filename to store a given result
103 def _resname (self, name, ext): return "{}.{}".format(name, ext)
104 def adfile (self): return self._resname("ad", "rspec")
105 def reqfile (self): return self._resname("req", "rspec")
106 def empty_reqfile (self): return "empty-rspec.xml"
107 def nodefile (self): return self._resname("nodes", "txt")
108 def describfile (self): return self._resname("describ", "rspec")
110 def sfa_describe(self, options):
111 "run sfi describe into described.rspec"
112 return self.test_plc.run_in_guest(self.sfi_user(
113 "describe {} -o {}/{}"
114 .format(self.hrn(), self.sfi_path(), self.describfile()))) == 0
117 def sfa_discover(self, options):
118 "discover resources into ad.rspec"
119 return self.test_plc.run_in_guest(self.sfi_user(
120 "resources {} -o {}/{}"\
121 .format(self.discover_option(),self.sfi_path(),self.adfile()))) == 0
123 def sfa_rspec(self, options):
124 "invoke sfiListNodes and sfiAddSlivers to prepare a rspec"
126 "sfiListNodes.py -i {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
127 self.sfi_path(), self.nodefile()),
128 "sfiAddSliver.py -i {}/{} -n {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
129 self.sfi_path(), self.nodefile(),
130 self.sfi_path(), self.reqfile()),
132 for command in commands:
133 if self.test_plc.run_in_guest(command) != 0: return False
136 def _sfa_allocate(self, file, options):
137 command = self.sfi_user("allocate {} {}".format(self.hrn(), file))
138 return self.test_plc.run_in_guest(command) == 0
140 def sfa_allocate(self, options):
141 "invoke run sfi allocate (on SM)"
142 return self._sfa_allocate(self.reqfile(), options)
143 def sfa_allocate_empty(self, options):
144 "invoke run sfi allocate (on SM) with an empty rspec"
145 return self._sfa_allocate(self.empty_reqfile(), options)
147 def sfa_provision(self, options):
148 "invoke run sfi provision (on SM)"
149 command = self.sfi_user("provision {}".format(self.hrn()))
150 return self.test_plc.run_in_guest(command) == 0
152 sfa_provision_empty = sfa_provision
155 return "{}_{}".format(self.test_auth_sfa.login_base, self.slice_spec['name'])
157 # all local nodes in slice ?
158 def sfa_check_slice_plc (self, options):
159 "check the slice has been created at the plc - all local nodes should be in slice"
160 slice = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(), self.plc_name())[0]
161 nodes = self.test_plc.apiserver.GetNodes(self.test_plc.auth_root(), {'peer_id':None})
164 if node['node_id'] in slice['node_ids']:
165 utils.header("local node {} found in slice {}".format(node['hostname'], slice['name']))
167 utils.header("ERROR - local node {} NOT FOUND in slice {}"\
168 .format(node['hostname'], slice['name']))
172 # no node left in slice ?
173 def sfa_check_slice_plc_empty (self, options):
174 "check the slice have been emptied at the plcs - no node should be in slice"
175 slices = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(),
178 return not slices[0]['node_ids']
180 # xxx historically this used to do the same as sfa-create-slice
181 # which was later on split into 3 distinct steps,
182 # and we can ignore the first that is about setting up the rspec
183 def sfa_update_slice(self, options):
184 "re-run sfi allocate and provision (on SM) on existing object"
185 return self.sfa_allocate(options) and self.sfa_provision(options)
188 def sfa_delete_slice(self, options):
190 self.test_plc.run_in_guest(self.sfi_pi("delete {}".format(self.hrn())))
191 return self.test_plc.run_in_guest(self.sfi_pi("remove -t slice {}".format(self.hrn()))) == 0
193 def locate_private_key(self):
194 return self.test_plc.locate_private_key_from_key_names ( [ self.slice_spec['key_name'] ] )
196 # check the resulting sliver
197 def ssh_slice_sfa(self, options, timeout_minutes=40, silent_minutes=0, period_seconds=15):
198 "tries to ssh-enter the SFA slice"
199 timeout = timedelta(minutes=timeout_minutes)
200 graceout = timedelta(minutes=silent_minutes)
201 period = timedelta(seconds=period_seconds)
203 private_key=self.locate_private_key()
205 utils.header("WARNING: Cannot find a valid key for slice {}".format(self.hrn()))
207 command="echo hostname ; hostname; echo id; id; echo uname -a ; uname -a"
210 slicename = self.plc_name()
211 dry_run = getattr(options,'dry_run',False)
212 for nodename in self.slice_spec['nodenames']:
213 (site_spec,node_spec) = self.test_plc.locate_node(nodename)
214 tasks.append( CompleterTaskSliceSsh(self.test_plc, node_spec['node_fields']['hostname'],
215 slicename, private_key, command,
216 expected=True, dry_run=dry_run))
217 return Completer (tasks, message='ssh_slice_sfa').run(timeout, graceout, period)