Updating connection plugins not yet updated in v2 to catch new code

This commit is contained in:
James Cammarata 2015-04-23 18:54:48 -05:00
parent 716a87ff36
commit 8c08f1b302
8 changed files with 255 additions and 87 deletions

View file

@ -14,8 +14,6 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json import json
import os import os
@ -52,6 +50,7 @@ class Connection(object):
self.accport = port[1] self.accport = port[1]
self.is_connected = False self.is_connected = False
self.has_pipelining = False self.has_pipelining = False
self.become_methods_supported=['sudo']
if not self.port: if not self.port:
self.port = constants.DEFAULT_REMOTE_PORT self.port = constants.DEFAULT_REMOTE_PORT
@ -142,7 +141,7 @@ class Connection(object):
# shutdown, so we'll reconnect. # shutdown, so we'll reconnect.
wrong_user = True wrong_user = True
except AnsibleError as e: except AnsibleError, e:
if allow_ssh: if allow_ssh:
if "WRONG_USER" in e: if "WRONG_USER" in e:
vvv("Switching users, waiting for the daemon on %s to shutdown completely..." % self.host) vvv("Switching users, waiting for the daemon on %s to shutdown completely..." % self.host)
@ -228,11 +227,11 @@ class Connection(object):
else: else:
return response.get('rc') == 0 return response.get('rc') == 0
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None):
''' run a command on the remote host ''' ''' run a command on the remote host '''
if su or su_user: if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise AnsibleError("Internal Error: this module does not support running commands via su") raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data: if in_data:
raise AnsibleError("Internal Error: this module does not support optimized module pipelining") raise AnsibleError("Internal Error: this module does not support optimized module pipelining")
@ -240,8 +239,8 @@ class Connection(object):
if executable == "": if executable == "":
executable = constants.DEFAULT_EXECUTABLE executable = constants.DEFAULT_EXECUTABLE
if self.runner.sudo and sudoable and sudo_user: if self.runner.become and sudoable:
cmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) cmd, prompt, success_key = utils.make_become_cmd(cmd, become_user, executable, self.runner.become_method, '', self.runner.become_exe)
vvv("EXEC COMMAND %s" % cmd) vvv("EXEC COMMAND %s" % cmd)
@ -294,8 +293,8 @@ class Connection(object):
if fd.tell() >= fstat.st_size: if fd.tell() >= fstat.st_size:
last = True last = True
data = dict(mode='put', data=base64.b64encode(data), out_path=out_path, last=last) data = dict(mode='put', data=base64.b64encode(data), out_path=out_path, last=last)
if self.runner.sudo: if self.runner.become:
data['user'] = self.runner.sudo_user data['user'] = self.runner.become_user
data = utils.jsonify(data) data = utils.jsonify(data)
data = utils.encrypt(self.key, data) data = utils.encrypt(self.key, data)

View file

@ -15,8 +15,6 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import distutils.spawn import distutils.spawn
import traceback import traceback
@ -26,6 +24,7 @@ import subprocess
from ansible import errors from ansible import errors
from ansible import utils from ansible import utils
from ansible.callbacks import vvv from ansible.callbacks import vvv
import ansible.constants as C
class Connection(object): class Connection(object):
''' Local chroot based connections ''' ''' Local chroot based connections '''
@ -33,6 +32,7 @@ class Connection(object):
def __init__(self, runner, host, port, *args, **kwargs): def __init__(self, runner, host, port, *args, **kwargs):
self.chroot = host self.chroot = host
self.has_pipelining = False self.has_pipelining = False
self.become_methods_supported=C.BECOME_METHODS
if os.geteuid() != 0: if os.geteuid() != 0:
raise errors.AnsibleError("chroot connection requires running as root") raise errors.AnsibleError("chroot connection requires running as root")
@ -62,16 +62,16 @@ class Connection(object):
return self return self
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None):
''' run a command on the chroot ''' ''' run a command on the chroot '''
if su or su_user: if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via su") raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data: if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
# We enter chroot as root so sudo stuff can be ignored # We enter chroot as root so we ignore privlege escalation?
if executable: if executable:
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd] local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]

