Package entropy :: Package client :: Package services :: Package system :: Module interfaces

Source Code for Module entropy.client.services.system.interfaces

  1  # -*- coding: utf-8 -*- 
  2  """ 
  3   
  4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
  5      @contact: lxnay@sabayonlinux.org 
  6      @copyright: Fabio Erculiani 
  7      @license: GPL-2 
  8   
  9      B{Entropy Client Services Base Interface}. 
 10   
 11  """ 
 12  from __future__ import with_statement 
 13  import time 
 14  from entropy.exceptions import * 
 15  from entropy.i18n import _ 
 16  from entropy.misc import TimeScheduled 
 17  from entropy.i18n import _ 
 18   
19 -class Client:
20 21 ssl_connection = True
22 - def __init__(self, OutputInterface, MethodsInterface = None, 23 ClientCommandsInterface = None, quiet = True, show_progress = False, 24 do_cache_connection = False, do_cache_session = False):
25 26 if not hasattr(OutputInterface, 'updateProgress'): 27 mytxt = _("OutputInterface does not have an updateProgress method") 28 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 29 elif not callable(OutputInterface.updateProgress): 30 mytxt = _("OutputInterface does not have an updateProgress method") 31 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 32 33 from entropy.client.services.system.commands import Client as ClientCommands 34 if not issubclass(ClientCommandsInterface, ClientCommands): 35 mytxt = _("A valid entropy.client.services.system.commands.Client class/subclass is needed") 36 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 37 38 from entropy.client.services.system.methods import BaseMixin 39 if not issubclass(MethodsInterface, BaseMixin): 40 mytxt = _("A valid entropy.client.services.system.methods.BaseMixin class/subclass is needed") 41 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 42 43 self.ClientCommandsInterface = ClientCommandsInterface 44 import socket, struct 45 import entropy.tools as entropyTools 46 self.socket, self.struct, self.entropyTools = socket, struct, entropyTools 47 from datetime import datetime 48 self.datetime = datetime 49 import threading 50 self.threading = threading 51 self.Output = OutputInterface 52 self.hostname = None 53 self.hostport = None 54 self.username = None 55 self.password = None 56 self.quiet = quiet 57 self.do_cache_connection = do_cache_connection 58 self.show_progress = show_progress 59 self.ClientCommandsInterface = ClientCommandsInterface 60 self.Methods = MethodsInterface(self) 61 self.session_cache = {} 62 self.SessionCacheLock = self.threading.Lock() 63 self.connection_cache = {} 64 self.CacheLock = self.threading.Lock() 65 self.shutdown = False 66 self.connection_killer = None 67 68 # XXX actually session cache doesn't work when the connection is closed and re-opened 69 # when the server is spawning requests under a child process (fork_requests = True) 70 # this should be fixed by pushing the cache to disk but triggers a possible security issue 71 # since sessions and their password are stored in memory and kept alive there until those 72 # expires 73 self.do_cache_session = do_cache_session 74 if self.do_cache_connection: 75 self.connection_killer = TimeScheduled(2, self.connection_killer_handler) 76 self.connection_killer.start()
77
78 - def __del__(self):
79 if hasattr(self,'shutdown'): 80 self.shutdown = True 81 if hasattr(self,'connection_killer'): 82 if self.connection_killer != None: 83 self.connection_killer.kill()
84
85 - def _validate_credentials(self):
86 if not isinstance(self.hostname,basestring): 87 raise IncorrectParameter("IncorrectParameter: hostname: %s. %s" % (_('not a string'),_('Please use setup_connection() properly'),)) 88 if not isinstance(self.username,basestring): 89 raise IncorrectParameter("IncorrectParameter: username: %s. %s" % (_('not a string'),_('Please use setup_connection() properly'),)) 90 if not isinstance(self.password,basestring): 91 raise IncorrectParameter("IncorrectParameter: password: %s. %s" % (_('not a string'),_('Please use setup_connection() properly'),)) 92 if not isinstance(self.hostport,int): 93 raise IncorrectParameter("IncorrectParameter: port: %s. %s" % (_('not an int'),_('Please use setup_connection() properly'),)) 94 if not isinstance(self.ssl_connection,bool): 95 raise IncorrectParameter("IncorrectParameter: ssl_connection: %s. %s" % (_('not a bool'),_('Please use setup_connection() properly'),))
96
97 - def get_session_cache(self, cmd_tuple):
98 if self.do_cache_session: 99 with self.SessionCacheLock: 100 return self.session_cache.get(cmd_tuple)
101
102 - def set_session_cache(self, cmd_tuple, session_id):
103 if self.do_cache_session: 104 with self.SessionCacheLock: 105 self.session_cache[cmd_tuple] = session_id
106
107 - def remove_session_cache(self, cmd_tuple):
108 if self.do_cache_session: 109 with self.SessionCacheLock: 110 del self.session_cache[cmd_tuple]
111
112 - def get_connection_cache_key(self):
113 return hash((self.hostname, self.hostport, self.username, self.password, self.ssl_connection,))
114
115 - def get_connection_cache(self):
116 if self.do_cache_connection: 117 key = self.get_connection_cache_key() 118 srv = self.connection_cache.get(key) 119 # FIXME: if you enable cache connection, you should also consider to clear the socket buffer 120 # srv.sock_conn 121 # srv.real_sock_conn 122 return srv
123
124 - def cache_connection(self, srv):
125 if self.do_cache_connection: 126 key = self.get_connection_cache_key() 127 self.connection_cache[key] = { 128 'conn': srv, 129 'ts': self.get_ts(), 130 }
131
132 - def update_connection_ts(self):
133 if self.do_cache_connection: 134 key = self.get_connection_cache_key() 135 if key not in self.connection_cache: 136 return 137 self.connection_cache[key]['ts'] = self.get_ts()
138
139 - def kill_all_connections(self):
140 if self.do_cache_connection: 141 self.CacheLock.acquire() 142 try: 143 keys = self.connection_cache.keys() 144 for key in keys: 145 data = self.connection_cache.pop(key) 146 data['conn'].disconnect() 147 finally: 148 self.CacheLock.release()
149
151 152 if not self.do_cache_connection: return 153 if self.shutdown: return 154 if not self.connection_cache: return 155 156 keys = self.connection_cache.keys() 157 for key in keys: 158 curr_ts = self.get_ts() 159 ts = self.connection_cache[key]['ts'] 160 delta = curr_ts - ts 161 if delta.seconds < 60: 162 continue 163 self.CacheLock.acquire() 164 try: 165 data = self.connection_cache.pop(key) 166 finally: 167 self.CacheLock.release() 168 srv = data['conn'] 169 srv.disconnect()
170
171 - def get_ts(self):
172 return self.datetime.fromtimestamp(time.time())
173
174 - def setup_connection(self, hostname, port, username, password, ssl):
175 self.hostname = hostname 176 self.hostport = port 177 self.username = username 178 self.password = password 179 self.ssl_connection = ssl 180 self._validate_credentials()
181
182 - def connect_to_service(self, timeout = None):
183 self._validate_credentials() 184 args = [self.Output, self.ClientCommandsInterface] 185 kwargs = { 186 'ssl': self.ssl_connection, 187 'quiet': self.quiet, 188 'show_progress': self.show_progress 189 } 190 if timeout != None: kwargs['socket_timeout'] = timeout 191 from entropy.services.ugc.interfaces import Client 192 srv = Client(*args,**kwargs) 193 srv.connect(self.hostname, self.hostport) 194 return srv
195
196 - def get_service_connection(self, timeout = None):
197 try: 198 srv = self.connect_to_service(timeout = timeout) 199 except (ConnectionError,self.socket.error,self.struct.error,): 200 return None 201 return srv
202
203 - def logout(self, srv, session_id):
204 self._validate_credentials() 205 return srv.CmdInterface.service_logout(self.username, session_id)
206
207 - def login(self, srv, session_id):
208 self._validate_credentials() 209 return srv.CmdInterface.service_login(self.username, self.password, session_id)
210 211 # eval(func) must have session as first param
212 - def do_cmd(self, login_required, func, args, kwargs):
213 214 with self.CacheLock: 215 216 srv = self.get_connection_cache() 217 if srv == None: 218 srv = self.get_service_connection(timeout = 10) 219 if srv != None: self.cache_connection(srv) 220 else: 221 srv = srv['conn'] 222 223 if srv == None: 224 return False, 'no connection' 225 226 cmd_tuple = (login_required, func,) 227 new_session = False 228 session = self.get_session_cache(cmd_tuple) 229 if session == None: 230 new_session = True 231 session = srv.open_session() 232 if session == None: 233 return False, 'no session' 234 else: 235 if not srv.is_session_alive(session): 236 new_session = True 237 session = srv.open_session() 238 if session == None: 239 return False, 'no session' 240 self.set_session_cache(cmd_tuple, session) 241 242 self.update_connection_ts() 243 args.insert(0,session) 244 245 if login_required and new_session: 246 logged, error = self.login(srv, session) 247 if not logged: 248 srv.close_session(session) 249 self.remove_session_cache(cmd_tuple) 250 if not self.do_cache_connection: 251 srv.disconnect() 252 return False, error 253 254 cmd_func = getattr(srv.CmdInterface, func) 255 rslt = cmd_func(*args, **kwargs) 256 if not self.do_cache_session: 257 if login_required: 258 self.logout(srv, session) 259 srv.close_session(session) 260 if not self.do_cache_connection: 261 srv.disconnect() 262 return rslt
263
265 return self.Methods.available_commands.copy()
266