deprecated -y option of run_log/TestMain
[tests.git] / system / TestSliceSfa.py
1 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
2 # Copyright (C) 2010 INRIA 
3 #
4
5 import os.path
6 import time
7 from datetime import datetime, timedelta
8 import json
9 import traceback
10
11 import utils
12 from TestNode import TestNode
13 from TestUser import TestUser
14 from TestBoxQemu import TestBoxQemu
15
16 from Completer import Completer, CompleterTask
17 from TestSlice import CompleterTaskSliceSsh
18
19 class TestSliceSfa:
20
21     def __init__ (self, test_auth_sfa, slice_spec):
22         self.test_auth_sfa = test_auth_sfa
23         self.slice_spec = slice_spec
24         # shortcuts
25         self.test_plc = self.test_auth_sfa.test_plc
26
27     def hrn (self): 
28         return self.test_auth_sfa.obj_hrn(self.slice_spec['name'])
29     def sfi_path (self):
30         return self.test_auth_sfa.sfi_path()
31
32     # send back up to the TestAuthSfa
33     def sfi_path (self):
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)
39
40     def discover_option(self):
41         return "-r GENI"
42
43     # those are step names exposed as methods of TestPlc, hence the _sfa
44
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
54
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")
59         too_late =  "+12m"
60 #        one_month = "+4w"
61         # we expect this to fail on too long term attemps, but to succeed otherwise
62         overall = True
63         for ( renew_until, expected) in [ (too_late, False), (one_month, True) ] :
64             sfi_command = "renew"
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....
71                 #overall=False
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))
76         return overall
77
78     def sfa_get_expires (self, options):
79         filename = "{}.json".format(self.hrn())
80         # /root/sfi/pg/<>
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)
84         sfi_command  = ""
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 
91         try:
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))
98             return expires
99         except:
100             traceback.print_exc()
101
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     
109     # run as user
110     def sfa_discover(self, options):
111         "discover resources into resouces_in.rspec"
112         return self.test_plc.run_in_guest(self.sfi_user(\
113                 "resources {} -o {}/{}"\
114                     .format(self.discover_option(),self.sfi_path(),self.adfile()))) == 0
115
116     def sfa_rspec(self, options):
117         "invoke sfiListNodes and sfiAddSlivers to prepare a rspec"
118         commands = [
119             "sfiListNodes.py -i {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
120                                                        self.sfi_path(), self.nodefile()),
121             "sfiAddSliver.py -i {}/{} -n {}/{} -o {}/{}".format(self.sfi_path(), self.adfile(),
122                                                                 self.sfi_path(), self.nodefile(),
123                                                                 self.sfi_path(), self.reqfile()),
124             ]
125         for command in commands:
126             if self.test_plc.run_in_guest(command) != 0: return False
127         return True
128
129     def _sfa_allocate(self, file, options):
130         command = self.sfi_user("allocate {} {}".format(self.hrn(), file))
131         return self.test_plc.run_in_guest(command) == 0
132
133     def sfa_allocate(self, options):
134         "invoke run sfi allocate (on SM)"
135         return self._sfa_allocate(self.reqfile(), options)
136     def sfa_allocate_empty(self, options):
137         "invoke run sfi allocate (on SM) with an empty rspec"
138         return self._sfa_allocate(self.empty_reqfile(), options)
139
140     def sfa_provision(self, options):
141         "invoke run sfi provision (on SM)"
142         command = self.sfi_user("provision {}".format(self.hrn()))
143         return self.test_plc.run_in_guest(command) == 0
144     # just a synonym
145     sfa_provision_empty = sfa_provision
146
147     def plc_name (self):
148         return "{}_{}".format(self.test_auth_sfa.login_base, self.slice_spec['name'])
149
150     # all local nodes in slice ?
151     def sfa_check_slice_plc (self, options):
152         "check the slice has been created at the plc - all local nodes should be in slice"
153         slice = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(), self.plc_name())[0]
154         nodes = self.test_plc.apiserver.GetNodes(self.test_plc.auth_root(), {'peer_id':None})
155         result = True
156         for node in nodes: 
157             if node['node_id'] in slice['node_ids']:
158                 utils.header("local node {} found in slice {}".format(node['hostname'], slice['name']))
159             else:
160                 utils.header("ERROR - local node {} NOT FOUND in slice {}"\
161                              .format(node['hostname'], slice['name']))
162                 result = False
163         return result
164
165     # no node left in slice ?
166     def sfa_check_slice_plc_empty (self, options):
167         "check the slice have been emptied at the plcs - no node should be in slice"
168         slices = self.test_plc.apiserver.GetSlices(self.test_plc.auth_root(), 
169                                                    self.plc_name(),
170                                                    ['node_ids'])
171         return not slices[0]['node_ids']
172
173     # xxx historically this used to do the same as sfa-create-slice
174     # which was later on split into 3 distinct steps, 
175     # and we can ignore the first that is about setting up the rspec
176     def sfa_update_slice(self, options):
177         "re-run sfi allocate and provision (on SM) on existing object"
178         return self.sfa_allocate(options) and self.sfa_provision(options)
179
180     # run as pi
181     def sfa_delete_slice(self, options):
182         "run sfi delete"
183         self.test_plc.run_in_guest(self.sfi_pi("delete {}".format(self.hrn())))
184         return self.test_plc.run_in_guest(self.sfi_pi("remove -t slice {}".format(self.hrn()))) == 0
185
186     def locate_private_key(self):
187         return self.test_plc.locate_private_key_from_key_names ( [ self.slice_spec['key_name'] ] )
188
189     # check the resulting sliver
190     def ssh_slice_sfa(self, options, timeout_minutes=40, silent_minutes=0, period_seconds=15):
191         "tries to ssh-enter the SFA slice"
192         timeout  = timedelta(minutes=timeout_minutes)
193         graceout = timedelta(minutes=silent_minutes)
194         period   = timedelta(seconds=period_seconds)
195         # locate a key
196         private_key=self.locate_private_key()
197         if not private_key :
198             utils.header("WARNING: Cannot find a valid key for slice {}".format(self.name()))
199             return False
200         command="echo hostname ; hostname; echo id; id; echo uname -a ; uname -a"
201         
202         tasks=[]
203         slicename=self.plc_name()
204         dry_run = getattr(options,'dry_run',False)
205         for nodename in self.slice_spec['nodenames']:
206             (site_spec,node_spec) = self.test_plc.locate_node(nodename)
207             tasks.append( CompleterTaskSliceSsh(self.test_plc, node_spec['node_fields']['hostname'],
208                                                 slicename, private_key, command,
209                                                 expected=True, dry_run=dry_run))
210         return Completer (tasks, message='ssh_slice_sfa').run(timeout, graceout, period)