#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use PVE::INotify; use JSON; use PVE::JSONSchema qw(get_standard_option); use PVE::CLIHandler; use PVE::Cluster; use PVE::HA::Tools; use PVE::API2::HA::Resources; use PVE::API2::HA::Groups; use PVE::HA::Env::PVE2; use base qw(PVE::CLIHandler); $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin'; $ENV{LC_ALL} = 'C'; die "please run as root\n" if $> != 0; my $nodename = PVE::INotify::nodename(); __PACKAGE__->register_method ({ name => 'enable', path => 'enable', method => 'POST', description => "Enable a HA resource.", parameters => { additionalProperties => 0, properties => { sid => get_standard_option('pve-ha-resource-id'), }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; # delete state (default is 'enabled') PVE::API2::HA::Resources->update({ sid => $param->{sid}, delete => 'state' }); return undef; }}); __PACKAGE__->register_method ({ name => 'disable', path => 'disable', method => 'POST', description => "Disable a HA resource.", parameters => { additionalProperties => 0, properties => { sid => get_standard_option('pve-ha-resource-id'), }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; PVE::API2::HA::Resources->update({ sid => $param->{sid}, state => 'disabled' }); return undef; }}); my $timestamp_to_status = sub { my ($ctime, $timestamp) = @_; my $tdiff = $ctime - $timestamp; if ($tdiff > 30) { return "old timestamp - dead?"; } elsif ($tdiff < -2) { return "detected time drift!"; } else { return "active"; } }; __PACKAGE__->register_method ({ name => 'status', path => 'status', method => 'GET', description => "Display HA manger status.", parameters => { additionalProperties => 0, properties => {}, }, returns => { type => 'null' }, code => sub { my ($param) = @_; PVE::Cluster::check_cfs_quorum(); my $haenv = PVE::HA::Env::PVE2->new($nodename); my $status = $haenv->read_manager_status(); my $ctime = $haenv->get_time(); my $master = $status->{master_node}; my $status_str = &$timestamp_to_status($ctime, $status->{timestamp}); print "master_node: $master ($status_str)\n"; my $time_str = localtime($status->{timestamp}); print "last_update: $time_str\n"; foreach my $node (sort keys %{$status->{node_status}}) { my $d = $status->{node_status}->{node}; my $lrm_status = $haenv->read_lrm_status($node); if (!$lrm_status->{timestamp}) { print "lrm_status: $node (unable to read lrm status)\n"; } else { $status_str = &$timestamp_to_status($ctime, $lrm_status->{timestamp}); my $time_str = localtime($lrm_status->{timestamp}); print "lrm_status: $node ($status_str, $time_str)\n"; } } print "manager_status:\n"; print to_json($status, { pretty => 1, canonical => 1} ); return undef; }}); my $cmddef = { enable => [ __PACKAGE__, 'enable', ['sid']], disable => [ __PACKAGE__, 'disable', ['sid']], status => [ __PACKAGE__, 'status'], config => [ 'PVE::API2::HA::Resources', 'index', [], {}, sub { my $res = shift; foreach my $rec (sort { $a->{sid} cmp $b->{sid} } @$res) { my ($type, $name) = split(':', $rec->{sid}, 2); print "$type:$name\n"; foreach my $k (sort keys %$rec) { next if $k eq 'digest' || $k eq 'sid' || $k eq 'type'; print "\t$k $rec->{$k}\n"; } print "\n"; }}], groups => [ 'PVE::API2::HA::Groups', 'index', [], {}, sub { my $res = shift; foreach my $rec (sort { $a->{group} cmp $b->{group} } @$res) { print "group: $rec->{group}\n"; foreach my $k (sort keys %$rec) { next if $k eq 'digest' || $k eq 'group' || $k eq 'type'; print "\t$k $rec->{$k}\n"; } print "\n"; }}], add => [ "PVE::API2::HA::Resources", 'create', ['sid'] ], remove => [ "PVE::API2::HA::Resources", 'delete', ['sid'] ], set => [ "PVE::API2::HA::Resources", 'update', ['sid'] ], migrate => [ "PVE::API2::HA::Resources", 'migrate', ['sid', 'node'] ], relocate => [ "PVE::API2::HA::Resources", 'relocate', ['sid', 'node'] ], }; my $cmd = shift; if ($cmd && $cmd ne 'printmanpod' && $cmd ne 'verifyapi') { PVE::Cluster::check_cfs_is_mounted(); PVE::Cluster::cfs_update(); } PVE::CLIHandler::handle_cmd($cmddef, "ha-manager", $cmd, \@ARGV, undef, $0); exit 0; __END__ =head1 NAME pvecm - Proxmox VE HA Command Line Interface =head1 SYNOPSIS =include synopsis =head1 DESCRIPTION ha-manager is a program to manage the HA configuration. =include pve_copyright