Improve error handling in for ssh_raw/rsync in ansible/puppet/bash
This commit is contained in:
parent
08c040c530
commit
99f1ccd1a2
@ -19,7 +19,6 @@ import os
|
|||||||
from solar.core.handlers.base import SOLAR_TEMP_LOCAL_LOCATION
|
from solar.core.handlers.base import SOLAR_TEMP_LOCAL_LOCATION
|
||||||
from solar.core.handlers.base import TempFileHandler
|
from solar.core.handlers.base import TempFileHandler
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar import errors
|
|
||||||
|
|
||||||
# otherwise fabric will sys.exit(1) in case of errors
|
# otherwise fabric will sys.exit(1) in case of errors
|
||||||
env.warn_only = True
|
env.warn_only = True
|
||||||
@ -40,7 +39,8 @@ class AnsibleTemplate(TempFileHandler):
|
|||||||
self._copy_templates_and_scripts(resource, action_name)
|
self._copy_templates_and_scripts(resource, action_name)
|
||||||
self.transport_sync.copy(resource, self.dst, '/tmp')
|
self.transport_sync.copy(resource, self.dst, '/tmp')
|
||||||
self.transport_sync.copy(resource, '/vagrant/library', '/tmp')
|
self.transport_sync.copy(resource, '/vagrant/library', '/tmp')
|
||||||
self.transport_sync.sync_all()
|
sync_results = self.transport_sync.sync_all()
|
||||||
|
self.verify_sync_results(sync_results)
|
||||||
|
|
||||||
# remote paths are not nested inside solar_local
|
# remote paths are not nested inside solar_local
|
||||||
remote_playbook_file = playbook_file.replace(
|
remote_playbook_file = playbook_file.replace(
|
||||||
@ -52,15 +52,8 @@ class AnsibleTemplate(TempFileHandler):
|
|||||||
'-i', remote_inventory_file, remote_playbook_file]
|
'-i', remote_inventory_file, remote_playbook_file]
|
||||||
log.debug('EXECUTING: %s', ' '.join(call_args))
|
log.debug('EXECUTING: %s', ' '.join(call_args))
|
||||||
|
|
||||||
out = self.transport_run.run(resource, *call_args)
|
rst = self.transport_run.run(resource, *call_args)
|
||||||
log.debug(out)
|
self.verify_run_result(call_args, rst)
|
||||||
if out.failed:
|
|
||||||
raise errors.SolarError(out)
|
|
||||||
|
|
||||||
# with fabric_api.shell_env(ANSIBLE_HOST_KEY_CHECKING='False'):
|
|
||||||
# out = fabric_api.local(' '.join(call_args), capture=True)
|
|
||||||
# if out.failed:
|
|
||||||
# raise errors.SolarError(out)
|
|
||||||
|
|
||||||
def _create_inventory(self, r):
|
def _create_inventory(self, r):
|
||||||
directory = self.dirs[r.name]
|
directory = self.dirs[r.name]
|
||||||
|
@ -21,6 +21,7 @@ import tempfile
|
|||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar.core.transports.ssh import SSHRunTransport
|
from solar.core.transports.ssh import SSHRunTransport
|
||||||
from solar.core.transports.ssh import SSHSyncTransport
|
from solar.core.transports.ssh import SSHSyncTransport
|
||||||
|
from solar import errors
|
||||||
from solar import utils
|
from solar import utils
|
||||||
|
|
||||||
|
|
||||||
@ -42,6 +43,22 @@ class BaseHandler(object):
|
|||||||
self.transport_sync.bind_with(self.transport_run)
|
self.transport_sync.bind_with(self.transport_run)
|
||||||
self.transport_run.bind_with(self.transport_sync)
|
self.transport_run.bind_with(self.transport_sync)
|
||||||
|
|
||||||
|
def verify_sync_results(self, results):
|
||||||
|
for result in results:
|
||||||
|
if isinstance(result, tuple) and len(result) == 3:
|
||||||
|
# TODO Include file information in result
|
||||||
|
rc, out, err = result
|
||||||
|
log.debug('RC %s OUT %s ERR %s', rc, out, err)
|
||||||
|
if rc:
|
||||||
|
raise errors.SolarError(err)
|
||||||
|
|
||||||
|
def verify_run_result(self, cmd, result):
|
||||||
|
rc, out, err = result
|
||||||
|
log.debug('CMD %r RC %s OUT %s ERR %s', cmd, rc, out, err)
|
||||||
|
if rc:
|
||||||
|
message = 'CMD %r failed RC %s ERR %s' % (cmd, rc, err)
|
||||||
|
raise errors.SolarError(message)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -27,4 +27,5 @@ class NaiveSync(BaseHandler):
|
|||||||
# to understand where src comes from
|
# to understand where src comes from
|
||||||
for item in args['sources']:
|
for item in args['sources']:
|
||||||
self.transport_sync.copy(resource, item['src'], item['dst'])
|
self.transport_sync.copy(resource, item['src'], item['dst'])
|
||||||
self.transport_sync.sync_all()
|
results = self.transport_sync.sync_all()
|
||||||
|
self.verify_sync_results(results)
|
||||||
|
@ -37,7 +37,8 @@ class Puppet(TempFileHandler):
|
|||||||
|
|
||||||
self.prepare_templates_and_scripts(resource, action_file, '')
|
self.prepare_templates_and_scripts(resource, action_file, '')
|
||||||
self.transport_sync.copy(resource, action_file, action_file_name)
|
self.transport_sync.copy(resource, action_file, action_file_name)
|
||||||
self.transport_sync.sync_all()
|
sync_results = self.transport_sync.sync_all()
|
||||||
|
self.verify_sync_results(sync_results)
|
||||||
|
|
||||||
cmd_args = ['puppet', 'apply', '-vd',
|
cmd_args = ['puppet', 'apply', '-vd',
|
||||||
action_file_name,
|
action_file_name,
|
||||||
@ -46,7 +47,7 @@ class Puppet(TempFileHandler):
|
|||||||
cmd_args.append('--modulepath={}'.format(
|
cmd_args.append('--modulepath={}'.format(
|
||||||
resource.args['puppet_modules']))
|
resource.args['puppet_modules']))
|
||||||
|
|
||||||
cmd = self.transport_run.run(
|
rc, out, err = self.transport_run.run(
|
||||||
resource,
|
resource,
|
||||||
*cmd_args,
|
*cmd_args,
|
||||||
env={
|
env={
|
||||||
@ -55,12 +56,12 @@ class Puppet(TempFileHandler):
|
|||||||
use_sudo=True,
|
use_sudo=True,
|
||||||
warn_only=True
|
warn_only=True
|
||||||
)
|
)
|
||||||
|
log.debug('CMD %r RC %s OUT %s ERR %s', cmd_args, rc, out, err)
|
||||||
# 0 - no changes, 2 - successfull changes
|
# 0 - no changes, 2 - successfull changes
|
||||||
if cmd.return_code not in [0, 2]:
|
if rc not in [0, 2]:
|
||||||
raise errors.SolarError(
|
raise errors.SolarError(
|
||||||
'Puppet for {} failed with {}'.format(
|
'Puppet for {} failed with RC {}'.format(
|
||||||
resource.name, cmd.return_code))
|
resource.name, rc))
|
||||||
return cmd
|
|
||||||
|
|
||||||
def _make_args(self, resource):
|
def _make_args(self, resource):
|
||||||
return {resource.name: {'input': resource.args}}
|
return {resource.name: {'input': resource.args}}
|
||||||
|
@ -18,7 +18,6 @@ import os
|
|||||||
from solar.core.handlers.base import SOLAR_TEMP_LOCAL_LOCATION
|
from solar.core.handlers.base import SOLAR_TEMP_LOCAL_LOCATION
|
||||||
from solar.core.handlers.base import TempFileHandler
|
from solar.core.handlers.base import TempFileHandler
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar import errors
|
|
||||||
|
|
||||||
|
|
||||||
class Shell(TempFileHandler):
|
class Shell(TempFileHandler):
|
||||||
@ -34,17 +33,14 @@ class Shell(TempFileHandler):
|
|||||||
self._copy_templates_and_scripts(resource, action_name)
|
self._copy_templates_and_scripts(resource, action_name)
|
||||||
|
|
||||||
self.transport_sync.copy(resource, self.dst, '/tmp')
|
self.transport_sync.copy(resource, self.dst, '/tmp')
|
||||||
self.transport_sync.sync_all()
|
sync_results = self.transport_sync.sync_all()
|
||||||
|
# TODO Include file information in result
|
||||||
|
self.verify_sync_results(sync_results)
|
||||||
|
|
||||||
cmd = self.transport_run.run(
|
rst = self.transport_run.run(
|
||||||
resource,
|
resource,
|
||||||
'bash', action_file_name,
|
'bash', action_file_name,
|
||||||
use_sudo=True,
|
use_sudo=True,
|
||||||
warn_only=True
|
warn_only=True
|
||||||
)
|
)
|
||||||
|
self.verify_run_results(['bash', action_file_name], rst)
|
||||||
if cmd.return_code:
|
|
||||||
raise errors.SolarError(
|
|
||||||
'Bash execution for {} failed with {}'.format(
|
|
||||||
resource.name, cmd.return_code))
|
|
||||||
return cmd
|
|
||||||
|
@ -38,7 +38,7 @@ class Executor(object):
|
|||||||
|
|
||||||
def run(self, transport):
|
def run(self, transport):
|
||||||
if self.valid:
|
if self.valid:
|
||||||
self._executor(transport)
|
return self._executor(transport)
|
||||||
|
|
||||||
|
|
||||||
class SolarRunResultWrp(object):
|
class SolarRunResultWrp(object):
|
||||||
@ -131,8 +131,10 @@ class SyncTransport(SolarTransport):
|
|||||||
self.preprocess(executor)
|
self.preprocess(executor)
|
||||||
|
|
||||||
def run_all(self):
|
def run_all(self):
|
||||||
|
rst = []
|
||||||
for executor in self.executors:
|
for executor in self.executors:
|
||||||
executor.run(self)
|
rst.append(executor.run(self))
|
||||||
|
return rst
|
||||||
|
|
||||||
def sync_all(self):
|
def sync_all(self):
|
||||||
"""Syncs all
|
"""Syncs all
|
||||||
@ -142,8 +144,9 @@ class SyncTransport(SolarTransport):
|
|||||||
Could be someday changed to parallel thing.
|
Could be someday changed to parallel thing.
|
||||||
"""
|
"""
|
||||||
self.preprocess_all()
|
self.preprocess_all()
|
||||||
self.run_all()
|
rst = self.run_all()
|
||||||
self.executors = [] # clear after all
|
self.executors = [] # clear after all
|
||||||
|
return rst
|
||||||
|
|
||||||
|
|
||||||
class RunTransport(SolarTransport):
|
class RunTransport(SolarTransport):
|
||||||
|
@ -60,8 +60,12 @@ class OnAll(object):
|
|||||||
|
|
||||||
def __get__(self, obj, objtype):
|
def __get__(self, obj, objtype):
|
||||||
def _inner(*args, **kwargs):
|
def _inner(*args, **kwargs):
|
||||||
|
results = []
|
||||||
for transport in obj._used_transports:
|
for transport in obj._used_transports:
|
||||||
getattr(transport, self._target)(*args, **kwargs)
|
rst = getattr(transport, self._target)(*args, **kwargs)
|
||||||
|
if rst:
|
||||||
|
results.extend(rst)
|
||||||
|
return results
|
||||||
return _inner
|
return _inner
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,11 +12,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from fabric import api as fabric_api
|
|
||||||
|
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar.core.transports.base import Executor
|
from solar.core.transports.base import Executor
|
||||||
from solar.core.transports.base import SyncTransport
|
from solar.core.transports.base import SyncTransport
|
||||||
|
from solar.utils import execute
|
||||||
|
|
||||||
# XXX:
|
# XXX:
|
||||||
# currently we don't support key verification or acceptation
|
# currently we don't support key verification or acceptation
|
||||||
@ -55,9 +54,8 @@ class RsyncSyncTransport(SyncTransport):
|
|||||||
_from=_from,
|
_from=_from,
|
||||||
_to=_to)
|
_to=_to)
|
||||||
|
|
||||||
rsync_executor = lambda transport: fabric_api.local(
|
rsync_executor = lambda transport: execute(
|
||||||
rsync_cmd
|
rsync_cmd, shell=True)
|
||||||
)
|
|
||||||
|
|
||||||
log.debug("RSYNC CMD: %r" % rsync_cmd)
|
log.debug("RSYNC CMD: %r" % rsync_cmd)
|
||||||
|
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from fabric import api as fabric_api
|
|
||||||
|
|
||||||
from solar.core.log import log
|
from solar.core.log import log
|
||||||
from solar.core.transports.base import RunTransport
|
from solar.core.transports.base import RunTransport
|
||||||
|
from solar.utils import execute
|
||||||
|
|
||||||
|
|
||||||
class _RawSSHTransport(object):
|
class _RawSSHTransport(object):
|
||||||
@ -68,5 +68,6 @@ class RawSSHRunTransport(RunTransport, _RawSSHTransport):
|
|||||||
ssh_cmd += (self._ssh_command_host(settings), remote_cmd)
|
ssh_cmd += (self._ssh_command_host(settings), remote_cmd)
|
||||||
|
|
||||||
log.debug("RAW SSH CMD: %r", ssh_cmd)
|
log.debug("RAW SSH CMD: %r", ssh_cmd)
|
||||||
|
# TODO convert it to SolarRunResult
|
||||||
|
|
||||||
return fabric_api.local(' '.join(ssh_cmd))
|
return execute(' '.join(ssh_cmd), shell=True)
|
||||||
|
@ -43,6 +43,17 @@ def communicate(command, data):
|
|||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
return popen.communicate(input=data)[0]
|
return popen.communicate(input=data)[0]
|
||||||
|
|
||||||
|
|
||||||
|
def execute(command, shell=False):
|
||||||
|
popen = subprocess.Popen(
|
||||||
|
command,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
shell=shell)
|
||||||
|
out, err = popen.communicate()
|
||||||
|
return popen.returncode, out, err
|
||||||
|
|
||||||
|
|
||||||
# Configure jinja2 filters
|
# Configure jinja2 filters
|
||||||
jinja_env_with_filters = Environment()
|
jinja_env_with_filters = Environment()
|
||||||
jinja_env_with_filters.filters['to_json'] = to_json
|
jinja_env_with_filters.filters['to_json'] = to_json
|
||||||
|
Loading…
x
Reference in New Issue
Block a user