Hide keyboard shortcuts

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

# 2017 Red Hat Inc. 

# (c) 2017 Ansible Project 

# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 

 

from __future__ import (absolute_import, division, print_function) 

__metaclass__ = type 

 

DOCUMENTATION = """ 

author: Ansible Core Team 

connection: persistent 

short_description: Use a persistent unix socket for connection 

description: 

- This is a helper plugin to allow making other connections persistent. 

version_added: "2.3" 

""" 

import os 

import pty 

import json 

import subprocess 

 

from ansible import constants as C 

from ansible.plugins.connection import ConnectionBase 

from ansible.module_utils._text import to_text 

from ansible.module_utils.six.moves import cPickle 

from ansible.module_utils.connection import Connection as SocketConnection 

from ansible.errors import AnsibleError 

 

try: 

from __main__ import display 

except ImportError: 

from ansible.utils.display import Display 

display = Display() 

 

 

class Connection(ConnectionBase): 

''' Local based connections ''' 

 

transport = 'persistent' 

has_pipelining = False 

 

def _connect(self): 

self._connected = True 

return self 

 

def exec_command(self, cmd, in_data=None, sudoable=True): 

display.vvvv('exec_command(), socket_path=%s' % self.socket_path, host=self._play_context.remote_addr) 

connection = SocketConnection(self.socket_path) 

out = connection.exec_command(cmd, in_data=in_data, sudoable=sudoable) 

return 0, out, '' 

 

def put_file(self, in_path, out_path): 

pass 

 

def fetch_file(self, in_path, out_path): 

pass 

 

def close(self): 

self._connected = False 

 

def run(self): 

"""Returns the path of the persistent connection socket. 

 

Attempts to ensure (within playcontext.timeout seconds) that the 

socket path exists. If the path exists (or the timeout has expired), 

returns the socket path. 

""" 

display.vvvv('starting connection from persistent connection plugin', host=self._play_context.remote_addr) 

socket_path = self._start_connection() 

display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr) 

setattr(self, '_socket_path', socket_path) 

return socket_path 

 

def _start_connection(self): 

''' 

Starts the persistent connection 

''' 

master, slave = pty.openpty() 

p = subprocess.Popen(["ansible-connection", to_text(os.getppid())], stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

stdin = os.fdopen(master, 'wb', 0) 

os.close(slave) 

 

# Need to force a protocol that is compatible with both py2 and py3. 

# That would be protocol=2 or less. 

# Also need to force a protocol that excludes certain control chars as 

# stdin in this case is a pty and control chars will cause problems. 

# that means only protocol=0 will work. 

src = cPickle.dumps(self._play_context.serialize(), protocol=0) 

stdin.write(src) 

 

stdin.write(b'\n#END_INIT#\n') 

stdin.flush() 

 

(stdout, stderr) = p.communicate() 

stdin.close() 

 

96 ↛ 99line 96 didn't jump to line 99, because the condition on line 96 was never false if p.returncode == 0: 

result = json.loads(to_text(stdout, errors='surrogate_then_replace')) 

else: 

result = json.loads(to_text(stderr, errors='surrogate_then_replace')) 

 

101 ↛ 105line 101 didn't jump to line 105, because the condition on line 101 was never false if 'messages' in result: 

for msg in result.get('messages'): 

display.vvvv('%s' % msg, host=self._play_context.remote_addr) 

 

105 ↛ 106line 105 didn't jump to line 106, because the condition on line 105 was never true if 'error' in result: 

if self._play_context.verbosity > 2: 

msg = "The full traceback is:\n" + result['exception'] 

display.display(msg, color=C.COLOR_ERROR) 

raise AnsibleError(result['error']) 

 

return result['socket_path']