diff options
Diffstat (limited to 'perl-install/standalone/drakups')
-rwxr-xr-x | perl-install/standalone/drakups | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/perl-install/standalone/drakups b/perl-install/standalone/drakups new file mode 100755 index 000000000..2bad4e5b8 --- /dev/null +++ b/perl-install/standalone/drakups @@ -0,0 +1,416 @@ +#!/usr/bin/perl + +use strict; +use lib qw(/usr/lib/libDrakX); +use standalone; +use common; +use mouse; +use detect_devices; +use ugtk2 qw(:create :dialogs :helpers :wrappers); +use interactive; +use Libconf qw(:functions); +use Libconf::Glueconf::NUT::Ups_conf; + +# config files: +my %files = (devices => "/etc/ups/ups.conf", + access => "/etc/ups/upsd.conf", + users => "/etc/ups/upsd.users", + ); + + +my ($struct, $users); # NUT configuration +my ($w, $in); # GUI +my %indexes; + + +sub writeconf() { + info_dialog(N("Warning"), "Write support for users is incomplete\n\nIt lacks some support for some extra fields that would be lost else"); + log::explanations("Updating NUT configuration accordingly"); + $struct->writeConf($files{devices}); + + if ($users) { + log::explanations("Updating NUT users configuration accordingly"); + $users->writeConf($files{users}); + } + + require services; + services::restart("upsd"); +} + +sub read_nut_config() { + $struct = Libconf::Glueconf::NUT::Ups_conf->new({ filename => $files{devices} }); +} + +sub readDriversList() { + my (%ups, @ups); + local $_; + foreach (cat_(first(glob("/usr/share/doc/nut-*/docs/driver.list")))) { + /^#/ and next; + if (my ($vendor, $model, $extra, $driver) = /^"(.*)"\s+"(.*)"\s+"(.*)"\s+"(.*)"/) { + $ups{$vendor}{$model . $extra} = { + driver => $driver, + extra => $extra, + }; + push @ups, "$vendor|$model ($extra)"; + } + } + \%ups, \@ups; +} + +my %models; + +sub add_device_wizard { + my ($in, $config) = @_; + my ($ups_models, $model_list) = readDriversList(); + + my ($ups, $vendor, $model, $extra, $name, $driver, $port, @new_devices, $opts); + my %methods = ( + # network => N("Connected through the network"), # need SNMP probe + # serial => N("Connected through a serial port"), + # usb => N("Connected through an usb cable"), + auto => N("Connected through a serial port or an usb cable"), + manual => N("Manual configuration"), + ); + my $method = $methods{auto}; + require wizards; + my $wiz = wizards->new({ + #defaultimage => "logdrake.png", # FIXME + name => N("Add an UPS device"), + pages => { + welcome => { + name => N("Welcome to the UPS configuration utility. + +Here, you'll add a new UPS to your system.\n"), + no_back => 1, + next => 'method' + }, + method => { + name => N("We're going to add an UPS device. + +Do you want to autodetect UPS devices connected to this machine or to manually select them?"), + data => [ { label => N("Autodetection"), val => \$method, type => "list", + list => [ values %methods ] } ], + post => sub { +{ reverse %methods }->{$method} }, + }, + auto => { + end => 1, + pre => sub { + local $::isWizard; + my $_wait = $in->wait_message(N("Please wait"), N("Detection in progress")); + # UPS autoconfig: + detect_devices::probeSerialDevices() if !$::testing; + @new_devices = (); + + foreach my $ups_device (detect_devices::getUPS()) { + my $str = $ups_device->{name} || $ups_device->{DESCRIPTION}; + $str =~ s/ /_/g; + $name = $str; + + if (!exists $struct->{$str}) { + $port = $struct->{$str}{port} = $ups_device->{port} || $ups_device->{DEVICE}; + $driver = $struct->{$str}{driver} = $ups_device->{driver}; + push @new_devices, $str; + } + } + }, + name => sub { + if (@new_devices) { + N("Congratulations") . "\n\n" . + N("The wizard successfully added the following UPS devices:") . join("\n\n-", @new_devices); + } else { + N("No new UPS devices was found"); + } + }, + }, + manual => { + name => N("UPS driver configuration") . "\n\n" . N("Please select your UPS model."), + data => [ { label => N("Manufacturer / Model:"), val => \$ups, list => $model_list, + type => 'combo', sort => 1, separator => '|' }, ], + post => sub { + ($vendor, $model, $extra) = ($1, $2, $3) if $ups =~ /(.*)\|(.*) \((.*)\)$/; + ($name, $driver, $port) = ("myups", $ups_models->{$vendor}{$model . $extra}{driver}, ""); + ($driver, $opts) = split(/\s+/, $driver); + "driver"; + }, + }, + driver => { + name => sub { + N("UPS driver configuration") . "\n\n" . N("We are configuring the \"%s\" UPS from \"%s\". +Please fill in its name, its driver and its port.", $model, $vendor); + }, + data => sub { + [ + { label => N("Name:"), val => \$name, help => N("The name of your ups") }, + { label => N("Driver:"), val => \$driver, help => N("The driver that manages your ups") }, + { label => N("Port:"), val => \$port, format => \&mouse::serial_port2text, type => "combo", + list => [ &mouse::serial_ports() ], not_edit => 0, + help => N("The port on which is connected your ups") }, + ]; + }, + post => sub { + $port = '/dev/' . $port if $port !~ m!/dev/!; + return 'end'; + }, + }, + end => { + name => sub { + N("Congratulations") . "\n\n" . N("The wizard successfully configured the new \"%s\" UPS device.", + $model . "|" . $vendor); + }, + end => 1, + no_back => 1, + next => 0 + }, + }, + }); + $wiz->process($in); + + $config->{$name}{driver} = $driver; + $config->{$name}{port} = $port; + $config->{$name}{$1} = $2 if $opts =~ /\b(.*)=(.*)\b/; + # refresh the GUI when needed: + $models{ups}->append_set(1 => $name, 2 => $driver, 3 => $port) if $models{ups}; + + log::explanations(qq(Configuring "$name" UPS)); +} + +my (@acls, @rules); + +sub load_access_conf() { + foreach (cat_($files{access})) { + s/#.*//; + if (/^\s*ACL\s*(\S*)\s*(\S*)/) { + my ($ip, $mask) = split('/', $2); + push @acls, [ $1, $ip, $mask ]; + } elsif (/^\s*ACCESS\s*(\S*)\s*(\S*)\s*(\S*)/) { + push @rules, [ $1, $2, $3 ]; + } + } +} + + + +#------------------------------------------------------------------ +# misc gui data + +sub edit_row { + my ($model, $o_iter) = @_; + # create new item if needed (that is when adding a new one) at end of list + my $iter = $o_iter || $model->append; + my $dialog = Gtk2::Dialog->new; + $dialog->set_transient_for($w->{real_window}); + $dialog->set_modal(1); + + gtkpack_($dialog->vbox, + #map { + #} + ); + + gtkadd($dialog->action_area, + gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { + # create new item if needed (that is when adding a new one) at end of list + $iter ||= $model->append; + # $model->set($iter, 1 => $file->get_text); # FILL ME + $dialog->destroy; + # $modified++; + }), + gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { $dialog->destroy }), + ); + + $dialog->show_all; + +} + + +sub add_callback { + my ($model, $_list, $_getindex) = @_; + edit_row($model); +} + +sub edit_callback { + my ($model, $list) = @_; + my ($iter) = $list->get_selection->get_selected; + return unless $iter; + edit_row($model, $iter); +} + +sub del_callback { + my ($model, $list) = @_; + my (undef, $iter) = $list->get_selection->get_selected; + my $removed_idx = $list->get($iter, 0); # 1st column is index + #@rules = grep { $_->{index} ne $removed_idx } @rules; + #$tree->remove($iter); + #sensitive_buttons(0); + #$modified++; +} + +my @pages = ( + { name => N("UPS devices"), + columns => [ N("Name"), N("Driver"), N("Port") ], # N("Manufacturer"), N("Model"), + callbacks => { + add => sub { + eval { add_device_wizard($in, $struct) }; + my $err = $@; + die $err if $err && $err !~ /wizcancel/; + $::WizardWindow->destroy if defined $::WizardWindow; + undef $::WizardWindow; + }, + edit => sub {}, + remove => sub {}, + }, + load => sub { + read_nut_config(); + map { [ $_, @{$struct->{$_}}{qw(driver port)} ] } keys %$struct; + }, + id => "ups", + }, + { name => N("UPS users"), + columns => [ N("Name") ], + callbacks => { + add => sub { + my ($name) = @_; + $users->{$name} = {}; + }, + edit => sub {}, + remove => sub {}, + }, + load => sub { + $users = Libconf::Glueconf::NUT::Ups_conf->new({ filename => $files{users} }); + map { [ $_ ] } keys %$users; + }, + id => "users", + }, + { name => N("Access Control Lists"), + columns => [ N("Name"), N("IP address"), N("IP mask") ], + callbacks => { + add => sub {}, + edit => sub {}, + remove => sub {}, + }, + load => sub { + load_access_conf(); + @acls; + }, + id => "acls", + }, + { name => N("Rules"), + columns => [ N("Action"), N("Level"), N("ACL name"), N("Password") ], + callbacks => { + N("Add") => sub {}, + N("Edit") => sub {}, + N("Remove") => sub {}, + }, + + load => sub { @rules }, # already loaded when we loaded acls + id => "rules", + }, + ); + + +#------------------------------------------------------------------ +# initialize: + +#$in = 'interactive'->vnew('su'); # require_root_capability(); +$in = 'interactive'->vnew; + +$ugtk2::wm_icon = "drakups"; + +if (!$::testing) { + $in->do_pkgs->ensure_is_installed('nut-server', '/etc/rc.d/init.d/upsd') or $in->exit(1); +} + +if (member('--wizard', @ARGV)) { + read_nut_config(); + add_device_wizard($in, $struct); + writeconf(); + $in->exit($@ ? 1 : 0); +} + +$w = ugtk2->new(N("UPS Management")); +if (!$::isEmbedded) { + $::main_window = $w->{real_window}; + $w->{window}->set_size_request(500, 550); + $w->{rwindow}->set_title(N("DrakUPS")); +} + +#------------------------------------------------------------------ +# main window: + +my $_msg = N("Welcome to the UPS configuration tools"); + +$w->{window}->add(gtkpack_(Gtk2::VBox->new, + if_(!$::isEmbedded, 0, Gtk2::Banner->new('drakups', N("DrakUPS"))), + 1, my $nb = Gtk2::Notebook->new, + 0, create_okcancel(my $oc = + { + ok_clicked => sub { + #$_->{save}->() foreach @pages; + writeconf(); + $w->exit; + }, + cancel_clicked => sub { $w->exit }, + }, + ), + ), + ); + +#------------------------------------------------------------------ +# build the notebook + +my %labels = ( + add => N("Add"), + edit => N("Edit"), + remove => N("Remove"), + ); + +foreach my $i (@pages) { + my $model = $models{$i->{id}} = Gtk2::ListStore->new("Glib::Int", ("Glib::String") x listlength(@{$i->{columns}})); + my (%buttons, $list); + $indexes{$i->{name}} = 0; + my $idx = \$indexes{$i->{name}}; + my $getindex = sub { $$idx++ }; + $nb->append_page(gtkpack_(Gtk2::VBox->new, + 1, create_scrolled_window($list = Gtk2::TreeView->new_with_model($model), + [ 'automatic', 'automatic' ]), + 0, gtkpack(Gtk2::HButtonBox->new, + (map { + my ($id, $label, $sub) = @$_; + gtksignal_connect($buttons{$id} = Gtk2::Button->new($label), clicked => sub { + $sub->($model, $list, $getindex); + }); + } ([ 'add', N("Add"), $i->{callbacks}{add} || \&add_callback ], + [ 'edit', N("Edit"), \&edit_callback ], + [ 'remove', N("Remove"), \&del_callback ], + ) + ) + #(map { + # gtksignal_connect(Gtk2::Button->new($_), clicked => $i->{callbacks}{$_}), + #} keys %{$i->{callbacks}}) + ), + ), + Gtk2::Label->new($i->{name}), + ); + #$i->{list} = $list; + each_index { + $list->append_column(Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i + 1)); + } @{$i->{columns}}; + my @u = $i->{load}->(); + foreach my $line (@u) { + $model->append_set(0 => $getindex->(), map_index { $::i + 1 => $_ } @$line); + } + my $set_sensitive = sub { + my ($bool) = @_; + $buttons{$_}->set_sensitive($bool) foreach qw(remove edit); + }; + $set_sensitive->(0); + $list->get_selection->signal_connect('changed' => sub { + my ($select) = @_; + my (undef, $iter) = $select->get_selected; + $set_sensitive->(defined $iter); + }); +} + +#------------------------------------------------------------------ +# let's start the show: +$w->{rwindow}->show_all; +$w->main; |