summaryrefslogtreecommitdiffstats
path: root/urpm/parallel_ssh.pm
blob: 5dfe33296291b0e1421a2831110fe07a02ffd104 (plain)
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
package urpm::parallel_ssh;


#- Copyright (C) 2002, 2003, 2004, 2005 MandrakeSoft SA
#- Copyright (C) 2005-2010 Mandriva SA

use strict;
use urpm::util 'dirname';
use urpm::msg;
use urpm::parallel;

our @ISA = 'urpm::parallel';

sub _localhost { $_[0] eq 'localhost' }
sub _ssh       { &_localhost ? '' : "ssh $_[0] " }
sub _host      { &_localhost ? '' : "$_[0]:" }

sub _scp {
    my ($urpm, $host, @para) = @_;
    my $dest = pop @para;

    $urpm->{log}("parallel_ssh: scp " . join(' ', @para) . " $host:$dest");
    system('scp', @para, _host($host) . $dest) == 0
      or $urpm->{fatal}(1, N("scp failed on host %s (%d)", $host, $? >> 8));
}

sub copy_to_dir {
    my ($parallel, $urpm, @para) = @_;
    my $dir = pop @para;

    foreach my $host (keys %{$parallel->{nodes}}) {
	if (_localhost($host)) {
	    if (my @f = grep { dirname($_) ne $dir } @para) {
		$urpm->{log}("parallel_ssh: cp @f $urpm->{cachedir}/rpms");
		system('cp', @f, $dir) == 0
		  or $urpm->{fatal}(1, N("cp failed on host %s (%d)", $host, $? >> 8));
	    }
	} else {
	    _scp($urpm, $host, @para, $dir);
	}
    }
}

sub propagate_file {
    my ($parallel, $urpm, $file) = @_;
    foreach (grep { !_localhost($_) } keys %{$parallel->{nodes}}) {
	_scp($urpm, $_, '-q', $file, $file);
    }
}

sub _ssh_urpm {
    my ($urpm, $node, $cmd, $para) = @_;

    $cmd ne 'urpme' && _localhost($node) and $para = "--nolock $para";

    # it doesn't matter for urpmq, and previous version of urpmq didn't handle it:
    $cmd ne 'urpmq' and $para = "--no-locales $para";

    $urpm->{log}("parallel_ssh: $node: $cmd $para");
    _ssh($node) . " $cmd $para";
}
sub _ssh_urpm_popen {
    my ($urpm, $node, $cmd, $para) = @_;

    my $command = _ssh_urpm($urpm, $node, $cmd, $para);
    open(my $fh, "$command |") or $urpm->{fatal}(1, "Can't fork ssh: $!");
    $fh;
}

sub urpm_popen {
    my ($parallel, $urpm, $cmd, $para, $do) = @_;

    my @errors;

    foreach my $node (keys %{$parallel->{nodes}}) {
	my $fh = _ssh_urpm_popen($urpm, $node, $cmd, $para);

	while (my $s = <$fh>) {
	    chomp $s;
	    $urpm->{debug}("parallel_ssh: $node: received: $s") if $urpm->{debug};
	    $do->($node, $s) and last;
	}
	close $fh or push @errors, N("%s failed on host %s (maybe it does not have a good version of urpmi?) (exit code: %d)", $cmd, $node, $? >> 8);
	$urpm->{debug}("parallel_ssh: $node: $cmd finished") if $urpm->{debug};
    }

    @errors;
}

sub run_urpm_command {
    my ($parallel, $urpm, $cmd, $para) = @_;

    foreach my $node (keys %{$parallel->{nodes}}) {
	system(_ssh_urpm($urpm, $node, $cmd, $para));
    }
}

#- allow to bootstrap from urpmi code directly (namespace is urpm).

package urpm;

no warnings 'redefine';

sub handle_parallel_options {
    my (undef, $options) = @_;
    my ($id, @nodes) = split /:/, $options;

    if ($id =~ /^ssh(?:\(([^\)]*)\))?$/) {
	my %nodes; @nodes{@nodes} = undef;
	return bless {
	    media   => $1,
	    nodes   => \%nodes,
	}, "urpm::parallel_ssh";
    }
    return undef;
}