View file

@ -18,9 +18,6 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# --- # ---
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# The func transport permit to use ansible over func. For people who have already setup # The func transport permit to use ansible over func. For people who have already setup
# func and that wish to play with ansible, this permit to move gradually to ansible # func and that wish to play with ansible, this permit to move gradually to ansible
# without having to redo completely the setup of the network. # without having to redo completely the setup of the network.
@ -56,16 +53,14 @@ class Connection(object):
self.client = fc.Client(self.host) self.client = fc.Client(self.host)
return self return self
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False,
executable='/bin/sh', in_data=None, su=None, su_user=None): executable='/bin/sh', in_data=None):
''' run a command on the remote minion ''' ''' run a command on the remote minion '''
if su or su_user:
raise errors.AnsibleError("Internal Error: this module does not support running commands via su")
if in_data: if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
# totally ignores privlege escalation
vvv("EXEC %s" % (cmd), host=self.host) vvv("EXEC %s" % (cmd), host=self.host)
p = self.client.command.run(cmd)[self.host] p = self.client.command.run(cmd)[self.host]
return (p[0], '', p[1], p[2]) return (p[0], '', p[1], p[2])

View file

@ -16,8 +16,6 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import distutils.spawn import distutils.spawn
import traceback import traceback
@ -26,6 +24,7 @@ import shutil
import subprocess import subprocess
from ansible import errors from ansible import errors
from ansible.callbacks import vvv from ansible.callbacks import vvv
import ansible.constants as C
class Connection(object): class Connection(object):
''' Local chroot based connections ''' ''' Local chroot based connections '''
@ -63,6 +62,7 @@ class Connection(object):
self.runner = runner self.runner = runner
self.host = host self.host = host
self.has_pipelining = False self.has_pipelining = False
self.become_methods_supported=C.BECOME_METHODS
if os.geteuid() != 0: if os.geteuid() != 0:
raise errors.AnsibleError("jail connection requires running as root") raise errors.AnsibleError("jail connection requires running as root")
@ -93,16 +93,16 @@ class Connection(object):
local_cmd = '%s "%s" %s' % (self.jexec_cmd, self.jail, cmd) local_cmd = '%s "%s" %s' % (self.jexec_cmd, self.jail, cmd)
return local_cmd return local_cmd
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None):
''' run a command on the chroot ''' ''' run a command on the chroot '''
if su or su_user: if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via su") raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data: if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
# We enter chroot as root so sudo stuff can be ignored # Ignores privilege escalation
local_cmd = self._generate_cmd(executable, cmd) local_cmd = self._generate_cmd(executable, cmd)
vvv("EXEC %s" % (local_cmd), host=self.jail) vvv("EXEC %s" % (local_cmd), host=self.jail)

View file

@ -16,14 +16,13 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import distutils.spawn import distutils.spawn
import os import os
import subprocess import subprocess
from ansible import errors from ansible import errors
from ansible.callbacks import vvv from ansible.callbacks import vvv
import ansible.constants as C
class Connection(object): class Connection(object):
''' Local lxc based connections ''' ''' Local lxc based connections '''
@ -52,6 +51,7 @@ class Connection(object):
self.host = host self.host = host
# port is unused, since this is local # port is unused, since this is local
self.port = port self.port = port
self.become_methods_supported=C.BECOME_METHODS
def connect(self, port=None): def connect(self, port=None):
''' connect to the lxc; nothing to do here ''' ''' connect to the lxc; nothing to do here '''
@ -67,16 +67,16 @@ class Connection(object):
local_cmd = '%s -q -c lxc:/// lxc-enter-namespace %s -- %s' % (self.cmd, self.lxc, cmd) local_cmd = '%s -q -c lxc:/// lxc-enter-namespace %s -- %s' % (self.cmd, self.lxc, cmd)
return local_cmd return local_cmd
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user, sudoable=False, executable='/bin/sh', in_data=None):
''' run a command on the chroot ''' ''' run a command on the chroot '''
if su or su_user: if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via su") raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data: if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
# We enter lxc as root so sudo stuff can be ignored # We ignore privelege escalation!
local_cmd = self._generate_cmd(executable, cmd) local_cmd = self._generate_cmd(executable, cmd)
vvv("EXEC %s" % (local_cmd), host=self.lxc) vvv("EXEC %s" % (local_cmd), host=self.lxc)

