use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
use PVE::RPCEnvironment;
-use Data::Dumper;
use PVE::RESTHandler;
my $resource_type_enum = PVE::HA::Resources->lookup_types();
-# fixme: fix permissions
-
my $api_copy_config = sub {
my ($cfg, $sid) = @_;
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 => {
my ($param) = @_;
my $cfg = PVE::HA::Config::read_resources_config();
+ my $groups = PVE::HA::Config::read_group_config();
my $res = [];
foreach my $sid (keys %{$cfg->{ids}}) {
my $scfg = &$api_copy_config($cfg, $sid);
next if $param->{type} && $param->{type} ne $scfg->{type};
+ if ($scfg->{group} && !$groups->{ids}->{$scfg->{group}}) {
+ $scfg->{errors}->{group} = "group '$scfg->{group}' does not exist";
+ }
push @$res, $scfg;
}
name => 'read',
path => '{sid}',
method => 'GET',
+ permissions => {
+ check => ['perm', '/', [ 'Sys.Audit' ]],
+ },
description => "Read resource configuration.",
parameters => {
additionalProperties => 0,
properties => {
- sid => get_standard_option('pve-ha-resource-id'),
+ sid => get_standard_option('pve-ha-resource-or-vm-id',
+ { completion => \&PVE::HA::Tools::complete_sid }),
},
},
returns => {},
my $cfg = PVE::HA::Config::read_resources_config();
- return &$api_copy_config($cfg, $param->{sid});
+ my $sid = PVE::HA::Tools::parse_sid($param->{sid});
+
+ return &$api_copy_config($cfg, $sid);
}});
__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' },
PVE::Cluster::check_cfs_quorum();
mkdir("/etc/pve/ha");
- my $sid = extract_param($param, 'sid');
- my ($type, $name) = PVE::HA::Tools::parse_sid($sid);
+ my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
if (my $param_type = extract_param($param, 'type')) {
# useless, but do it anyway
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_config(
+ PVE::HA::Config::lock_ha_domain(
sub {
my $cfg = PVE::HA::Config::read_resources_config();
$cfg->{ids}->{$sid} = $opts;
- PVE::HA::Env::PVE2::write_resources_config($cfg)
+ PVE::HA::Config::write_resources_config($cfg)
}, "create resource failed");
path => '{sid}',
method => 'PUT',
description => "Update resource configuration.",
+ permissions => {
+ check => ['perm', '/', [ 'Sys.Console' ]],
+ },
parameters => PVE::HA::Resources->updateSchema(),
returns => { type => 'null' },
code => sub {
my $digest = extract_param($param, 'digest');
my $delete = extract_param($param, 'delete');
- my $sid = extract_param($param, 'sid');
- my ($type, $name) = PVE::HA::Tools::parse_sid($sid);
+ my ($sid, $type, $name) = PVE::HA::Tools::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;
}
- PVE::HA::Config::lock_ha_config(
+ 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 {
my $cfg = PVE::HA::Config::read_resources_config();
path => '{sid}',
method => 'DELETE',
description => "Delete resource configuration.",
+ permissions => {
+ check => ['perm', '/', [ 'Sys.Console' ]],
+ },
parameters => {
additionalProperties => 0,
properties => {
- sid => get_standard_option('pve-ha-resource-id'),
+ sid => get_standard_option('pve-ha-resource-or-vm-id',
+ { completion => \&PVE::HA::Tools::complete_sid }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- my $sid = extract_param($param, 'sid');
+ my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
- PVE::HA::Config::lock_ha_config(
+ PVE::HA::Config::service_is_ha_managed($sid);
+
+ PVE::HA::Config::lock_ha_domain(
sub {
my $cfg = PVE::HA::Config::read_resources_config();
PVE::HA::Config::write_resources_config($cfg)
- }, "delete storage failed");
+ }, "delete resource failed");
return undef;
}});
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-id'),
- node => get_standard_option('pve-node'),
+ 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 }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- PVE::HA::Config::queue_crm_commands("migrate $param->{sid} $param->{node}");
+ my ($sid, $type, $name) = PVE::HA::Tools::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;
}});
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-id'),
- node => get_standard_option('pve-node'),
+ 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 }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- PVE::HA::Config::queue_crm_commands("relocate $param->{sid} $param->{node}");
+ my ($sid, $type, $name) = PVE::HA::Tools::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;
}});