1;
>; # stores the values of the command-line options our %options = (verbose => 0); # used by urpmf sub add_param_closure { my (@tags) = @_; return sub { $::qf .= join $::separator, '', map { "%$_" } @tags }; } # debug code to display a nice message when exiting, # to ensure f*cking code (eg: Sys::Syslog) won't exit and break graphical interfaces END { $::debug_exit and print STDERR "EXITING (pid=$$)\n" } sub set_debug { my ($urpm) = @_; $::debug_exit = 1; $options{verbose}++; $urpm->{debug} = $urpm->{debug_URPM} = sub { print STDERR "$_[0]\n" }; } sub set_verbose { $options{verbose} += $_[0]; } # options specifications for Getopt::Long my %options_spec_all = ( 'debug' => sub { set_debug($urpm) }, 'debug-librpm' => sub { URPM::setVerbosity(7) }, # 7 == RPMLOG_DEBUG 'q|quiet' => sub { set_verbose(-1) }, 'v|verbose' => sub { set_verbose(1) }, 'urpmi-root=s' => sub { urpm::set_files($urpm, $_[1]) }, 'wait-lock' => \$options{wait_lock}, 'use-copied-hdlist' => sub { $urpm->{options}{use_copied_hdlist} = 1 }, 'tune-rpm=s' => sub { urpm::set_tune_rpm($urpm, $_[1]) }, "no-locales" => sub { $urpm::msg::no_translation = 1 }, "version" => sub { require urpm; print "$tool $urpm::VERSION\n"; exit(0) }, "help|h" => sub { if (defined &::usage) { ::usage() } else { die "No help defined\n" } }, ); my %options_spec = ( # warning: for gurpm, urpm is _not_ a real urpmi object, only options should be altered: gurpmi => { 'media|mediums=s' => sub { $urpm->{options}{media} = 1 }, 'searchmedia|search-media=s' => sub { $urpm->{options}{searchmedia} = 1 }, }, urpmi => { update => \$::update, 'media|mediums=s' => \$::media, 'excludemedia|exclude-media=s' => \$::excludemedia, 'sortmedia|sort-media=s' => \$::sortmedia, 'searchmedia|search-media=s' => \$::searchmedia, 'synthesis=s' => \$options{synthesis}, auto => sub { $urpm->{options}{auto} = 1 }, 'allow-medium-change' => \$::allow_medium_change, 'gui' => \$::gui, 'auto-select' => \$::auto_select, 'auto-update' => sub { $::auto_update = $::auto_select = 1 }, 'auto-orphans' => \$options{auto_orphans}, 'no-remove|no-uninstall' => \$::no_remove, 'no-install|noinstall' => \$::no_install, 'keep!' => sub { $urpm->{options}{keep} = $_[1] }, 'logfile=s' => \$::logfile, 'split-level=s' => sub { $urpm->{options}{'split-level'} = $_[1] }, 'split-length=s' => sub { $urpm->{options}{'split-length'} = $_[1] }, 'fuzzy!' => sub { $urpm->{options}{fuzzy} = $_[1] }, 'src|s' => sub { $urpm->{error}("option --src is deprecated, use --buildrequires instead (nb: it doesn't download src.rpm anymore)"); $options{buildrequires} = 1 }, 'buildrequires' => \$options{buildrequires}, 'install-src' => \$::install_src, clean => sub { $::clean = 1; $::noclean = 0 }, noclean => sub { $::clean = $urpm->{options}{'pre-clean'} = $urpm->{options}{'post-clean'} = 0; $::noclean = 1; }, 'pre-clean!' => sub { $urpm->{options}{'pre-clean'} = $_[1] }, 'post-clean!' => sub { $urpm->{options}{'post-clean'} = $_[1] }, 'no-priority-upgrade' => sub { #- keep this option which is passed by older urpmi. #- since we can't know what the previous_priority_upgrade list was, #- just use a rubbish value which will mean list has changed $options{previous_priority_upgrade} = 'list_has_changed'; }, 'previous-priority-upgrade=s' => \$options{previous_priority_upgrade}, force => \$::force, justdb => \$options{justdb}, replacepkgs => \$options{replacepkgs}, suggests => sub { $urpm->{fatal}(1, "Use --allow-suggests instead of --suggests"); }, 'allow-suggests' => sub { $urpm->{options}{'no-suggests'} = 0 }, 'no-suggests' => sub { $urpm->{options}{'no-suggests'} = 1 }, 'allow-nodeps' => sub { $urpm->{options}{'allow-nodeps'} = 1 }, 'allow-force' => sub { $urpm->{options}{'allow-force'} = 1 }, 'parallel=s' => \$::parallel, 'metalink!' => sub { $urpm->{options}{metalink} = $_[1] }, # deprecated in favor of --downloader xxx wget => sub { $urpm->{options}{downloader} = 'wget' }, curl => sub { $urpm->{options}{downloader} = 'curl' }, prozilla => sub { $urpm->{options}{downloader} = 'prozilla' }, aria2 => sub { $urpm->{options}{downloader} = 'aria2' }, 'downloader=s' => sub { $urpm->{options}{downloader} = $_[1] }, 'curl-options=s' => sub { $urpm->{options}{'curl-options'} = $_[1] }, 'rsync-options=s' => sub { $urpm->{options}{'rsync-options'} = $_[1] }, 'wget-options=s' => sub { $urpm->{options}{'wget-options'} = $_[1] }, 'prozilla-options=s' => sub { $urpm->{options}{'prozilla-options'} = $_[1] }, 'aria2-options=s' => sub { $urpm->{options}{'aria2-options'} = $_[1] }, 'limit-rate=s' => sub { $urpm->{options}{'limit-rate'} = $_[1] },