... | ... |
@@ -21,6 +21,7 @@ __metaclass__ = type |
21 | 21 |
|
22 | 22 |
import distutils.spawn |
23 | 23 |
import os |
24 |
+import os.path |
|
24 | 25 |
import subprocess |
25 | 26 |
import traceback |
26 | 27 |
|
... | ... |
@@ -83,8 +84,6 @@ class Connection(ConnectionBase): |
83 | 83 |
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd] |
84 | 84 |
|
85 | 85 |
self._display.vvv("EXEC %s" % (local_cmd), host=self.chroot) |
86 |
- # FIXME: cwd= needs to be set to the basedir of the playbook, which |
|
87 |
- # should come from loader, but is not in the connection plugins |
|
88 | 86 |
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin, |
89 | 87 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
90 | 88 |
|
... | ... |
@@ -99,12 +98,26 @@ class Connection(ConnectionBase): |
99 | 99 |
stdout, stderr = p.communicate(in_data) |
100 | 100 |
return (p.returncode, stdout, stderr) |
101 | 101 |
|
102 |
+ def _prefix_login_path(self, remote_path): |
|
103 |
+ ''' Make sure that we put files into a standard path |
|
104 |
+ |
|
105 |
+ If a path is relative, then we need to choose where to put it. |
|
106 |
+ ssh chooses $HOME but we aren't guaranteed that a home dir will |
|
107 |
+ exist in any given chroot. So for now we're choosing "/" instead. |
|
108 |
+ This also happens to be the former default. |
|
109 |
+ |
|
110 |
+ Can revisit using $HOME instead if it's a problem |
|
111 |
+ ''' |
|
112 |
+ if not remote_path.startswith(os.path.sep): |
|
113 |
+ remote_path = os.path.join(os.path.sep, remote_path) |
|
114 |
+ return os.path.normpath(remote_path) |
|
115 |
+ |
|
102 | 116 |
def put_file(self, in_path, out_path): |
103 | 117 |
''' transfer a file from local to chroot ''' |
104 | 118 |
super(Connection, self).put_file(in_path, out_path) |
105 |
- |
|
106 | 119 |
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot) |
107 | 120 |
|
121 |
+ out_path = self._prefix_login_path(out_path) |
|
108 | 122 |
try: |
109 | 123 |
with open(in_path, 'rb') as in_file: |
110 | 124 |
try: |
... | ... |
@@ -124,9 +137,9 @@ class Connection(ConnectionBase): |
124 | 124 |
def fetch_file(self, in_path, out_path): |
125 | 125 |
''' fetch a file from chroot to local ''' |
126 | 126 |
super(Connection, self).fetch_file(in_path, out_path) |
127 |
- |
|
128 | 127 |
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot) |
129 | 128 |
|
129 |
+ in_path = self._prefix_login_path(in_path) |
|
130 | 130 |
try: |
131 | 131 |
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE)) |
132 | 132 |
except OSError: |
... | ... |
@@ -26,19 +26,20 @@ __metaclass__ = type |
26 | 26 |
|
27 | 27 |
import distutils.spawn |
28 | 28 |
import os |
29 |
+import os.path |
|
29 | 30 |
import subprocess |
30 | 31 |
import re |
31 | 32 |
|
32 | 33 |
from distutils.version import LooseVersion |
33 | 34 |
|
34 | 35 |
import ansible.constants as C |
35 |
- |
|
36 | 36 |
from ansible.errors import AnsibleError, AnsibleFileNotFound |
37 | 37 |
from ansible.plugins.connection import ConnectionBase |
38 | 38 |
|
39 | 39 |
BUFSIZE = 65536 |
40 | 40 |
|
41 | 41 |
class Connection(ConnectionBase): |
42 |
+ ''' Local docker based connections ''' |
|
42 | 43 |
|
43 | 44 |
transport = 'docker' |
44 | 45 |
has_pipelining = True |
... | ... |
@@ -53,9 +54,11 @@ class Connection(ConnectionBase): |
53 | 53 |
# Note: docker supports running as non-root in some configurations. |
54 | 54 |
# (For instance, setting the UNIX socket file to be readable and |
55 | 55 |
# writable by a specific UNIX group and then putting users into that |
56 |
- # group). But if the user is getting a permission denied error it |
|
57 |
- # probably means that docker on their system is only configured to be |
|
58 |
- # connected to by root and they are not running as root. |
|
56 |
+ # group). Therefore we don't check that the user is root when using |
|
57 |
+ # this connection. But if the user is getting a permission denied |
|
58 |
+ # error it probably means that docker on their system is only |
|
59 |
+ # configured to be connected to by root and they are not running as |
|
60 |
+ # root. |
|
59 | 61 |
|
60 | 62 |
if 'docker_command' in kwargs: |
61 | 63 |
self.docker_cmd = kwargs['docker_command'] |
... | ... |
@@ -79,7 +82,6 @@ class Connection(ConnectionBase): |
79 | 79 |
def _get_docker_version(self): |
80 | 80 |
|
81 | 81 |
cmd = [self.docker_cmd, 'version'] |
82 |
- |
|
83 | 82 |
cmd_output = subprocess.check_output(cmd) |
84 | 83 |
|
85 | 84 |
for line in cmd_output.split('\n'): |
... | ... |
@@ -106,7 +108,7 @@ class Connection(ConnectionBase): |
106 | 106 |
self._connected = True |
107 | 107 |
|
108 | 108 |
def exec_command(self, cmd, in_data=None, sudoable=False): |
109 |
- """ Run a command on the local host """ |
|
109 |
+ """ Run a command on the docker host """ |
|
110 | 110 |
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) |
111 | 111 |
|
112 | 112 |
executable = C.DEFAULT_EXECUTABLE.split()[0] if C.DEFAULT_EXECUTABLE else '/bin/sh' |
... | ... |
@@ -114,22 +116,32 @@ class Connection(ConnectionBase): |
114 | 114 |
local_cmd = [self.docker_cmd, "exec", '-i', self._play_context.remote_addr, executable, '-c', cmd] |
115 | 115 |
|
116 | 116 |
self._display.vvv("EXEC %s" % (local_cmd), host=self._play_context.remote_addr) |
117 |
- # FIXME: cwd= needs to be set to the basedir of the playbook, which |
|
118 |
- # should come from loader, but is not in the connection plugins |
|
119 |
- p = subprocess.Popen(local_cmd, |
|
120 |
- shell=False, |
|
121 |
- stdin=subprocess.PIPE, |
|
117 |
+ p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE, |
|
122 | 118 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
123 | 119 |
|
124 | 120 |
stdout, stderr = p.communicate(in_data) |
125 | 121 |
return (p.returncode, stdout, stderr) |
126 | 122 |
|
123 |
+ def _prefix_login_path(self, remote_path): |
|
124 |
+ ''' Make sure that we put files into a standard path |
|
125 |
+ |
|
126 |
+ If a path is relative, then we need to choose where to put it. |
|
127 |
+ ssh chooses $HOME but we aren't guaranteed that a home dir will |
|
128 |
+ exist in any given chroot. So for now we're choosing "/" instead. |
|
129 |
+ This also happens to be the former default. |
|
130 |
+ |
|
131 |
+ Can revisit using $HOME instead if it's a problem |
|
132 |
+ ''' |
|
133 |
+ if not remote_path.startswith(os.path.sep): |
|
134 |
+ remote_path = os.path.join(os.path.sep, remote_path) |
|
135 |
+ return os.path.normpath(remote_path) |
|
136 |
+ |
|
127 | 137 |
def put_file(self, in_path, out_path): |
128 |
- """ Transfer a file from local to container """ |
|
138 |
+ """ Transfer a file from local to docker container """ |
|
129 | 139 |
super(Connection, self).put_file(in_path, out_path) |
130 |
- |
|
131 | 140 |
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) |
132 | 141 |
|
142 |
+ out_path = self._prefix_login_path(out_path) |
|
133 | 143 |
if not os.path.exists(in_path): |
134 | 144 |
raise AnsibleFileNotFound( |
135 | 145 |
"file or module does not exist: %s" % in_path) |
... | ... |
@@ -161,9 +173,9 @@ class Connection(ConnectionBase): |
161 | 161 |
def fetch_file(self, in_path, out_path): |
162 | 162 |
""" Fetch a file from container to local. """ |
163 | 163 |
super(Connection, self).fetch_file(in_path, out_path) |
164 |
- |
|
165 | 164 |
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) |
166 | 165 |
|
166 |
+ in_path = self._prefix_login_path(in_path) |
|
167 | 167 |
# out_path is the final file path, but docker takes a directory, not a |
168 | 168 |
# file path |
169 | 169 |
out_dir = os.path.dirname(out_path) |
... | ... |
@@ -22,6 +22,7 @@ __metaclass__ = type |
22 | 22 |
|
23 | 23 |
import distutils.spawn |
24 | 24 |
import os |
25 |
+import os.path |
|
25 | 26 |
import subprocess |
26 | 27 |
import traceback |
27 | 28 |
|
... | ... |
@@ -67,8 +68,6 @@ class Connection(ConnectionBase): |
67 | 67 |
return cmd |
68 | 68 |
|
69 | 69 |
def list_jails(self): |
70 |
- # FIXME: cwd= needs to be set to the basedir of the playbook, which |
|
71 |
- # should come from loader, but is not in the connection plugins |
|
72 | 70 |
p = subprocess.Popen([self.jls_cmd, '-q', 'name'], |
73 | 71 |
stdin=subprocess.PIPE, |
74 | 72 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
... | ... |
@@ -78,8 +77,6 @@ class Connection(ConnectionBase): |
78 | 78 |
return stdout.split() |
79 | 79 |
|
80 | 80 |
def get_jail_path(self): |
81 |
- # FIXME: cwd= needs to be set to the basedir of the playbook, which |
|
82 |
- # should come from loader, but is not in the connection plugins |
|
83 | 81 |
p = subprocess.Popen([self.jls_cmd, '-j', self.jail, '-q', 'path'], |
84 | 82 |
stdin=subprocess.PIPE, |
85 | 83 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
... | ... |
@@ -107,8 +104,6 @@ class Connection(ConnectionBase): |
107 | 107 |
local_cmd = [self.jexec_cmd, self.jail, executable, '-c', cmd] |
108 | 108 |
|
109 | 109 |
self._display.vvv("EXEC %s" % (local_cmd), host=self.jail) |
110 |
- # FIXME: cwd= needs to be set to the basedir of the playbook, which |
|
111 |
- # should come from loader, but is not in the connection plugins |
|
112 | 110 |
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin, |
113 | 111 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
114 | 112 |
|
... | ... |
@@ -130,11 +125,26 @@ class Connection(ConnectionBase): |
130 | 130 |
stdout, stderr = p.communicate(in_data) |
131 | 131 |
return (p.returncode, stdout, stderr) |
132 | 132 |
|
133 |
+ def _prefix_login_path(self, remote_path): |
|
134 |
+ ''' Make sure that we put files into a standard path |
|
135 |
+ |
|
136 |
+ If a path is relative, then we need to choose where to put it. |
|
137 |
+ ssh chooses $HOME but we aren't guaranteed that a home dir will |
|
138 |
+ exist in any given chroot. So for now we're choosing "/" instead. |
|
139 |
+ This also happens to be the former default. |
|
140 |
+ |
|
141 |
+ Can revisit using $HOME instead if it's a problem |
|
142 |
+ ''' |
|
143 |
+ if not remote_path.startswith(os.path.sep): |
|
144 |
+ remote_path = os.path.join(os.path.sep, remote_path) |
|
145 |
+ return os.path.normpath(remote_path) |
|
146 |
+ |
|
133 | 147 |
def put_file(self, in_path, out_path): |
134 | 148 |
''' transfer a file from local to jail ''' |
135 | 149 |
super(Connection, self).put_file(in_path, out_path) |
136 | 150 |
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.jail) |
137 | 151 |
|
152 |
+ out_path = self._prefix_login_path(out_path) |
|
138 | 153 |
try: |
139 | 154 |
with open(in_path, 'rb') as in_file: |
140 | 155 |
try: |
... | ... |
@@ -156,6 +166,7 @@ class Connection(ConnectionBase): |
156 | 156 |
super(Connection, self).fetch_file(in_path, out_path) |
157 | 157 |
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.jail) |
158 | 158 |
|
159 |
+ in_path = self._prefix_login_path(in_path) |
|
159 | 160 |
try: |
160 | 161 |
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE)) |
161 | 162 |
except OSError: |
... | ... |
@@ -23,6 +23,7 @@ __metaclass__ = type |
23 | 23 |
|
24 | 24 |
import distutils.spawn |
25 | 25 |
import os |
26 |
+import os.path |
|
26 | 27 |
import subprocess |
27 | 28 |
import traceback |
28 | 29 |
|
... | ... |
@@ -116,8 +117,6 @@ class Connection(ConnectionBase): |
116 | 116 |
local_cmd = [self.zlogin_cmd, self.zone, executable, '-c', cmd] |
117 | 117 |
|
118 | 118 |
self._display.vvv("EXEC %s" % (local_cmd), host=self.zone) |
119 |
- # FIXME: cwd= should be set to the basedir of the playbook, which |
|
120 |
- # should come from loader but is not in the connection plugins |
|
121 | 119 |
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin, |
122 | 120 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
123 | 121 |
|
... | ... |
@@ -139,11 +138,26 @@ class Connection(ConnectionBase): |
139 | 139 |
stdout, stderr = p.communicate(in_data) |
140 | 140 |
return (p.returncode, stdout, stderr) |
141 | 141 |
|
142 |
+ def _prefix_login_path(self, remote_path): |
|
143 |
+ ''' Make sure that we put files into a standard path |
|
144 |
+ |
|
145 |
+ If a path is relative, then we need to choose where to put it. |
|
146 |
+ ssh chooses $HOME but we aren't guaranteed that a home dir will |
|
147 |
+ exist in any given chroot. So for now we're choosing "/" instead. |
|
148 |
+ This also happens to be the former default. |
|
149 |
+ |
|
150 |
+ Can revisit using $HOME instead if it's a problem |
|
151 |
+ ''' |
|
152 |
+ if not remote_path.startswith(os.path.sep): |
|
153 |
+ remote_path = os.path.join(os.path.sep, remote_path) |
|
154 |
+ return os.path.normpath(remote_path) |
|
155 |
+ |
|
142 | 156 |
def put_file(self, in_path, out_path): |
143 | 157 |
''' transfer a file from local to zone ''' |
144 | 158 |
super(Connection, self).put_file(in_path, out_path) |
145 | 159 |
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.zone) |
146 | 160 |
|
161 |
+ out_path = self._prefix_login_path(out_path) |
|
147 | 162 |
try: |
148 | 163 |
with open(in_path, 'rb') as in_file: |
149 | 164 |
try: |
... | ... |
@@ -165,6 +179,7 @@ class Connection(ConnectionBase): |
165 | 165 |
super(Connection, self).fetch_file(in_path, out_path) |
166 | 166 |
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.zone) |
167 | 167 |
|
168 |
+ in_path = self._prefix_login_path(in_path) |
|
168 | 169 |
try: |
169 | 170 |
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE)) |
170 | 171 |
except OSError: |