View file

@ -14,8 +14,7 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# --- # ---
# The paramiko transport is provided because many distributions, in particular EL6 and before # The paramiko transport is provided because many distributions, in particular EL6 and before
@ -126,6 +125,9 @@ class Connection(object):
self.private_key_file = private_key_file self.private_key_file = private_key_file
self.has_pipelining = False self.has_pipelining = False
# TODO: add pbrun, pfexec
self.become_methods_supported=['sudo', 'su', 'pbrun']
def _cache_key(self): def _cache_key(self):
return "%s__%s__" % (self.host, self.user) return "%s__%s__" % (self.host, self.user)
@ -171,7 +173,7 @@ class Connection(object):
key_filename=key_filename, password=self.password, key_filename=key_filename, password=self.password,
timeout=self.runner.timeout, port=self.port) timeout=self.runner.timeout, port=self.port)
except Exception as e: except Exception, e:
msg = str(e) msg = str(e)
if "PID check failed" in msg: if "PID check failed" in msg:
@ -185,9 +187,12 @@ class Connection(object):
return ssh return ssh
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None):
''' run a command on the remote host ''' ''' run a command on the remote host '''
if self.runner.become and sudoable and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data: if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
@ -198,7 +203,7 @@ class Connection(object):
self.ssh.get_transport().set_keepalive(5) self.ssh.get_transport().set_keepalive(5)
chan = self.ssh.get_transport().open_session() chan = self.ssh.get_transport().open_session()
except Exception as e: except Exception, e:
msg = "Failed to open session" msg = "Failed to open session"
if len(str(e)) > 0: if len(str(e)) > 0:
@ -207,7 +212,7 @@ class Connection(object):
no_prompt_out = '' no_prompt_out = ''
no_prompt_err = '' no_prompt_err = ''
if not (self.runner.sudo and sudoable) and not (self.runner.su and su): if not (self.runner.become and sudoable):
if executable: if executable:
quoted_command = executable + ' -c ' + pipes.quote(cmd) quoted_command = executable + ' -c ' + pipes.quote(cmd)
@ -225,50 +230,46 @@ class Connection(object):
chan.get_pty(term=os.getenv('TERM', 'vt100'), chan.get_pty(term=os.getenv('TERM', 'vt100'),
width=int(os.getenv('COLUMNS', 0)), width=int(os.getenv('COLUMNS', 0)),
height=int(os.getenv('LINES', 0))) height=int(os.getenv('LINES', 0)))
if self.runner.sudo or sudoable: if self.runner.become and sudoable:
shcmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd) shcmd, prompt, success_key = utils.make_become_cmd(cmd, become_user, executable, self.runner.become_method, '', self.runner.become_exe)
elif self.runner.su or su:
shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
vvv("EXEC %s" % shcmd, host=self.host) vvv("EXEC %s" % shcmd, host=self.host)
sudo_output = '' become_output = ''
try: try:
chan.exec_command(shcmd) chan.exec_command(shcmd)
if self.runner.sudo_pass or self.runner.su_pass: if self.runner.become_pass:
while True: while True:
if success_key in sudo_output or \ if success_key in become_output or \
(self.runner.sudo_pass and sudo_output.endswith(prompt)) or \ (prompt and become_output.endswith(prompt)) or \
(self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)): utils.su_prompts.check_su_prompt(become_output):
break break
chunk = chan.recv(bufsize) chunk = chan.recv(bufsize)
if not chunk: if not chunk:
if 'unknown user' in sudo_output: if 'unknown user' in become_output:
raise errors.AnsibleError( raise errors.AnsibleError(
'user %s does not exist' % sudo_user) 'user %s does not exist' % become_user)
else: else:
raise errors.AnsibleError('ssh connection ' + raise errors.AnsibleError('ssh connection ' +
'closed waiting for password prompt') 'closed waiting for password prompt')
sudo_output += chunk become_output += chunk
if success_key not in sudo_output: if success_key not in become_output:
if sudoable: if sudoable:
chan.sendall(self.runner.sudo_pass + '\n') chan.sendall(self.runner.become_pass + '\n')
elif su:
chan.sendall(self.runner.su_pass + '\n')
else: else:
no_prompt_out += sudo_output no_prompt_out += become_output
no_prompt_err += sudo_output no_prompt_err += become_output
except socket.timeout: except socket.timeout:
raise errors.AnsibleError('ssh timed out waiting for sudo.\n' + sudo_output) raise errors.AnsibleError('ssh timed out waiting for privilege escalation.\n' + become_output)
stdout = ''.join(chan.makefile('rb', bufsize)) stdout = ''.join(chan.makefile('rb', bufsize))
stderr = ''.join(chan.makefile_stderr('rb', bufsize)) stderr = ''.join(chan.makefile_stderr('rb', bufsize))
@ -285,7 +286,7 @@ class Connection(object):
try: try:
self.sftp = self.ssh.open_sftp() self.sftp = self.ssh.open_sftp()
except Exception as e: except Exception, e:
raise errors.AnsibleError("failed to open a SFTP connection (%s)" % e) raise errors.AnsibleError("failed to open a SFTP connection (%s)" % e)
try: try:
@ -309,7 +310,7 @@ class Connection(object):
try: try:
self.sftp = self._connect_sftp() self.sftp = self._connect_sftp()
except Exception as e: except Exception, e:
raise errors.AnsibleError("failed to open a SFTP connection (%s)", e) raise errors.AnsibleError("failed to open a SFTP connection (%s)", e)
try: try:

View file

@ -14,18 +14,15 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type from __future__ import absolute_import
import base64 import base64
import hashlib
import imp
import os import os
import re import re
import shlex import shlex
import traceback import traceback
import urlparse
from six.moves.urllib import parse as urlparse
from ansible import errors from ansible import errors
from ansible import utils from ansible import utils
from ansible.callbacks import vvv, vvvv, verbose from ansible.callbacks import vvv, vvvv, verbose
@ -38,9 +35,12 @@ try:
except ImportError: except ImportError:
raise errors.AnsibleError("winrm is not installed") raise errors.AnsibleError("winrm is not installed")
_winrm_cache = { HAVE_KERBEROS = False
# 'user:pwhash@host:port': <protocol instance> try:
} import kerberos
HAVE_KERBEROS = True
except ImportError:
pass
def vvvvv(msg, host=None): def vvvvv(msg, host=None):
verbose(msg, host=host, caplevel=4) verbose(msg, host=host, caplevel=4)
@ -48,6 +48,11 @@ def vvvvv(msg, host=None):
class Connection(object): class Connection(object):
'''WinRM connections over HTTP/HTTPS.''' '''WinRM connections over HTTP/HTTPS.'''
transport_schemes = {
'http': [('kerberos', 'http'), ('plaintext', 'http'), ('plaintext', 'https')],
'https': [('kerberos', 'https'), ('plaintext', 'https')],
}
def __init__(self, runner, host, port, user, password, *args, **kwargs): def __init__(self, runner, host, port, user, password, *args, **kwargs):
self.runner = runner self.runner = runner
self.host = host self.host = host
@ -61,6 +66,10 @@ class Connection(object):
self.shell_id = None self.shell_id = None
self.delegate = None self.delegate = None
# Add runas support
#self.become_methods_supported=['runas']
self.become_methods_supported=[]
def _winrm_connect(self): def _winrm_connect(self):
''' '''
Establish a WinRM connection over HTTP/HTTPS. Establish a WinRM connection over HTTP/HTTPS.
@ -69,23 +78,22 @@ class Connection(object):
vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \
(self.user, port, self.host), host=self.host) (self.user, port, self.host), host=self.host)
netloc = '%s:%d' % (self.host, port) netloc = '%s:%d' % (self.host, port)
cache_key = '%s:%s@%s:%d' % (self.user, hashlib.md5(self.password).hexdigest(), self.host, port)
if cache_key in _winrm_cache:
vvvv('WINRM REUSE EXISTING CONNECTION: %s' % cache_key, host=self.host)
return _winrm_cache[cache_key]
transport_schemes = [('plaintext', 'https'), ('plaintext', 'http')] # FIXME: ssl/kerberos
if port == 5985:
transport_schemes = reversed(transport_schemes)
exc = None exc = None
for transport, scheme in transport_schemes: for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']:
if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self.user):
continue
if transport == 'kerberos':
realm = self.user.split('@', 1)[1].strip() or None
else:
realm = None
endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', ''))
vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint),
host=self.host) host=self.host)
protocol = Protocol(endpoint, transport=transport, protocol = Protocol(endpoint, transport=transport,
username=self.user, password=self.password) username=self.user, password=self.password,
realm=realm)
try: try:
protocol.send_message('') protocol.send_message('')
_winrm_cache[cache_key] = protocol
return protocol return protocol
except WinRMTransportError, exc: except WinRMTransportError, exc:
err_msg = str(exc) err_msg = str(exc)
@ -97,7 +105,6 @@ class Connection(object):
if code == 401: if code == 401:
raise errors.AnsibleError("the username/password specified for this server was incorrect") raise errors.AnsibleError("the username/password specified for this server was incorrect")
elif code == 411: elif code == 411:
_winrm_cache[cache_key] = protocol
return protocol return protocol
vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host)
continue continue
@ -133,7 +140,11 @@ class Connection(object):
self.protocol = self._winrm_connect() self.protocol = self._winrm_connect()
return self return self
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable=None, in_data=None, su=None, su_user=None): def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable=None, in_data=None):
if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
cmd = cmd.encode('utf-8') cmd = cmd.encode('utf-8')
cmd_parts = shlex.split(cmd, posix=False) cmd_parts = shlex.split(cmd, posix=False)
if '-EncodedCommand' in cmd_parts: if '-EncodedCommand' in cmd_parts:
@ -144,11 +155,11 @@ class Connection(object):
vvv("EXEC %s" % cmd, host=self.host) vvv("EXEC %s" % cmd, host=self.host)
# For script/raw support. # For script/raw support.
if cmd_parts and cmd_parts[0].lower().endswith('.ps1'): if cmd_parts and cmd_parts[0].lower().endswith('.ps1'):
script = powershell._build_file_cmd(cmd_parts) script = powershell._build_file_cmd(cmd_parts, quote_args=False)
cmd_parts = powershell._encode_script(script, as_list=True) cmd_parts = powershell._encode_script(script, as_list=True)
try: try:
result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True)
except Exception as e: except Exception, e:
traceback.print_exc() traceback.print_exc()
raise errors.AnsibleError("failed to exec cmd %s" % cmd) raise errors.AnsibleError("failed to exec cmd %s" % cmd)
return (result.status_code, '', result.std_out.encode('utf-8'), result.std_err.encode('utf-8')) return (result.status_code, '', result.std_out.encode('utf-8'), result.std_err.encode('utf-8'))
@ -194,7 +205,7 @@ class Connection(object):
def fetch_file(self, in_path, out_path): def fetch_file(self, in_path, out_path):
out_path = out_path.replace('\\', '/') out_path = out_path.replace('\\', '/')
vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
buffer_size = 2**20 # 1MB chunks buffer_size = 2**19 # 0.5MB chunks
if not os.path.exists(os.path.dirname(out_path)): if not os.path.exists(os.path.dirname(out_path)):
os.makedirs(os.path.dirname(out_path)) os.makedirs(os.path.dirname(out_path))
out_file = None out_file = None

