Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2
rubygem-webyast-services
SERVICES.pm
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File SERVICES.pm of Package rubygem-webyast-services
#-- # Copyright (c) 2009-2010 Novell, Inc. # # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License # as published by the Free Software Foundation. # # This program 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 this program; if not, contact Novell, Inc. # # To contact Novell about this file by physical or electronic mail, # you may find current contact information at www.novell.com #++ package YaPI::SERVICES; use strict; use YaST::YCP qw(:LOGGING); use YaPI; use Data::Dumper; # ------------------- imported modules YaST::YCP::Import ("Directory"); YaST::YCP::Import ("FileUtils"); YaST::YCP::Import ("Package"); YaST::YCP::Import ("Progress"); YaST::YCP::Import ("Service"); YaST::YCP::Import ("SCR"); YaST::YCP::Import ("Report"); YaST::YCP::Import ("RunlevelEd"); # ------------------------------------- our $VERSION = '1.0.0'; our @CAPABILITIES = ('SLES11'); our %TYPEINFO; my $custom_services_dir = "/etc/webyast"; my $custom_services_file = "custom_services.yml"; my $error_message = ""; # check for key presence in given list sub contains { my ( $list, $key, $ignorecase ) = @_; if ( $ignorecase ) { if ( grep /^$key$/i, @{$list} ) { return 1; } } else { if ( grep /^$key$/, @{$list} ) { return 1; } } return 0; } # log error message and fill it into $error_message variable sub report_error { $error_message = shift; y2error ($error_message); } # parse the file with custom services and return the hash describing the file sub parse_custom_services { my $custom_services_path = "$custom_services_dir/vendor/$custom_services_file"; unless (FileUtils->Exists ($custom_services_path)) { y2milestone ("$custom_services_path not available, using default"); $custom_services_path = "$custom_services_dir/$custom_services_file" } if (!FileUtils->Exists ($custom_services_path)) { report_error ("$custom_services_path file not present"); return {}; } if (!Package->Installed ("yast2-ruby-bindings")) { report_error ("yast2-ruby-bindings not installed, cannot read custom services"); return {}; } if (!FileUtils->Exists (Directory->moduledir()."/YML.rb")) { report_error ("YML.rb not present, cannot parse config file"); return {}; } YaST::YCP::Import ("YML"); my $parsed = YML->parse ($custom_services_path); if (!defined $parsed || ref ($parsed) ne "HASH") { report_error ("custom services file could not be read"); return {}; } return $parsed; } # read the list of custom services and return the information about them # if requested, read the status of services sub read_custom_services { my $args = shift; my @ret = (); my $services = parse_custom_services (); foreach my $name (keys %$services) { my $s = { "name" => $name }; $s->{"description"} = ($services->{$name}{"description"} || "") if $args->{"description"} || 0; $s->{"shortdescription"}= ($services->{$name}{"shortdescription"} || "") if $args->{"shortdescription"} || 0; # read list of available commands, it may be limited for 'custom service' my @commands = (); foreach my $key (keys %{$services->{$name}}) { if (contains (["start","stop","restart","reload","try-restart"], $key, 1)) { push @commands, $key; } } $s->{"commands"} = \@commands; if ($args->{"read_status"} || 0) { my $cmd = $services->{$name}{"status"}; if (!$cmd) { report_error ("status script for $name not defined or empty"); next; } my $out = SCR->Execute (".target.bash_output", $cmd); $s->{"status"} = $out->{"exit"}; } push @ret, $s; } return \@ret; } # read infomation about custom service and execute given command with it sub execute_custom_script { my $name = shift; my $action = shift; my $services = parse_custom_services (); my $ret = { "stdout" => "", "stderr" => "failure", "exit" => 255 }; if (%$services) { my $service = $services->{$name}; if (!defined $service || ref ($service) ne "HASH" || ! %$service) { report_error ("service $name not defined or empty in config file"); $ret->{"stderr"} = $error_message; return $ret; } my $cmd = $services->{$name}{$action}; if (!$cmd) { report_error ("'$action' script for $name not defined or empty"); $ret->{"stderr"} = $error_message; return $ret; } $ret = SCR->Execute (".target.bash_output", $cmd); } return $ret; } # Return the list of services enabled in given runlevel, or even all available. # # Parameter is an argument map with possible keys: # "service" : if defined, only the status of _this given service_ will be returned (= list with one item) # "runlevel" : integer; if not defined, current runlevel will be used # "read_status" : if true, service status will be queried and returned for each service # "custom" : if true, custom services (defined in config file) will be read (otherwise list of init.d services) # "description" : if true, read the description of each service # "only_enabled" : if true, return only list of services enabled in given runlevel # - neither "start_runlevels", nor "enabled" key will be part of resulting maps # "start_runlevels" if true, each service's result map will contain list of runlevels where it is started # - if not present (or false), "enabled" key with boolean value will be returned instead # "filter" : list of strings; defines filtered list of services that should be returned # @returns array of hashes BEGIN{$TYPEINFO{Read} = ["function", ["list", [ "map", "string", "any"]], ["map", "string", "any"]]; } sub Read { my $self = shift; my $args = shift; my @ret = (); my $runlevel = $args->{"runlevel"} || ""; $runlevel = SCR->Read (".init.scripts.current_runlevel") unless ($runlevel); unless ($runlevel) { $runlevel = SCR->Read (".init.scripts.default_runlevel"); y2warning ("current runlevel not available, using default ('$runlevel')"); } my @filter = (); @filter = @{$args->{"filter"}} if defined $args->{"filter"}; my $filter_map= {}; foreach my $s (@filter) { $filter_map->{$s} = 1; } # only read status of one service if the name was given if ($args->{"service"} || "") { my $name = $args->{"service"} || ""; my $exec = $self->Execute ({ "name" => $name, "action" => "status", "only_execute" => 1, "only_this" => 1, "custom" => $args->{"custom"} || 0 }); my $s = { "name" => $name, "status" => $exec->{"exit"} || 0, # custom service is always 'enabled' (in fact, we can't check) "enabled" => ($args->{"custom"} || 0) || YaST::YCP::Boolean (Service->Enabled ($name)) }; push @ret, $s; return \@ret; } # read only custom services if ($args->{"custom"} || 0) { return read_custom_services ($args); } if ($args->{"only_enabled"}) { # generate the output list foreach my $name (@{Service->EnabledServices ($runlevel)}) { next if (@filter && !defined $filter_map->{$name}); # should not be returned my $s = { "name" => $name, }; $s->{"status"} = Service->Status ($name) if ($args->{"read_status"} || 0); if (($args->{"description"} || 0) || ($args->{"shortdescription"} || 0)) { my $info = Service->Info ($name); $s->{"description"} = ($info->{"description"} || "") if $args->{"description"} || 0; $s->{"shortdescription"}= ($info->{"shortdescription"} || "") if $args->{"shortdescription"} || 0; } push @ret, $s; } } else { my $progress_orig = Progress->set (0); Report->DisplayErrors (0, 0); RunlevelEd->Read (); my $full_services = RunlevelEd->services (); while (my ($name, $info) = each %$full_services) { next if (@filter && !defined $filter_map->{$name}); # should not be returned next if (contains ($info->{"defstart"} || [], "B", 1)); my $s = { "name" => $name }; if ($args->{"start_runlevels"} || 0) { $s->{"start_runlevels"} = $info->{"start"} || []; } else { my $start = $info->{"start"} || []; # for "B" check, see RunlevelEd::StartContainsImplicitly $s->{"enabled"} = YaST::YCP::Boolean (contains ($start, $runlevel, 1) || contains ($start, "B", 1)); } # return start and stop dependencies for each service if ($args->{"dependencies"} || 0) { my @required_for_start = (); # filter out services started on boot by default: foreach my $rq (@{RunlevelEd->ServiceDependencies ($name, 1)}) { my $start = $full_services->{$rq}{"start"} || []; push @required_for_start, $rq unless contains ($start, "B", 1); } $s->{"required_for_start"} = \@required_for_start; $s->{"required_for_stop"} = RunlevelEd->ServiceDependencies ($name, 0); } $s->{"status"} = Service->Status ($name) if ($args->{"read_status"} || 0); $s->{"description"} = ($info->{"description"} || "") if $args->{"description"} || 0; $s->{"shortdescription"}= ($info->{"shortdescription"} || "") if $args->{"shortdescription"} || 0; push @ret, $s; } Progress->set ($progress_orig); } return \@ret; } # Return the status of given service # return value is the exit code of status function BEGIN{$TYPEINFO{Get} = ["function", "integer", "string" ]; } sub Get { my $self = shift; my $name = shift; return Service->Status ($name); } # Executes an action (e.g. "restart") with given service # If the action is start or stop, it will also enable (resp. disable) # the service for current runlevel. # # parameter is a map where "name" is service name, "action" means what to do # - if "only_execute" key is present, do not continue with enabling/disabling # - if action is "enable" or "disable", only enables/disables service # - if "custom" key is present (with true value), indicates custom service, which # has special handling. Also, custom service will not be enabled/disabled. # # return value is map with "exit", "stdout" and "stderr" keys BEGIN{$TYPEINFO{Execute} = ["function", [ "map", "string", "any"], [ "map", "string", "any"]]; } sub Execute { my $self = shift; my $args = shift; my $name = $args->{"name"} || ""; my $action = $args->{"action"} || ""; my $ret = {}; y2debug ("Execute args: ", Dumper ($args)); # no enable/disable my $only_execute = $args->{"only_execute"} || 0; # do not solve dependencies my $only_this = $args->{"only_this"} || 0; # just a shurtcut, so Execute function can be used for Enable only return $self->Enable ($args) if ($action eq "enable" || $action eq "disable"); # custom service has special handling if ($args->{"custom"} || 0) { return execute_custom_script ($name, $action); } # only handle given service, not dependencies elsif ($only_this) { $ret = Service->RunInitScriptOutput ($name, $action); unless ($only_execute) { if (($ret->{"exit"} || 0) ne 0) { y2error ("action '$action' failed"); return $ret; } if ($action eq "start") { $args->{"action"} = "enable"; } else { $args->{"action"} = "disable"; } return $self->Enable ($args); } } # full action: start/stop and enable/disable required service else { my $progress_orig = Progress->set (0); RunlevelEd->Read (); Progress->set ($progress_orig); my $full_services = RunlevelEd->services (); my $runlevel = RunlevelEd->GetCurrentRunlevel (); if ($runlevel eq "unknown") { $runlevel = RunlevelEd->GetDefaultRunlevel (); y2warning ("current runlevel not available, using default ('$runlevel')"); } # in fact, this may mean "start & enable" (depends on $only_execute) my $start = ($action eq "start") || ($action eq "restart"); # list of runlevels where the service should be enabled my $rls = $start? ($full_services->{$name}{"defstart"} || []) : undef; # list of dependencies my $dep_s = RunlevelEd->ServiceDependencies ($name, $start); # filtered list; unfortunatelly it does not really check for current status $dep_s = RunlevelEd->FilterAlreadyDoneServices ($dep_s, $rls, $start, 1, 1); my $enable_args = { "action" => ($action eq "start") ? "enable" : "disable", # we're solving dependencies here, so no need to do it in Enable call again "only_this" => 1 }; foreach my $s (@$dep_s) { # check if service is not already running my $status = Service->Status ($s); # action for required service: when restarting selected, only start required ones my $req_action = ($action eq "restart") ? "start" : $action; if (($start && $status != 0) || ($status == 0 && !$start)) { # RunInitScriptWithTimeOut would be better, but does not return stderr $ret = Service->RunInitScriptOutput ($s, $req_action); } if (($ret->{"exit"} || 0) ne 0) { y2error ("action '$req_action' for service '$s' failed"); return $ret; } next if $only_execute; my $startlist = $full_services->{$s}{"start"} || []; my $service_enabled = contains ($startlist, $runlevel, 1) || contains ($startlist, "B", 1); if (($start && !$service_enabled) || (!$start && $service_enabled)) { $enable_args->{"name"} = $s; $ret = $self->Enable ($enable_args); } if (($ret->{"exit"} || 0) ne 0) { y2error ("insserv call for service '$s' failed"); return $ret; } } # now, finally start/stop our service... $ret = Service->RunInitScriptOutput ($name, $action); if (($ret->{"exit"} || 0) ne 0) { y2error ("action '$action' for service '$name' failed"); return $ret; } return $ret if $only_execute; # ... and enable/disable it $enable_args->{"name"} = $name; $ret = $self->Enable ($enable_args); } return $ret; } # Enable/Disable given service in current runlevel # parameter is a map where "name" is service name, "action" means what to do # return value is map with "exit", "stdout" and "stderr" keys BEGIN{$TYPEINFO{Enable} = ["function", [ "map", "string", "any"], [ "map", "string", "any"]]; } sub Enable { my $self = shift; my $args = shift; my $name = $args->{"name"} || ""; my $action = $args->{"action"} || ""; my $ret = { "stdout" => "", "stderr" => "", "exit" => 0 }; # do not solve dependencies my $only_this = $args->{"only_this"} || 0; y2debug ("Enable args: ", Dumper ($args)); # enable/disable with dependencies unless ($only_this) { my $progress_orig = Progress->set (0); Report->DisplayErrors (0, 0); RunlevelEd->Read (); my $exit = 0; if ($action eq "enable") { $exit = RunlevelEd->ServiceInstall ($name, undef); if ($exit == 1) { $ret->{"stderr"} = "Failed to enable service $name."; $ret->{"stdout"} = $name; $ret->{"exit"} = 1000; } } elsif ($action eq "disable") { $exit = RunlevelEd->ServiceRemove ($name, undef); if ($exit == 1) { $ret->{"stderr"} = "Failed to disable service $name."; $ret->{"stdout"} = $name; $ret->{"exit"} = 2000; } } unless (RunlevelEd->Write ()) { $ret->{"stderr"} = "Failed during writing runlevel settings."; $ret->{"exit"} = 3000; } Progress->set ($progress_orig); return $ret; } if ($action eq "enable") { unless (Service->Enable ($name)) { $ret->{"stderr"} = "Failed to enable service $name."; $ret->{"stdout"} = $name; $ret->{"exit"} = 1000; } } elsif ($action eq "disable") { unless (Service->Disable ($name)) { $ret->{"stderr"} = "Failed to disable service $name."; $ret->{"stdout"} = $name; $ret->{"exit"} = 2000; } } else { $ret->{"stderr"} = "Unknown action '$action'"; $ret->{"exit"} = 3; } return $ret; } 1;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor