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

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

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com> 

# (c) 2015, 2017 Toshio Kuratomi <tkuratomi@ansible.com> 

# 

# This file is part of Ansible 

# 

# Ansible 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. 

# 

# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>. 

from __future__ import (absolute_import, division, print_function) 

__metaclass__ = type 

 

DOCUMENTATION = ''' 

connection: local 

short_description: execute on controller 

description: 

- This connection plugin allows ansible to execute tasks on the Ansible 'controller' instead of on a remote host. 

author: ansible (@core) 

version_added: historical 

notes: 

- The remote user is ignored, the user with which the ansible CLI was executed is used instead. 

''' 

 

import os 

import shutil 

import subprocess 

import fcntl 

import getpass 

 

import ansible.constants as C 

from ansible.compat import selectors 

from ansible.errors import AnsibleError, AnsibleFileNotFound 

from ansible.module_utils.six import text_type, binary_type 

from ansible.module_utils._text import to_bytes, to_native, to_text 

from ansible.plugins.connection import ConnectionBase 

 

 

try: 

from __main__ import display 

except ImportError: 

from ansible.utils.display import Display 

display = Display() 

 

 

class Connection(ConnectionBase): 

''' Local based connections ''' 

 

transport = 'local' 

has_pipelining = True 

 

def _connect(self): 

''' connect to the local host; nothing to do here ''' 

 

# Because we haven't made any remote connection we're running as 

# the local user, rather than as whatever is configured in 

# remote_user. 

self._play_context.remote_user = getpass.getuser() 

 

67 ↛ 70line 67 didn't jump to line 70, because the condition on line 67 was never false if not self._connected: 

display.vvv(u"ESTABLISH LOCAL CONNECTION FOR USER: {0}".format(self._play_context.remote_user), host=self._play_context.remote_addr) 

self._connected = True 

return self 

 

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

''' run a command on the local host ''' 

 

super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) 

 

display.debug("in local.exec_command()") 

 

executable = C.DEFAULT_EXECUTABLE.split()[0] if C.DEFAULT_EXECUTABLE else None 

 

display.vvv(u"EXEC {0}".format(to_text(cmd)), host=self._play_context.remote_addr) 

display.debug("opening command with Popen()") 

 

84 ↛ 87line 84 didn't jump to line 87, because the condition on line 84 was never false if isinstance(cmd, (text_type, binary_type)): 

cmd = to_bytes(cmd) 

else: 

cmd = map(to_bytes, cmd) 

 

p = subprocess.Popen( 

cmd, 

shell=isinstance(cmd, (text_type, binary_type)), 

executable=executable, # cwd=... 

stdin=subprocess.PIPE, 

stdout=subprocess.PIPE, 

stderr=subprocess.PIPE, 

) 

display.debug("done running command with Popen()") 

 

99 ↛ 100line 99 didn't jump to line 100, because the condition on line 99 was never true if self._play_context.prompt and sudoable: 

fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) 

fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) 

selector = selectors.DefaultSelector() 

selector.register(p.stdout, selectors.EVENT_READ) 

selector.register(p.stderr, selectors.EVENT_READ) 

 

become_output = b'' 

try: 

while not self.check_become_success(become_output) and not self.check_password_prompt(become_output): 

events = selector.select(self._play_context.timeout) 

if not events: 

stdout, stderr = p.communicate() 

raise AnsibleError('timeout waiting for privilege escalation password prompt:\n' + to_native(become_output)) 

 

for key, event in events: 

if key.fileobj == p.stdout: 

chunk = p.stdout.read() 

elif key.fileobj == p.stderr: 

chunk = p.stderr.read() 

 

if not chunk: 

stdout, stderr = p.communicate() 

raise AnsibleError('privilege output closed while waiting for password prompt:\n' + to_native(become_output)) 

become_output += chunk 

finally: 

selector.close() 

 

if not self.check_become_success(become_output): 

p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n') 

fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) 

fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK) 

 

display.debug("getting output with communicate()") 

stdout, stderr = p.communicate(in_data) 

display.debug("done communicating") 

 

display.debug("done with local.exec_command()") 

return (p.returncode, stdout, stderr) 

 

def put_file(self, in_path, out_path): 

''' transfer a file from local to local ''' 

 

super(Connection, self).put_file(in_path, out_path) 

 

display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._play_context.remote_addr) 

145 ↛ 146line 145 didn't jump to line 146, because the condition on line 145 was never true if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')): 

raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_native(in_path))) 

try: 

shutil.copyfile(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict')) 

except shutil.Error: 

raise AnsibleError("failed to copy: {0} and {1} are the same".format(to_native(in_path), to_native(out_path))) 

except IOError as e: 

raise AnsibleError("failed to transfer file to {0}: {1}".format(to_native(out_path), to_native(e))) 

 

def fetch_file(self, in_path, out_path): 

''' fetch a file from local to local -- for copatibility ''' 

 

super(Connection, self).fetch_file(in_path, out_path) 

 

display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self._play_context.remote_addr) 

self.put_file(in_path, out_path) 

 

def close(self): 

''' terminate the connection; nothing to do here ''' 

self._connected = False