View file

@ -0,0 +1,162 @@
# Based on local.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
# and chroot.py (c) 2013, Maykel Moya <mmoya@speedyrails.com>
# and jail.py (c) 2013, Michael Scherer <misc@zarb.org>
# (c) 2015, Dagobert Michelsen <dam@baltic-online.de>
#
# 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/>.
import distutils.spawn
import traceback
import os
import shutil
import subprocess
from subprocess import Popen,PIPE
from ansible import errors
from ansible.callbacks import vvv
import ansible.constants as C
class Connection(object):
''' Local zone based connections '''
def _search_executable(self, executable):
cmd = distutils.spawn.find_executable(executable)
if not cmd:
raise errors.AnsibleError("%s command not found in PATH") % executable
return cmd
def list_zones(self):
pipe = subprocess.Popen([self.zoneadm_cmd, 'list', '-ip'],
cwd=self.runner.basedir,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#stdout, stderr = p.communicate()
zones = []
for l in pipe.stdout.readlines():
# 1:work:running:/zones/work:3126dc59-9a07-4829-cde9-a816e4c5040e:native:shared
s = l.split(':')
if s[1] != 'global':
zones.append(s[1])
return zones
def get_zone_path(self):
#solaris10vm# zoneadm -z cswbuild list -p
#-:cswbuild:installed:/zones/cswbuild:479f3c4b-d0c6-e97b-cd04-fd58f2c0238e:native:shared
pipe = subprocess.Popen([self.zoneadm_cmd, '-z', self.zone, 'list', '-p'],
cwd=self.runner.basedir,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#stdout, stderr = p.communicate()
path = pipe.stdout.readlines()[0].split(':')[3]
return path + '/root'
def __init__(self, runner, host, port, *args, **kwargs):
self.zone = host
self.runner = runner
self.host = host
self.has_pipelining = False
self.become_methods_supported=C.BECOME_METHODS
if os.geteuid() != 0:
raise errors.AnsibleError("zone connection requires running as root")
self.zoneadm_cmd = self._search_executable('zoneadm')
self.zlogin_cmd = self._search_executable('zlogin')
if not self.zone in self.list_zones():
raise errors.AnsibleError("incorrect zone name %s" % self.zone)
self.host = host
# port is unused, since this is local
self.port = port
def connect(self, port=None):
''' connect to the zone; nothing to do here '''
vvv("THIS IS A LOCAL ZONE DIR", host=self.zone)
return self
# a modifier
def _generate_cmd(self, executable, cmd):
if executable:
local_cmd = [self.zlogin_cmd, self.zone, executable, cmd]
else:
local_cmd = '%s "%s" %s' % (self.zlogin_cmd, self.zone, cmd)
return local_cmd
def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable=None, in_data=None):
''' run a command on the zone '''
if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported:
raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)
if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
# We happily ignore privelege escalation
if executable == '/bin/sh':
executable = None
local_cmd = self._generate_cmd(executable, cmd)
vvv("EXEC %s" % (local_cmd), host=self.zone)
p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
cwd=self.runner.basedir,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
return (p.returncode, '', stdout, stderr)
def _normalize_path(self, path, prefix):
if not path.startswith(os.path.sep):
path = os.path.join(os.path.sep, path)
normpath = os.path.normpath(path)
return os.path.join(prefix, normpath[1:])
def _copy_file(self, in_path, out_path):
if not os.path.exists(in_path):
raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path)
try:
shutil.copyfile(in_path, out_path)
except shutil.Error:
traceback.print_exc()
raise errors.AnsibleError("failed to copy: %s and %s are the same" % (in_path, out_path))
except IOError:
traceback.print_exc()
raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def put_file(self, in_path, out_path):
''' transfer a file from local to zone '''
out_path = self._normalize_path(out_path, self.get_zone_path())
vvv("PUT %s TO %s" % (in_path, out_path), host=self.zone)
self._copy_file(in_path, out_path)
def fetch_file(self, in_path, out_path):
''' fetch a file from zone to local '''
in_path = self._normalize_path(in_path, self.get_zone_path())
vvv("FETCH %s TO %s" % (in_path, out_path), host=self.zone)
self._copy_file(in_path, out_path)
def close(self):
''' terminate the connection; nothing to do here '''
pass