1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
42
43 defaultSessionProfile = copy.deepcopy(_X2GO_SESSIONPROFILE_DEFAULTS)
44 _non_profile_sections = ('embedded')
45
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
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
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
106 self._init_profile_cache(profile_id)
107
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
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
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
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
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
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
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
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
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
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
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
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
397
398 @property
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
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
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
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
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
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
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
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
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
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
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
631 _profile_id = self.to_profile_id(profile_id_or_name)
632 elif self.has_profile_id(profile_id_or_name):
633
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
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
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
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
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
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
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
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
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
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
773 """\
774 Inherit from this class and provide a way for actually
775 providing such a PKey object.
776
777 """
778 return None
779