mirror of
				https://git.proxmox.com/git/pve-manager
				synced 2025-11-04 10:10:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			388 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
package PVE::API2::Services;
 | 
						|
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
 | 
						|
use PVE::Tools;
 | 
						|
use PVE::SafeSyslog;
 | 
						|
use PVE::Cluster;
 | 
						|
use PVE::INotify;
 | 
						|
use PVE::Exception qw(raise_param_exc);
 | 
						|
use PVE::RESTHandler;
 | 
						|
use PVE::RPCEnvironment;
 | 
						|
use PVE::JSONSchema qw(get_standard_option);
 | 
						|
use PVE::AccessControl;
 | 
						|
use IO::File;
 | 
						|
 | 
						|
use base qw(PVE::RESTHandler);
 | 
						|
 | 
						|
my $service_name_list = [
 | 
						|
    'pveproxy', 
 | 
						|
    'pvedaemon',
 | 
						|
    'spiceproxy',
 | 
						|
    'pvestatd',
 | 
						|
    'pve-cluster',
 | 
						|
    'corosync',
 | 
						|
    'pve-firewall',
 | 
						|
    'pvefw-logger',
 | 
						|
    'pve-ha-crm',
 | 
						|
    'pve-ha-lrm',
 | 
						|
    'sshd',
 | 
						|
    'syslog',
 | 
						|
    'cron',
 | 
						|
    'postfix',
 | 
						|
    'ksmtuned',
 | 
						|
    'systemd-timesyncd',
 | 
						|
    ];
 | 
						|
 | 
						|
my $get_full_service_state = sub {
 | 
						|
    my ($service) = @_;
 | 
						|
 | 
						|
    my $res;
 | 
						|
    
 | 
						|
    my $parser = sub {
 | 
						|
	my $line = shift;
 | 
						|
	if ($line =~ m/^([^=\s]+)=(.*)$/) {
 | 
						|
	    $res->{$1} = $2;
 | 
						|
	}
 | 
						|
    };
 | 
						|
 | 
						|
    PVE::Tools::run_command(['systemctl', 'show', $service], outfunc => $parser); 
 | 
						|
    
 | 
						|
    return $res;
 | 
						|
};
 | 
						|
 | 
						|
my $static_service_list;
 | 
						|
 | 
						|
