diff --git a/fuel_dev_tools/docker/astute.py b/fuel_dev_tools/docker/astute.py index 28941ed..4f04af5 100644 --- a/fuel_dev_tools/docker/astute.py +++ b/fuel_dev_tools/docker/astute.py @@ -98,6 +98,20 @@ class Rsync(DockerAstuteMixin, docker.RsyncCommand, docker.ShellCommand): raise +class RsyncAgent(DockerAstuteMixin, docker.RsyncCommand): + """Rsync files to the Docker container.""" + @property + def source_path(self): + return '.' + + @property + def target_path(self): + return 'usr/libexec/mcollective/mcollective/agent' + + def post_sync(self, parsed_args): + self.restart_container() + + class Start(DockerAstuteMixin, docker.StartCommand): """Start Docker container.""" diff --git a/fuel_dev_tools/docker/mcollective.py b/fuel_dev_tools/docker/mcollective.py new file mode 100644 index 0000000..df3b3b7 --- /dev/null +++ b/fuel_dev_tools/docker/mcollective.py @@ -0,0 +1,42 @@ +# Copyright 2015 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os + +from fabric import api as fabric_api + +from fuel_dev_tools import docker + + +class DockerMcollectiveMixin(object): + container = 'mcollective' + default_command = '/bin/bash' + + def get_log_directory(self): + return '/var/log/docker-logs/mcollective' + + +class RsyncAgent(DockerMcollectiveMixin, docker.RsyncCommand): + """Rsync files to the Docker container.""" + @property + def source_path(self): + return '.' + + @property + def target_path(self): + return 'usr/libexec/mcollective/mcollective/agent' + + def post_sync(self, parsed_args): + self.restart_container() + diff --git a/fuel_dev_tools/rsync.py b/fuel_dev_tools/rsync.py index ee915c6..fb74d6a 100644 --- a/fuel_dev_tools/rsync.py +++ b/fuel_dev_tools/rsync.py @@ -31,7 +31,7 @@ class RsyncMixin(object): #) result = subprocess.check_output( - ['rsync', 'avz'] + list(args) + [source, target] + ['rsync', '-avz'] + list(args) + [source, target] ) self.print_debug(result.decode('utf-8')) diff --git a/fuel_dev_tools/shell.py b/fuel_dev_tools/shell.py index 3c2461a..49c317c 100644 --- a/fuel_dev_tools/shell.py +++ b/fuel_dev_tools/shell.py @@ -32,6 +32,7 @@ from fuel_dev_tools.docker import nailgun from fuel_dev_tools.docker import nginx from fuel_dev_tools.docker import postgres from fuel_dev_tools.docker import rabbitmq +from fuel_dev_tools.slaves import mcagent from fuel_dev_tools import exc from fuel_dev_tools import info from fuel_dev_tools import ssh @@ -54,6 +55,8 @@ COMMANDS = { 'astute-tail': astute.Tail, 'astute-volumes': astute.Volumes, + 'mcagent-rsync': mcagent.Rsync, + 'nailgun-id': nailgun.Id, 'nailgun-config': nailgun.Config, 'nailgun-db-reset': nailgun.DBReset, diff --git a/fuel_dev_tools/slaves/__init__.py b/fuel_dev_tools/slaves/__init__.py new file mode 100644 index 0000000..e8ad086 --- /dev/null +++ b/fuel_dev_tools/slaves/__init__.py @@ -0,0 +1,22 @@ +from fabric import api as fabric_api + +from fuel_dev_tools import cmd_parser +from fuel_dev_tools import ssh + + +class SlavesMixin(cmd_parser.CmdParserMixin, ssh.SSHMixin): + def discover_slaves(self): + slaves = self.ssh_command('fuel', 'node') + + return self.parse_output(slaves) + + def slave_command(self, slave, *cmd): + cmd = [ + 'ssh', '-A', '-t', + '{}@{}'.format(self.app_args.user, self.app_args.ip), + '-p', self.app_args.port, + 'ssh', '-A', '-t', + 'root@{ip}'.format(**slave) + ] + list(cmd) + + return fabric_api.run(' '.join(cmd)) diff --git a/fuel_dev_tools/slaves/mcagent.py b/fuel_dev_tools/slaves/mcagent.py new file mode 100644 index 0000000..d29cf39 --- /dev/null +++ b/fuel_dev_tools/slaves/mcagent.py @@ -0,0 +1,62 @@ +import os + +from fuel_dev_tools import command +from fuel_dev_tools.docker import astute +from fuel_dev_tools.docker import mcollective +from fuel_dev_tools import rsync +from fuel_dev_tools import slaves +from fuel_dev_tools import ssh + + +class Rsync(slaves.SlavesMixin, + ssh.SSHMixin, + rsync.RsyncMixin, + command.BaseCommand): + + def get_parser(self, prog_name): + parser = super(Rsync, self).get_parser(prog_name) + + parser.add_argument( + '-s', '--source', + nargs='?', + default='.', + help='Source of the rsync-ed directory.' + ) + + return parser + + def target_for_slave(self, slave): + if slave['status'] in ['discover', 'error']: + return '/usr/libexec/mcollective/mcollective/agent' + + raise Exception( + 'Don\'t know target for status {status} for node {name}'.format( + **slave) + ) + + def take_action(self, parsed_args): + for slave in self.discover_slaves(): + self.print_debug('Syncing to slave {name} [{ip}]'.format(**slave)) + + source = parsed_args.source + target = ':{}'.format(self.target_for_slave(slave)) + + hop_args = [ + '-e', + 'ssh -A -t root@{} -p {} ssh -A -t root@{}'.format( + self.app_args.ip, + self.app_args.port, + slave['ip'] + ) + ] + + self.rsync(source, target, *hop_args) + + self.print_debug('Restarting mcollective') + self.slave_command(slave, '/etc/init.d/mcollective', 'restart') + + mc = mcollective.RsyncAgent(self.app, self.app_args) + mc.take_action(parsed_args) + + ac = astute.RsyncAgent(self.app, self.app_args) + ac.take_action(parsed_args) diff --git a/fuel_dev_tools/ssh.py b/fuel_dev_tools/ssh.py index 4c1f601..b0e1c73 100644 --- a/fuel_dev_tools/ssh.py +++ b/fuel_dev_tools/ssh.py @@ -17,7 +17,6 @@ import six import subprocess import fabric -from fabric import context_managers from fabric import api as fabric_api from fuel_dev_tools import command