X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2FPVE%2FAPI2%2FHA%2FResources.pm;h=1ffdf2ef488f75833b140a71285275152105489a;hb=289e47849216182923a79a58023a0cbf829c5625;hp=d4b4b7189f38e37ea5bc56f519c5a27b018b606d;hpb=66c7e7eff93cd167365652871896d267787835d8;p=pve-ha-manager.git diff --git a/src/PVE/API2/HA/Resources.pm b/src/PVE/API2/HA/Resources.pm index d4b4b71..1ffdf2e 100644 --- a/src/PVE/API2/HA/Resources.pm +++ b/src/PVE/API2/HA/Resources.pm @@ -12,7 +12,6 @@ use HTTP::Status qw(:constants); use Storable qw(dclone); use PVE::JSONSchema qw(get_standard_option); use PVE::RPCEnvironment; -use Data::Dumper; use PVE::RESTHandler; @@ -22,8 +21,6 @@ use base qw(PVE::RESTHandler); my $resource_type_enum = PVE::HA::Resources->lookup_types(); -# fixme: fix permissions - my $api_copy_config = sub { my ($cfg, $sid) = @_; @@ -36,11 +33,26 @@ my $api_copy_config = sub { return $scfg; }; +sub check_service_state { + my ($sid, $req_state) = @_; + + my $service_status = PVE::HA::Config::get_service_status($sid); + if ($service_status->{managed} && $service_status->{state} eq 'error') { + # service in error state, must get disabled before new state request + # can be executed + return if defined($req_state) && $req_state eq 'disabled'; + die "service '$sid' in error state, must be disabled and fixed first\n"; + } +} + __PACKAGE__->register_method ({ name => 'index', path => '', method => 'GET', description => "List HA resources.", + permissions => { + check => ['perm', '/', [ 'Sys.Audit' ]], + }, parameters => { additionalProperties => 0, properties => { @@ -83,6 +95,9 @@ __PACKAGE__->register_method ({ name => 'read', path => '{sid}', method => 'GET', + permissions => { + check => ['perm', '/', [ 'Sys.Audit' ]], + }, description => "Read resource configuration.", parameters => { additionalProperties => 0, @@ -91,13 +106,50 @@ __PACKAGE__->register_method ({ { completion => \&PVE::HA::Tools::complete_sid }), }, }, - returns => {}, + returns => { + type => 'object', + properties => { + sid => get_standard_option('pve-ha-resource-or-vm-id'), + digest => { + type => 'string', + description => 'Can be used to prevent concurrent modifications.', + }, + type => { + type => 'string', + description => 'The type of the resources.', + }, + state => { + type => 'string', + enum => ['started', 'stopped', 'enabled', 'disabled', 'ignored'], + optional => 1, + description => "Requested resource state.", + }, + group => get_standard_option('pve-ha-group-id', { optional => 1, }), + max_restart => { + description => "Maximal number of tries to restart the service on". + " a node after its start failed.", + type => 'integer', + optional => 1, + }, + max_relocate => { + description => "Maximal number of service relocate tries when a". + " service failes to start.", + type => 'integer', + optional => 1, + }, + comment => { + description => "Description.", + type => 'string', + optional => 1, + }, + }, + }, code => sub { my ($param) = @_; my $cfg = PVE::HA::Config::read_resources_config(); - my $sid = PVE::HA::Tools::parse_sid($param->{sid}); + my $sid = PVE::HA::Config::parse_sid($param->{sid}); return &$api_copy_config($cfg, $sid); }}); @@ -107,6 +159,9 @@ __PACKAGE__->register_method ({ protected => 1, path => '', method => 'POST', + permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], + }, description => "Create a new HA resource.", parameters => PVE::HA::Resources->createSchema(), returns => { type => 'null' }, @@ -116,8 +171,8 @@ __PACKAGE__->register_method ({ # create /etc/pve/ha directory PVE::Cluster::check_cfs_quorum(); mkdir("/etc/pve/ha"); - - my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid')); + + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); if (my $param_type = extract_param($param, 'type')) { # useless, but do it anyway @@ -127,6 +182,8 @@ __PACKAGE__->register_method ({ my $plugin = PVE::HA::Resources->lookup($type); $plugin->verify_name($name); + $plugin->exists($name); + my $opts = $plugin->check_config($sid, $param, 1, 1); PVE::HA::Config::lock_ha_domain( @@ -153,6 +210,9 @@ __PACKAGE__->register_method ({ path => '{sid}', method => 'PUT', description => "Update resource configuration.", + permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], + }, parameters => PVE::HA::Resources->updateSchema(), returns => { type => 'null' }, code => sub { @@ -161,13 +221,22 @@ __PACKAGE__->register_method ({ my $digest = extract_param($param, 'digest'); my $delete = extract_param($param, 'delete'); - my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid')); + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); if (my $param_type = extract_param($param, 'type')) { # useless, but do it anyway die "types does not match\n" if $param_type ne $type; } + if (my $group = $param->{group}) { + my $group_cfg = PVE::HA::Config::read_group_config(); + + die "HA group '$group' does not exist\n" + if !$group_cfg->{ids}->{$group}; + } + + check_service_state($sid, $param->{state}); + PVE::HA::Config::lock_ha_domain( sub { @@ -211,6 +280,9 @@ __PACKAGE__->register_method ({ path => '{sid}', method => 'DELETE', description => "Delete resource configuration.", + permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], + }, parameters => { additionalProperties => 0, properties => { @@ -222,18 +294,23 @@ __PACKAGE__->register_method ({ code => sub { my ($param) = @_; - my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid')); + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); - PVE::HA::Config::lock_ha_domain( - sub { + my $cfg = PVE::HA::Config::read_resources_config(); - my $cfg = PVE::HA::Config::read_resources_config(); + # cannot use service_is_ha_managed as it ignores 'ignored' services, + # see bug report #1602 + if (!defined($cfg->{ids}) || !defined($cfg->{ids}->{$sid})) { + die "cannot delete service '$sid', not HA managed!\n"; + } - delete $cfg->{ids}->{$sid}; + PVE::HA::Config::lock_ha_domain(sub { - PVE::HA::Config::write_resources_config($cfg) + $cfg = PVE::HA::Config::read_resources_config(); + delete $cfg->{ids}->{$sid} or die "'$sid' not configured!\n"; + PVE::HA::Config::write_resources_config($cfg); - }, "delete storage failed"); + }, "delete resource failed"); return undef; }}); @@ -244,23 +321,32 @@ __PACKAGE__->register_method ({ path => '{sid}/migrate', method => 'POST', description => "Request resource migration (online) to another node.", + permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], + }, parameters => { additionalProperties => 0, properties => { sid => get_standard_option('pve-ha-resource-or-vm-id', { completion => \&PVE::HA::Tools::complete_sid }), - node => get_standard_option('pve-node', - { completion => \&PVE::Cluster::get_nodelist }), + node => get_standard_option('pve-node', { + completion => \&PVE::Cluster::complete_migration_target, + description => "Target node.", + }), }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; - my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid')); + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); + + PVE::HA::Config::service_is_ha_managed($sid); + + check_service_state($sid); PVE::HA::Config::queue_crm_commands("migrate $sid $param->{node}"); - + return undef; }}); @@ -270,23 +356,32 @@ __PACKAGE__->register_method ({ path => '{sid}/relocate', method => 'POST', description => "Request resource relocatzion to another node. This stops the service on the old node, and restarts it on the target node.", + permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], + }, parameters => { additionalProperties => 0, properties => { sid => get_standard_option('pve-ha-resource-or-vm-id', { completion => \&PVE::HA::Tools::complete_sid }), - node => get_standard_option('pve-node', - { completion => \&PVE::Cluster::get_nodelist }), + node => get_standard_option('pve-node', { + completion => \&PVE::Cluster::complete_migration_target, + description => "Target node.", + }), }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; - my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid')); + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); + + PVE::HA::Config::service_is_ha_managed($sid); + + check_service_state($sid); PVE::HA::Config::queue_crm_commands("relocate $sid $param->{node}"); - + return undef; }});