Package x2go :: Package backends :: Package profiles :: Module base
[frames] | no frames]

Source Code for Module x2go.backends.profiles.base

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2014 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2Go is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU Affero General Public License as published by 
  7  # the Free Software Foundation; either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2Go is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU Affero General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU Affero General Public License 
 16  # along with this program; if not, write to the 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19   
 20  """\ 
 21  L{X2GoSessionProfiles} class - managing x2goclient session profiles. 
 22   
 23  L{X2GoSessionProfiles} is a public API class. Use this class in your Python X2Go based  
 24  applications. 
 25   
 26  """ 
 27  __NAME__ = 'x2gosessionprofiles-pylib' 
 28   
 29  import copy 
 30  import types 
 31  import re 
 32   
 33  # Python X2Go modules 
 34  from x2go.defaults import X2GO_SESSIONPROFILE_DEFAULTS as _X2GO_SESSIONPROFILE_DEFAULTS 
 35  from x2go.defaults import X2GO_DESKTOPSESSIONS as _X2GO_DESKTOPSESSIONS 
 36  import x2go.log as log 
 37  import x2go.utils as utils 
 38   
 39  from x2go.x2go_exceptions import X2GoProfileException 
40 41 -class X2GoSessionProfiles():
42 43 defaultSessionProfile = copy.deepcopy(_X2GO_SESSIONPROFILE_DEFAULTS) 44 _non_profile_sections = ('embedded') 45
46 - def __init__(self, session_profile_defaults=None, logger=None, loglevel=log.loglevel_DEFAULT, **kwargs):
47 """\ 48 Retrieve X2Go session profiles. Base class for the different specific session profile 49 configuration backends. 50 51 @param session_profile_defaults: a default session profile 52 @type session_profile_defaults: C{dict} 53 @param logger: you can pass an L{X2GoLogger} object to the 54 L{x2go.backends.profiles.httpbroker.X2GoSessionProfiles} constructor 55 @type logger: L{X2GoLogger} instance 56 @param loglevel: if no L{X2GoLogger} object has been supplied a new one will be 57 constructed with the given loglevel 58 @type loglevel: C{int} 59 60 """ 61 self.defaultValues = {} 62 self._profile_metatypes = {} 63 self._cached_profile_ids = {} 64 self.__useexports = {} 65 self._profiles_need_profile_id_renewal = [] 66 self.write_user_config = False 67 68 if logger is None: 69 self.logger = log.X2GoLogger(loglevel=loglevel) 70 else: 71 self.logger = copy.deepcopy(logger) 72 self.logger.tag = __NAME__ 73 74 if utils._checkSessionProfileDefaults(session_profile_defaults): 75 self.defaultSessionProfile = session_profile_defaults 76 77 self.populate_session_profiles()
78
79 - def __call__(self, profile_id_or_name):
80 """\ 81 Retrieve the session profile configuration for a given session profile ID (or name) 82 83 @param profile_id_or_name: profile ID or profile name 84 @type profile_id_or_name: C{str} 85 86 @return: the profile ID's / name's profile configuration 87 @rtype: C{dict} 88 89 """ 90 _profile_id = self.check_profile_id_or_name(self, profile_id_or_name) 91 return self.get_profile_config(profile_id=_profile_id)
92
93 - def init_profile_cache(self, profile_id_or_name):
94 """\ 95 Some session profile backends (e.g. the broker backends cache 96 dynamic session profile data). On new connections, it is 97 recommented to (re-)initialize these caches. 98 99 @param profile_id_or_name: profile ID or profile name 100 @type profile_id_or_name: C{str} 101 102 """ 103 profile_id = self.check_profile_id_or_name(profile_id_or_name) 104 105 # allow backend specific clean-up 106 self._init_profile_cache(profile_id)
107
108 - def _init_profile_cache(self, profile_id):
109 """\ 110 Inherit from this class to (re-)initialize profile ID based 111 cache storage. 112 113 """ 114 pass
115
117 """\ 118 Load a session profile set from the configuration storage 119 backend and make it available for this class. 120 121 @return: a set of session profiles 122 @rtype: C{dict} 123 124 """ 125 self.session_profiles = self. _populate_session_profiles() 126 127 # scan for duplicate profile names and handle them... 128 scan_profile_names = {} 129 for profile_id in self.session_profiles.keys(): 130 profile_name = self.to_profile_name(profile_id) 131 if profile_name not in scan_profile_names.keys(): 132 scan_profile_names[profile_name] = [profile_id] 133 else: 134 scan_profile_names[profile_name].append(profile_id) 135 _duplicates = {} 136 for profile_name in scan_profile_names.keys(): 137 if len(scan_profile_names[profile_name]) > 1: 138 _duplicates[profile_name] = scan_profile_names[profile_name] 139 for profile_name in _duplicates.keys(): 140 i = 1 141 for profile_id in _duplicates[profile_name]: 142 self.update_value(None, 'name', '{name} ({i})'.format(name=profile_name, i=i), profile_id=profile_id) 143 i += 1
144
146 """\ 147 Inherit from this class and provide the backend specific way of loading / 148 populating a set of session profile via this method. 149 150 @return: a set of session profiles 151 @rtype: C{dict} 152 153 """ 154 return {}
155
156 - def get_profile_metatype(self, profile_id_or_name, force=False):
157 """\ 158 Detect a human readable session profile type from the session profile configuration. 159 160 @param profile_id_or_name: profile ID or profile name 161 @type profile_id_or_name: C{str} 162 @param force: re-detect the meta type, otherwise use a cached result 163 @type force: C{bool} 164 165 @return: the profile ID's / name's meta type 166 @rtype: C{str} 167 168 """ 169 _profile_id = self.check_profile_id_or_name(profile_id_or_name) 170 171 if not self._profile_metatypes.has_key(_profile_id) or force: 172 _config = self.get_profile_config(_profile_id) 173 if _config['host']: 174 if _config['rdpserver'] and _config['command'] == 'RDP': 175 _metatype = 'RDP/proxy' 176 elif _config['published']: 177 178 if _config['command'] in _X2GO_DESKTOPSESSIONS.keys(): 179 _metatype = '%s + Published Applications' % _config['command'] 180 else: 181 _metatype = 'Published Applications' 182 183 elif _config['rootless']: 184 _metatype = 'Single Applications' 185 elif _config['command'] in _X2GO_DESKTOPSESSIONS.keys(): 186 _metatype = '%s Desktop' % _config['command'] 187 elif _config['command'] in _X2GO_DESKTOPSESSIONS.values(): 188 _metatype = '%s Desktop' % [ s for s in _X2GO_DESKTOPSESSIONS.keys() if _config['command'] == _X2GO_DESKTOPSESSIONS[s] ][0] 189 else: 190 _metatype = 'CUSTOM Desktop' 191 else: 192 if _config['rdpserver'] and _config['command'] == 'RDP': 193 _metatype = 'RDP/direct' 194 else: 195 _metatype = 'not supported' 196 self._profile_metatypes[_profile_id] = unicode(_metatype) 197 else: 198 return self._profile_metatypes[_profile_id]
199
200 - def is_mutable(self, profile_id_or_name=None, profile_id=None):
201 """\ 202 Check if a given profile name (or ID) is mutable or not. 203 204 @param profile_id_or_name: profile name or profile ID 205 @type profile_id_or_name: C{str} 206 @param profile_id: if the profile ID is known, pass it in directly and skip 207 the L{check_profile_id_or_name()} call 208 @type profile_id: C{str} 209 210 @return: C{True} if the session profile of the specified name/ID is mutable 211 @rtype: C{bool} 212 213 @raise X2GoProfileException: if no such session profile exists 214 215 """ 216 try: 217 profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) 218 return self._is_mutable(profile_id) 219 except X2GoProfileException: 220 return None
221
222 - def _is_mutable(self, profile_id):
223 """\ 224 Inherit from this base class and provide your own decision making 225 code here if a given profile ID is mutable or not. 226 227 @param profile_id: profile ID 228 @type profile_id: C{str} 229 230 @return: C{True} if the session profile of the specified ID is mutable 231 @rtype: C{bool} 232 233 """ 234 return False
235
237 """\ 238 Check if the current session profile backend supports 239 mutable session profiles. 240 241 @return: list of mutable profiles 242 @rtype: C{list} 243 244 """ 245 return self._supports_mutable_profiles()
246
248 """\ 249 Inherit from this base class and provide your own decision making 250 code here if a your session profile backend supports mutable 251 session profiles or not. 252 253 @return: list of mutable profiles 254 @rtype: C{list} 255 256 """ 257 return False
258
259 - def mutable_profile_ids(self):
260 """\ 261 List all mutable session profiles. 262 263 @return: List up all session profile IDs of mutable session profiles. 264 @rtype: C{bool} 265 266 """ 267 return [ p for p in self.profile_ids if self._is_mutable(p) ]
268
269 - def write(self):
270 """\ 271 Store session profile data to the storage backend. 272 273 @return: C{True} if the write process has been successfull, C{False} otherwise 274 @rtype: C{bool} 275 276 """ 277 # then update profile IDs for profiles that have a renamed host attribute... 278 for profile_id in self._profiles_need_profile_id_renewal: 279 _config = self.get_profile_config(profile_id=profile_id) 280 281 self._delete_profile(profile_id) 282 283 try: del self._cached_profile_ids[profile_id] 284 except KeyError: pass 285 self.add_profile(profile_id=None, force_add=True, **_config) 286 287 self._profiles_need_profile_id_renewal = [] 288 self._cached_profile_ids = {} 289 290 return self._write()
291
292 - def _write(self):
293 """\ 294 Write session profiles back to session profile storage backend. Inherit from this 295 class and adapt to the session profile backend via this method. 296 297 """ 298 return True
299
300 - def get_profile_option_type(self, option):
301 """\ 302 Get the data type for a specific session profile option. 303 304 @param option: the option to get the data type for 305 @type option: will be detected by this method 306 307 @return: the data type of C{option} 308 @rtype: C{type} 309 310 """ 311 try: 312 return type(self.defaultSessionProfile[option]) 313 except KeyError: 314 return types.StringType
315
316 - def get_profile_config(self, profile_id_or_name=None, parameter=None, profile_id=None):
317 """\ 318 The configuration options for a single session profile. 319 320 @param profile_id_or_name: either profile ID or profile name is accepted 321 @type profile_id_or_name: C{str} 322 @param parameter: if specified, only the value for the given parameter is returned 323 @type parameter: C{str} 324 @param profile_id: profile ID (faster than specifying C{profile_id_or_name}) 325 @type profile_id: C{str} 326 327 @return: the session profile configuration for the given profile ID (or name) 328 @rtype: C{dict} 329 330 """ 331 _profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) 332 _profile_config = {} 333 if parameter is None: 334 parameters = self._get_profile_options(_profile_id) 335 else: 336 parameters = [parameter] 337 for option in parameters: 338 value = self._get_profile_parameter(_profile_id, option, key_type=self.get_profile_option_type(option)) 339 340 if type(value) is types.StringType: 341 value = unicode(value) 342 343 if option == 'export' and type(value) is types.UnicodeType: 344 345 _value = value.replace(',', ';').strip().strip('"').strip().strip(';').strip() 346 value = {} 347 if _value: 348 _export_paths = _value.split(';') 349 for _path in _export_paths: 350 if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path 351 _auto_export_path = re.match('.*:1$', _path) and True or False 352 _export_path = ':'.join(_path.split(':')[:-1]) 353 value[_export_path] = _auto_export_path 354 355 _profile_config[option] = value 356 357 if parameter is not None: 358 if parameter in _profile_config.keys(): 359 value = _profile_config[parameter] 360 return value 361 else: 362 raise X2GoProfileException('no such session profile parameter: %s' % parameter) 363 364 return _profile_config
365
366 - def default_profile_config(self):
367 """\ 368 Return a default session profile. 369 370 @return: default session profile 371 @rtype: C{dict} 372 373 """ 374 return copy.deepcopy(self.defaultSessionProfile)
375
376 - def has_profile(self, profile_id_or_name):
377 """\ 378 Does a session profile of a given profile ID or profile name exist? 379 380 @param profile_id_or_name: profile ID or profile name 381 @type profile_id_or_name: C{str} 382 383 @return: C{True} if there is such a session profile, C{False} otherwise 384 @rtype: C{bool} 385 386 """ 387 try: 388 self.check_profile_id_or_name(profile_id_or_name) 389 return True 390 except X2GoProfileException: 391 return False
392
394 for p in self._get_profile_ids(): 395 if p not in self._non_profile_sections: 396 self._cached_profile_ids[p] = self.to_profile_name(p)
397 398 @property
399 - def profile_ids(self):
400 """\ 401 Render a list of all profile IDs found in the session profiles configuration. 402 403 """ 404 if not self._cached_profile_ids: 405 self._update_profile_ids_cache() 406 return self._cached_profile_ids.keys()
407
408 - def _get_profile_ids(self):
409 """\ 410 Inherit from this class and provide a way for actually getting 411 a list of session profile IDs from the storage backend via this method. 412 413 @return: list of available session profile IDs 414 @rtype: C{list} 415 416 """ 417 return []
418
419 - def has_profile_id(self, profile_id):
420 """\ 421 Does a session profile of a given profile ID exist? (Faster than L{has_profile()}.) 422 423 @param profile_id: profile ID 424 @type profile_id: C{str} 425 426 @return: C{True} if there is such a session profile, C{False} otherwise 427 @rtype: C{bool} 428 429 """ 430 return unicode(profile_id) in self.profile_ids
431 432 @property
433 - def profile_names(self):
434 """\ 435 Render a list of all profile names found in the session profiles configuration. 436 437 """ 438 if not self._cached_profile_ids: 439 self._update_profile_ids_cache() 440 return self._cached_profile_ids.values()
441
442 - def has_profile_name(self, profile_name):
443 """\ 444 Does a session profile of a given profile name exist? (Faster than L{has_profile()}.) 445 446 @param profile_name: profile name 447 @type profile_name: C{str} 448 449 @return: C{True} if there is such a session profile, C{False} otherwise 450 @rtype: C{bool} 451 452 """ 453 return unicode(profile_name) in self.profile_names
454
455 - def to_profile_id(self, profile_name):
456 """\ 457 Convert profile name to profile ID. 458 459 @param profile_name: profile name 460 @type profile_name: C{str} 461 462 @return: profile ID 463 @rtype: C{str} 464 465 """ 466 _profile_ids = [ p for p in self.profile_ids if self._cached_profile_ids[p] == profile_name ] 467 if len(_profile_ids) == 1: 468 return unicode(_profile_ids[0]) 469 elif len(_profile_ids) == 0: 470 return None 471 else: 472 raise X2GoProfileException('The sessions config file contains multiple session profiles with name: %s' % profile_name)
473
474 - def to_profile_name(self, profile_id):
475 """\ 476 Convert profile ID to profile name. 477 478 @param profile_id: profile ID 479 @type profile_id: C{str} 480 481 @return: profile name 482 @rtype: C{str} 483 484 """ 485 try: 486 _profile_name = self.get_profile_config(profile_id=profile_id, parameter='name') 487 return unicode(_profile_name) 488 except: 489 return u''
490
491 - def add_profile(self, profile_id=None, force_add=False, **kwargs):
492 """\ 493 Add a new session profile. 494 495 @param profile_id: a custom profile ID--if left empty a profile ID will be auto-generated 496 @type profile_id: C{str} 497 @param kwargs: session profile options for this new session profile 498 @type kwargs: C{dict} 499 500 @return: the (auto-generated) profile ID of the new session profile 501 @rtype: C{str} 502 503 """ 504 if profile_id is None or profile_id in self.profile_ids: 505 profile_id = utils._genSessionProfileId() 506 self.session_profiles[profile_id] = self.default_profile_config() 507 508 if 'name' not in kwargs.keys(): 509 raise X2GoProfileException('session profile parameter ,,name\'\' is missing in method parameters') 510 511 if kwargs['name'] in self.profile_names and not force_add: 512 raise X2GoProfileException('a profile of name ,,%s\'\' already exists' % kwargs['name']) 513 514 self._cached_profile_ids[profile_id] = kwargs['name'] 515 516 for key, value in kwargs.items(): 517 self.update_value(None, key, value, profile_id=profile_id) 518 519 _default_session_profile = self.default_profile_config() 520 for key, value in _default_session_profile.items(): 521 if key in kwargs: continue 522 self.update_value(None, key, value, profile_id=profile_id) 523 524 self._cached_profile_ids = {} 525 526 return unicode(profile_id)
527
528 - def delete_profile(self, profile_id_or_name):
529 """\ 530 Delete a session profile from the configuration file. 531 532 @param profile_id_or_name: profile ID or profile name 533 @type profile_id_or_name: C{str} 534 535 """ 536 _profile_id = self.check_profile_id_or_name(profile_id_or_name) 537 538 self._delete_profile(_profile_id) 539 540 self.write_user_config = True 541 self.write() 542 self._cached_profile_ids = {}
543
544 - def _delete_profile(self, profile_id):
545 """\ 546 Inherit from this class and provide a way for actually deleting 547 a complete session profile from the storage backend via this method. 548 549 """ 550 pass
551
552 - def update_value(self, profile_id_or_name, option, value, profile_id=None):
553 """\ 554 Update a value in a session profile. 555 556 @param profile_id_or_name: the profile ID 557 @type profile_id_or_name: C{str} 558 @param option: the session profile option of the given profile ID 559 @type option: C{str} 560 @param value: the value to update the session profile option with 561 @type value: any type, depends on the session profile option 562 @param profile_id: if the profile ID is known, pass it in directly and skip 563 the L{check_profile_id_or_name()} call 564 @type profile_id: C{str} 565 566 """ 567 try: 568 profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) 569 except X2GoProfileException: 570 profile_id = profile_id_or_name 571 572 if not self.is_mutable(profile_id=profile_id): 573 raise X2GoProfileException("session profile cannot be modified, it is marked as immutable") 574 575 if option == 'name': 576 profile_name = value 577 current_profile_name = self.get_value(profile_id, option) 578 if not profile_name: 579 raise X2GoProfileException('profile name for profile id %s must not be empty' % profile_id) 580 else: 581 if profile_name != current_profile_name: 582 try: del self._cached_profile_ids[profile_id] 583 except KeyError: pass 584 if profile_name in self.profile_names: 585 raise X2GoProfileException('a profile of name ,,%s\'\' already exists' % profile_name) 586 self._cached_profile_ids[profile_id] = profile_name 587 588 if option == 'export' and type(value) == types.DictType: 589 _strvalue = '"' 590 for folder in value.keys(): 591 _strvalue += "%s:%s;" % (folder, int(value[folder])) 592 _strvalue += '"' 593 _strvalue = _strvalue.replace('""', '') 594 value = _strvalue 595 596 if option == 'host': 597 _host = self.get_profile_config(profile_id=profile_id, parameter='host') 598 if _host != value and _host is not None: 599 self._profiles_need_profile_id_renewal.append(profile_id) 600 if type(value) is types.TupleType: 601 value = list(value) 602 if type(value) is not types.ListType: 603 value = value.split(',') 604 605 self._update_value(profile_id, option, value)
606
607 - def _update_value(self, profile_id, option, value):
608 """\ 609 Inherit from this class and provide for actually updating 610 a session profile's value in the storage backend via this method. 611 612 """ 613 pass
614
615 - def check_profile_id_or_name(self, profile_id_or_name):
616 """\ 617 Detect the profile ID from a given string which maybe profile ID or profile name. 618 619 @param profile_id_or_name: profile ID or profile name 620 @type profile_id_or_name: C{str} 621 622 @return: profile ID 623 @rtype: C{str} 624 625 @raise X2GoProfileException: if no such session profile exists 626 627 """ 628 _profile_id = None 629 if self.has_profile_name(profile_id_or_name): 630 # we were given a sesion profile name... 631 _profile_id = self.to_profile_id(profile_id_or_name) 632 elif self.has_profile_id(profile_id_or_name): 633 # we were given a session profile id... 634 _profile_id = profile_id_or_name 635 else: 636 raise X2GoProfileException('No session profile with id or name ,,%s\'\' exists.' % profile_id_or_name) 637 if _profile_id is not None: 638 _profile_id = unicode(_profile_id) 639 return _profile_id
640
641 - def to_session_params(self, profile_id_or_name=None, profile_id=None):
642 """\ 643 Convert session profile options to L{X2GoSession} constructor method parameters. 644 645 @param profile_id_or_name: either profile ID or profile name is accepted 646 @type profile_id_or_name: C{str} 647 @param profile_id: profile ID (fast than specifying C{profile_id_or_name}) 648 @type profile_id: C{str} 649 650 @return: a dictionary of L{X2GoSession} constructor method parameters 651 @rtype: C{dict} 652 653 """ 654 _profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) 655 return utils._convert_SessionProfileOptions_2_SessionParams(self.get_profile_config(_profile_id))
656
657 - def get_session_param(self, profile_id_or_name, param):
658 """\ 659 Get a single L{X2GoSession} parameter from a specific session profile. 660 661 @param profile_id_or_name: either profile ID or profile name is accepted 662 @type profile_id_or_name: C{str} 663 @param param: the parameter name in the L{X2GoSession} constructor method 664 @type param: C{str} 665 666 @return: the value of the session profile option represented by C{param} 667 @rtype: depends on the session profile option requested 668 669 """ 670 return self.to_session_params(profile_id_or_name)[param]
671
672 - def _get_profile_parameter(self, profile_id, option, key_type):
673 """\ 674 Inherit from this class and provide a way for actually obtaining 675 the value of a specific profile parameter. 676 677 @param profile_id: the profile's unique ID 678 @type profile_id: C{str} 679 @param option: the session profile option for which to retrieve its value 680 @type option: C{str} 681 @param key_type: type of the value to return 682 @type key_type: C{typeobject} 683 684 @return: value of a session profile parameter 685 @rtype: C{various types} 686 687 """ 688 return None
689
690 - def _get_profile_options(self, profile_id):
691 """\ 692 Inherit from this class and provide a way for actually obtaining 693 a list of available profile options of a given session profile. 694 695 @return: list of available option is the given session profile 696 @rtype: C{list} 697 698 """ 699 return []
700
701 - def get_server_hostname(self, profile_id):
702 """\ 703 Retrieve host name of the X2Go Server configured in a session profile. 704 705 @param profile_id: the profile's unique ID 706 @type profile_id: C{str} 707 708 @return: the host name of the X2Go Server configured by the session profile 709 of the given profile ID 710 @rtype: C{list} 711 712 """ 713 return unicode(self._get_server_hostname(profile_id))
714
715 - def _get_server_hostname(self, profile_id):
716 """\ 717 Inherit from this class and provide a way for actually obtaining 718 a the server host name for a given profile ID. 719 720 @param profile_id: the profile's unique ID 721 @type profile_id: C{str} 722 723 @return: the host name of the X2Go Server configured by the session profile 724 of the given profile ID 725 @rtype: C{list} 726 727 """ 728 return u'localhost'
729
730 - def get_server_port(self, profile_id):
731 """\ 732 Retrieve SSH port of the X2Go Server configured in a session profile. 733 734 @param profile_id: the profile's unique ID 735 @type profile_id: C{str} 736 737 @return: the SSH port of the X2Go Server configured by the session profile 738 of the given profile ID 739 @rtype: C{list} 740 741 """ 742 return self._get_server_port(profile_id)
743
744 - def _get_server_port(self, profile_id):
745 """\ 746 Inherit from this class and provide a way for actually obtaining 747 a the server SSH port for a given profile ID. 748 749 @param profile_id: the profile's unique ID 750 @type profile_id: C{str} 751 752 @return: the SSH port of the X2Go Server configured by the session profile 753 of the given profile ID 754 @rtype: C{list} 755 756 """ 757 return 22
758
759 - def get_pkey_object(self, profile_id):
760 """\ 761 If available, return a PKey (Paramiko/SSH private key) object. 762 763 @param profile_id: the profile's unique ID 764 @type profile_id: C{str} 765 766 @return: a Paramiko/SSH PKey object 767 @rtype: C{obj} 768 769 """ 770 return self._get_pkey_object(profile_id)
771
772 - def _get_pkey_object(self, profile_id):
773 """\ 774 Inherit from this class and provide a way for actually 775 providing such a PKey object. 776 777 """ 778 return None
779