sub get_service_list {
 | 
						|
 | 
						|
    return $static_service_list if $static_service_list;
 | 
						|
    
 | 
						|
    my $list = {};
 | 
						|
    foreach my $name (@$service_name_list) {
 | 
						|
	my $ss;
 | 
						|
	eval { $ss = &$get_full_service_state($name); };
 | 
						|
	warn $@ if $@;
 | 
						|
	next if !$ss;
 | 
						|
	next if !defined($ss->{Description});
 | 
						|
	$list->{$name} = { name => $name, desc =>  $ss->{Description} };
 | 
						|
    }
 | 
						|
 | 
						|
    $static_service_list = $list;
 | 
						|
    
 | 
						|
    return $static_service_list;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my $service_prop_desc = {
 | 
						|
    description => "Service ID",
 | 
						|
    type => 'string',
 | 
						|
    enum => $service_name_list,
 | 
						|
};
 | 
						|
 | 
						|
my $service_cmd = sub {
 | 
						|
    my ($service, $cmd) = @_;
 | 
						|
 | 
						|
    my $initd_cmd;
 | 
						|
 | 
						|
    die "unknown service command '$cmd'\n"
 | 
						|
	if $cmd !~ m/^(start|stop|restart|reload)$/;
 | 
						|
 | 
						|
    if ($service eq 'pvecluster' || $service eq 'pvedaemon' || $service eq 'pveproxy') {
 | 
						|
	if ($cmd eq 'restart') {    
 | 
						|
	    # OK
 | 
						|
	} else {
 | 
						|
	    die "invalid service cmd '$service $cmd': ERROR";
 | 
						|
	}
 | 
						|
    }
 | 
						|
    
 | 
						|
    PVE::Tools::run_command(['systemctl', $cmd, $service]);
 | 
						|
};
 | 
						|
 | 
						|
my $service_state = sub {
 | 
						|
    my ($service) = @_;
 | 
						|
 | 
						|
    my $ss;
 | 
						|
    eval { $ss = &$get_full_service_state($service); };
 | 
						|
    if (my $err = $@) {
 | 
						|
	return 'unknown';
 | 
						|
    }
 | 
						|
 | 
						|
    return $ss->{SubState} if $ss->{SubState};
 | 
						|
 | 
						|
    return 'unknown';
 | 
						|
};
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'index', 
 | 
						|
    path => '', 
 | 
						|
    method => 'GET',
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
 | 
						|
    },
 | 
						|
    description => "Service list.",
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => {
 | 
						|
	type => 'array',
 | 
						|
	items => {
 | 
						|
	    type => "object",
 | 
						|
	    properties => {},
 | 
						|
	},
 | 
						|
	links => [ { rel => 'child', href => "{service}" } ],
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $res = [];
 | 
						|
 | 
						|
	my $service_list = get_service_list();
 | 
						|
	
 | 
						|
	foreach my $id (keys %{$service_list}) {
 | 
						|
	    push @$res, { 
 | 
						|
		service => $id,
 | 
						|
		name => $service_list->{$id}->{name},
 | 
						|
		desc => $service_list->{$id}->{desc},
 | 
						|
		state => &$service_state($id),
 | 
						|
	    };
 | 
						|
	}
 | 
						|
 | 
						|
	return $res;
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method({
 | 
						|
    name => 'srvcmdidx',
 | 
						|
    path => '{service}', 
 | 
						|
    method => 'GET',
 | 
						|
    description => "Directory index",
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
 | 
						|
    },
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => {
 | 
						|
	type => 'array',
 | 
						|
	items => {
 | 
						|
	    type => "object",
 | 
						|
	    properties => {
 | 
						|
		subdir => { type => 'string' },
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	links => [ { rel => 'child', href => "{subdir}" } ],
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
 | 
						|
	my $res = [
 | 
						|
	    { subdir => 'state' },
 | 
						|
	    { subdir => 'start' },
 | 
						|
	    { subdir => 'stop' },
 | 
						|
	    { subdir => 'restart' },
 | 
						|
	    { subdir => 'reload' },
 | 
						|
	    ];
 | 
						|
	
 | 
						|
	return $res;
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'service_state', 
 | 
						|
    path => '{service}/state', 
 | 
						|
    method => 'GET',
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Audit' ]],
 | 
						|
    },
 | 
						|
    description => "Read service properties",
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => {
 | 
						|
	type => "object",
 | 
						|
	properties => {},
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $service_list = get_service_list();
 | 
						|
	
 | 
						|
	my $si = $service_list->{$param->{service}};
 | 
						|
	return {
 | 
						|
	    service => $param->{service},
 | 
						|
	    name => $si->{name},
 | 
						|
	    desc => $si->{desc},
 | 
						|
	    state => &$service_state($param->{service}),
 | 
						|
	};
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'service_start', 
 | 
						|
    path => '{service}/start', 
 | 
						|
    method => 'POST',
 | 
						|
    description => "Start service.",
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
 | 
						|
    },
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => { 
 | 
						|
	type => 'string',
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $rpcenv = PVE::RPCEnvironment::get();
 | 
						|
 | 
						|
	my $user = $rpcenv->get_user();
 | 
						|
 | 
						|
	my $realcmd = sub {
 | 
						|
	    my $upid = shift;
 | 
						|
 | 
						|
	    syslog('info', "starting service $param->{service}: $upid\n");
 | 
						|
 | 
						|
	    &$service_cmd($param->{service}, 'start');
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	return $rpcenv->fork_worker('srvstart', $param->{service}, $user, $realcmd);
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'service_stop', 
 | 
						|
    path => '{service}/stop', 
 | 
						|
    method => 'POST',
 | 
						|
    description => "Stop service.",
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
 | 
						|
    },
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => { 
 | 
						|
	type => 'string',
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $rpcenv = PVE::RPCEnvironment::get();
 | 
						|
 | 
						|
	my $user = $rpcenv->get_user();
 | 
						|
 | 
						|
	my $realcmd = sub {
 | 
						|
	    my $upid = shift;
 | 
						|
 | 
						|
	    syslog('info', "stoping service $param->{service}: $upid\n");
 | 
						|
 | 
						|
	    &$service_cmd($param->{service}, 'stop');
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	return $rpcenv->fork_worker('srvstop', $param->{service}, $user, $realcmd);
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'service_restart', 
 | 
						|
    path => '{service}/restart', 
 | 
						|
    method => 'POST',
 | 
						|
    description => "Restart service.",
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
 | 
						|
    },
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => { 
 | 
						|
	type => 'string',
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $rpcenv = PVE::RPCEnvironment::get();
 | 
						|
 | 
						|
	my $user = $rpcenv->get_user();
 | 
						|
 | 
						|
	my $realcmd = sub {
 | 
						|
	    my $upid = shift;
 | 
						|
 | 
						|
	    syslog('info', "re-starting service $param->{service}: $upid\n");
 | 
						|
 | 
						|
	    &$service_cmd($param->{service}, 'restart');
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	return $rpcenv->fork_worker('srvrestart', $param->{service}, $user, $realcmd);
 | 
						|
    }});
 | 
						|
 | 
						|
__PACKAGE__->register_method ({
 | 
						|
    name => 'service_reload', 
 | 
						|
    path => '{service}/reload', 
 | 
						|
    method => 'POST',
 | 
						|
    description => "Reload service.",
 | 
						|
    permissions => {
 | 
						|
	check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
 | 
						|
    },
 | 
						|
    proxyto => 'node',
 | 
						|
    protected => 1,
 | 
						|
    parameters => {
 | 
						|
    	additionalProperties => 0,
 | 
						|
	properties => {
 | 
						|
	    node => get_standard_option('pve-node'),
 | 
						|
	    service => $service_prop_desc,
 | 
						|
	},
 | 
						|
    },
 | 
						|
    returns => { 
 | 
						|
	type => 'string',
 | 
						|
    },
 | 
						|
    code => sub {
 | 
						|
	my ($param) = @_;
 | 
						|
  
 | 
						|
	my $rpcenv = PVE::RPCEnvironment::get();
 | 
						|
 | 
						|
	my $user = $rpcenv->get_user();
 | 
						|
 | 
						|
	my $realcmd = sub {
 | 
						|
	    my $upid = shift;
 | 
						|
 | 
						|
	    syslog('info', "reloading service $param->{service}: $upid\n");
 | 
						|
 | 
						|
	    &$service_cmd($param->{service}, 'reload');
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	return $rpcenv->fork_worker('srvreload', $param->{service}, $user, $realcmd);
 | 
						|
    }});
 |