Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

# Authors: 

#   Jason Gerard DeRose <jderose@redhat.com> 

# 

# Copyright (C) 2008  Red Hat 

# see file 'COPYING' for use and warranty information 

# 

# This program is free software; you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# This program is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 

# GNU General Public License for more details. 

# 

# You should have received a copy of the GNU General Public License 

# along with this program.  If not, see <http://www.gnu.org/licenses/>. 

 

""" 

Base classes for all backed-end plugins. 

""" 

 

import threading 

import plugable 

import os 

from errors import PublicError, InternalError, CommandError 

from request import context, Connection, destroy_context 

 

 

class Backend(plugable.Plugin): 

    """ 

    Base class for all backend plugins. 

    """ 

 

 

class Connectible(Backend): 

    """ 

    Base class for backend plugins that create connections. 

 

    In addition to the nicety of providing a standard connection API, all 

    backend plugins that create connections should use this base class so that 

    `request.destroy_context()` can properly close all open connections. 

    """ 

 

    def __init__(self, shared_instance=True): 

        Backend.__init__(self) 

        if shared_instance: 

            self.id = self.name 

        else: 

            self.id = '%s_%s' % (self.name, str(id(self))) 

 

    def connect(self, *args, **kw): 

        """ 

        Create thread-local connection. 

        """ 

        if hasattr(context, self.id): 

            raise StandardError( 

                "connect: 'context.%s' already exists in thread %r" % ( 

                    self.id, threading.currentThread().getName() 

                ) 

            ) 

        conn = self.create_connection(*args, **kw) 

        setattr(context, self.id, Connection(conn, self.disconnect)) 

        assert self.conn is conn 

        self.debug('Created connection context.%s' % self.id) 

 

    def create_connection(self, *args, **kw): 

        raise NotImplementedError('%s.create_connection()' % self.id) 

 

    def disconnect(self): 

        if not hasattr(context, self.id): 

            raise StandardError( 

                "disconnect: 'context.%s' does not exist in thread %r" % ( 

                    self.id, threading.currentThread().getName() 

                ) 

            ) 

        self.destroy_connection() 

        delattr(context, self.id) 

        self.debug('Destroyed connection context.%s' % self.id) 

 

    def destroy_connection(self): 

        raise NotImplementedError('%s.destroy_connection()' % self.id) 

 

    def isconnected(self): 

        """ 

        Return ``True`` if thread-local connection on `request.context` exists. 

        """ 

        return hasattr(context, self.id) 

 

    def __get_conn(self): 

        """ 

        Return thread-local connection. 

        """ 

        if not hasattr(context, self.id): 

            raise AttributeError('no context.%s in thread %r' % ( 

                self.id, threading.currentThread().getName()) 

            ) 

        return getattr(context, self.id).conn 

    conn = property(__get_conn) 

 

 

class Executioner(Backend): 

 

    def create_context(self, ccache=None, client_ip=None): 

        """ 

        client_ip: The IP address of the remote client. 

        """ 

 

        if ccache is not None: 

            os.environ["KRB5CCNAME"] = ccache 

 

        if self.env.in_server: 

            self.Backend.ldap2.connect(ccache=ccache) 

        else: 

            self.Backend.xmlclient.connect(verbose=(self.env.verbose >= 2), 

                fallback=self.env.fallback, delegate=self.env.delegate) 

        if client_ip is not None: 

            setattr(context, "client_ip", client_ip) 

 

    def destroy_context(self): 

        destroy_context() 

 

    def execute(self, _name, *args, **options): 

        error = None 

        try: 

            if _name not in self.Command: 

                raise CommandError(name=_name) 

            result = self.Command[_name](*args, **options) 

        except PublicError, e: 

            error = e 

        except StandardError, e: 

            self.exception( 

                'non-public: %s: %s', e.__class__.__name__, str(e) 

            ) 

            error = InternalError() 

        except Exception, e: 

            self.exception( 

                'unhandled exception: %s: %s', e.__class__.__name__, str(e) 

            ) 

            error = InternalError() 

        destroy_context() 

        if error is None: 

            return result 

        assert isinstance(error, PublicError) 

        raise error #pylint: disable=E0702