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