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