Upstream proxmox-git/pve-manager state of the touched files before addd95543d
This commit is contained in:
1 parent
bddd179228
commit
d0798f384d
1 file changed
+375
@@ -0,0 +1,375 @@
|
||||
package PVE::CLI::pvenode;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PVE::API2::ACME;
|
||||
use PVE::API2::ACMEAccount;
|
||||
use PVE::API2::ACMEPlugin;
|
||||
use PVE::API2::Certificates;
|
||||
use PVE::API2::NodeConfig;
|
||||
use PVE::API2::Nodes;
|
||||
use PVE::API2::Tasks;
|
||||
|
||||
use PVE::ACME::Challenge;
|
||||
use PVE::CertHelpers;
|
||||
use PVE::Certificate;
|
||||
use PVE::Exception qw(raise_param_exc raise);
|
||||
use PVE::JSONSchema qw(get_standard_option);
|
||||
use PVE::NodeConfig;
|
||||
use PVE::RPCEnvironment;
|
||||
use PVE::CLIFormatter;
|
||||
use PVE::RESTHandler;
|
||||
use PVE::CLIHandler;
|
||||
use PVE::PTY;
|
||||
|
||||
use base qw(PVE::CLIHandler);
|
||||
|
||||
my $nodename = PVE::INotify::nodename();
|
||||
|
||||
sub setup_environment {
|
||||
PVE::RPCEnvironment->setup_default_cli_env();
|
||||
}
|
||||
|
||||
my $upid_exit = sub {
|
||||
my $upid = shift;
|
||||
my $status = PVE::Tools::upid_read_status($upid);
|
||||
print "Task $status\n";
|
||||
exit(PVE::Tools::upid_status_is_error($status) ? -1 : 0);
|
||||
};
|
||||
|
||||
sub param_mapping {
|
||||
my ($name) = @_;
|
||||
|
||||
my $load_file_and_encode = sub {
|
||||
my ($filename) = @_;
|
||||
|
||||
return PVE::ACME::Challenge->encode_value(
|
||||
'string',
|
||||
'data',
|
||||
PVE::Tools::file_get_contents($filename),
|
||||
);
|
||||
};
|
||||
|
||||
my $mapping = {
|
||||
'upload_custom_cert' => [
|
||||
'certificates', 'key',
|
||||
],
|
||||
'add_plugin' => [
|
||||
[
|
||||
'data',
|
||||
$load_file_and_encode,
|
||||
"File with one key-value pair per line, will be base64url encode for storage in plugin config.",
|
||||
0,
|
||||
],
|
||||
],
|
||||
'update_plugin' => [
|
||||
[
|
||||
'data',
|
||||
$load_file_and_encode,
|
||||
"File with one key-value pair per line, will be base64url encode for storage in plugin config.",
|
||||
0,
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
return $mapping->{$name};
|
||||
}
|
||||
|
||||
__PACKAGE__->register_method({
|
||||
name => 'acme_register',
|
||||
path => 'acme_register',
|
||||
method => 'POST',
|
||||
description => "Register a new ACME account with a compatible CA.",
|
||||
parameters => {
|
||||
additionalProperties => 0,
|
||||
properties => {
|
||||
name => get_standard_option('pve-acme-account-name'),
|
||||
contact => get_standard_option('pve-acme-account-contact'),
|
||||
directory => get_standard_option('pve-acme-directory-url', {
|
||||
optional => 1,
|
||||
}),
|
||||
},
|
||||
},
|
||||
returns => { type => 'null' },
|
||||
code => sub {
|
||||
my ($param) = @_;
|
||||
|
||||
my $custom_directory = 0;
|
||||
if (!$param->{directory}) {
|
||||
my $directories = PVE::API2::ACMEAccount->get_directories({});
|
||||
print "Directory endpoints:\n";
|
||||
my $i = 0;
|
||||
while ($i < @$directories) {
|
||||
print $i, ") ", $directories->[$i]->{name}, " (", $directories->[$i]->{url},
|
||||
")\n";
|
||||
$i++;
|
||||
}
|
||||
print $i, ") Custom\n";
|
||||
|
||||
my $get_dir_selection = sub {
|
||||
my $selection = PVE::PTY::read_line("Enter selection: ");
|
||||
if ($selection =~ /^(\d+)$/) {
|
||||
$selection = $1;
|
||||
if ($selection == $i) {
|
||||
$param->{directory} = PVE::PTY::read_line("Enter custom URL: ");
|
||||
$custom_directory = 1;
|
||||
return;
|
||||
} elsif ($selection < $i && $selection >= 0) {
|
||||
$param->{directory} = $directories->[$selection]->{url};
|
||||
return;
|
||||
}
|
||||
}
|
||||
print "Invalid selection.\n";
|
||||
};
|
||||
|
||||
my $attempts = 0;
|
||||
while (!$param->{directory}) {
|
||||
die "Aborting.\n" if $attempts > 3;
|
||||
$get_dir_selection->();
|
||||
$attempts++;
|
||||
}
|
||||
}
|
||||
print "\nAttempting to fetch Terms of Service from '$param->{directory}'..\n";
|
||||
my $meta = PVE::API2::ACMEAccount->get_meta({ directory => $param->{directory} });
|
||||
if ($meta->{termsOfService}) {
|
||||
my $tos = $meta->{termsOfService};
|
||||
print "Terms of Service: $tos\n";
|
||||
my $agreed = PVE::PTY::read_line('Do you agree to the above terms? [y|N]: ');
|
||||
die "Cannot continue without agreeing to ToS, aborting.\n"
|
||||
if ($agreed !~ /^y$/i);
|
||||
|
||||
$param->{tos_url} = $tos;
|
||||
} else {
|
||||
print "No Terms of Service found, proceeding.\n";
|
||||
}
|
||||
|
||||
my $eab_enabled = $meta->{externalAccountRequired};
|
||||
if (!$eab_enabled && $custom_directory) {
|
||||
my $agreed =
|
||||
PVE::PTY::read_line('Do you want to use external account binding? [y|N]: ');
|
||||
$eab_enabled = ($agreed =~ /^y$/i);
|
||||
} elsif ($eab_enabled) {
|
||||
print "The CA requires external account binding.\n";
|
||||
}
|
||||
if ($eab_enabled) {
|
||||
print "You should have received a key id and a key from your CA.\n";
|
||||
my $eab_kid = PVE::PTY::read_line('Enter EAB key id: ');
|
||||
my $eab_hmac_key = PVE::PTY::read_line('Enter EAB key: ');
|
||||
|
||||
$param->{'eab-kid'} = $eab_kid;
|
||||
$param->{'eab-hmac-key'} = $eab_hmac_key;
|
||||
}
|
||||
|
||||
print "\nAttempting to register account with '$param->{directory}'..\n";
|
||||
|
||||
$upid_exit->(PVE::API2::ACMEAccount->register_account($param));
|
||||
},
|
||||
});
|
||||
|
||||
my $print_cert_info = sub {
|
||||
my ($schema, $cert, $options) = @_;
|
||||
|
||||
my $order = [
|
||||
qw(filename fingerprint subject issuer notbefore notafter public-key-type public-key-bits san)
|
||||
];
|
||||
PVE::CLIFormatter::print_api_result(
|
||||
$cert,
|
||||
$schema,
|
||||
$order,
|
||||
{ %$options, noheader => 1, sort_key => 0 },
|
||||
);
|
||||
};
|
||||
|
||||
our $cmddef = {
|
||||
config => {
|
||||
get => [
|
||||
'PVE::API2::NodeConfig',
|
||||
'get_config',
|
||||
[],
|
||||
{ node => $nodename },
|
||||
sub {
|
||||
my ($res) = @_;
|
||||
print PVE::NodeConfig::write_node_config($res);
|
||||
},
|
||||
],
|
||||
set => ['PVE::API2::NodeConfig', 'set_options', [], { node => $nodename }],
|
||||
},
|
||||
|
||||
startall => ['PVE::API2::Nodes::Nodeinfo', 'startall', [], { node => $nodename }],
|
||||
stopall => ['PVE::API2::Nodes::Nodeinfo', 'stopall', [], { node => $nodename }],
|
||||
migrateall =>
|
||||
['PVE::API2::Nodes::Nodeinfo', 'migrateall', ['target'], { node => $nodename }],
|
||||
|
||||
cert => {
|
||||
info => [
|
||||
'PVE::API2::Certificates',
|
||||
'info',
|
||||
[],
|
||||
{ node => $nodename },
|
||||
sub {
|
||||
my ($res, $schema, $options) = @_;
|
||||
|
||||
if (!$options->{'output-format'} || $options->{'output-format'} eq 'text') {
|
||||
for my $cert (sort { $a->{filename} cmp $b->{filename} } @$res) {
|
||||
$print_cert_info->($schema->{items}, $cert, $options);
|
||||
}
|
||||
} else {
|
||||
PVE::CLIFormatter::print_api_result($res, $schema, undef, $options);
|
||||
}
|
||||
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
set => [
|
||||
'PVE::API2::Certificates',
|
||||
'upload_custom_cert',
|
||||
['certificates', 'key'],
|
||||
{ node => $nodename },
|
||||
sub {
|
||||
my ($res, $schema, $options) = @_;
|
||||
$print_cert_info->($schema, $res, $options);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
delete =>
|
||||
['PVE::API2::Certificates', 'remove_custom_cert', ['restart'], { node => $nodename }],
|
||||
},
|
||||
|
||||
task => {
|
||||
list => [
|
||||
'PVE::API2::Tasks',
|
||||
'node_tasks',
|
||||
[],
|
||||
{ node => $nodename },
|
||||
sub {
|
||||
my ($data, $schema, $options) = @_;
|
||||
foreach my $task (@$data) {
|
||||
if (!defined($task->{status})) {
|
||||
$task->{status} = 'UNKNOWN';
|
||||
# RUNNING is set by the API call and needs to be checked explicitly
|
||||
} elsif (
|
||||
PVE::Tools::upid_status_is_error($task->{status})
|
||||
&& $task->{status} ne 'RUNNING'
|
||||
) {
|
||||
$task->{status} = 'ERROR';
|
||||
}
|
||||
}
|
||||
PVE::CLIFormatter::print_api_result(
|
||||
$data,
|
||||
$schema,
|
||||
['upid', 'type', 'id', 'user', 'starttime', 'endtime', 'status'],
|
||||
$options,
|
||||
);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
status => [
|
||||
'PVE::API2::Tasks',
|
||||
'read_task_status',
|
||||
['upid'],
|
||||
{ node => $nodename },
|
||||
sub {
|
||||
my ($data, $schema, $options) = @_;
|
||||
PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
# set limit to 1000000, so we see the whole log, not only the first 50 lines by default
|
||||
log => [
|
||||
'PVE::API2::Tasks',
|
||||
'read_task_log',
|
||||
['upid'],
|
||||
{ node => $nodename, limit => 1000000 },
|
||||
sub {
|
||||
my ($data, $resultprops) = @_;
|
||||
foreach my $line (@$data) {
|
||||
print $line->{t} . "\n";
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
acme => {
|
||||
account => {
|
||||
list => [
|
||||
'PVE::API2::ACMEAccount',
|
||||
'account_index',
|
||||
[],
|
||||
{},
|
||||
sub {
|
||||
my ($res) = @_;
|
||||
for my $acc (@$res) {
|
||||
print "$acc->{name}\n";
|
||||
}
|
||||
},
|
||||
],
|
||||
register => [__PACKAGE__, 'acme_register', ['name', 'contact'], {}, $upid_exit],
|
||||
deactivate =>
|
||||
['PVE::API2::ACMEAccount', 'deactivate_account', ['name'], {}, $upid_exit],
|
||||
info => [
|
||||
'PVE::API2::ACMEAccount',
|
||||
'get_account',
|
||||
['name'],
|
||||
{},
|
||||
sub {
|
||||
my ($data, $schema, $options) = @_;
|
||||
PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
update => ['PVE::API2::ACMEAccount', 'update_account', ['name'], {}, $upid_exit],
|
||||
},
|
||||
cert => {
|
||||
order =>
|
||||
['PVE::API2::ACME', 'new_certificate', [], { node => $nodename }, $upid_exit],
|
||||
renew =>
|
||||
['PVE::API2::ACME', 'renew_certificate', [], { node => $nodename }, $upid_exit],
|
||||
revoke =>
|
||||
['PVE::API2::ACME', 'revoke_certificate', [], { node => $nodename }, $upid_exit],
|
||||
},
|
||||
plugin => {
|
||||
list => [
|
||||
'PVE::API2::ACMEPlugin',
|
||||
'index',
|
||||
[],
|
||||
{},
|
||||
sub {
|
||||
my ($data, $schema, $options) = @_;
|
||||
PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
config => [
|
||||
'PVE::API2::ACMEPlugin',
|
||||
'get_plugin_config',
|
||||
['id'],
|
||||
{},
|
||||
sub {
|
||||
my ($data, $schema, $options) = @_;
|
||||
PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
|
||||
},
|
||||
$PVE::RESTHandler::standard_output_options,
|
||||
],
|
||||
add => ['PVE::API2::ACMEPlugin', 'add_plugin', ['type', 'id']],
|
||||
set => ['PVE::API2::ACMEPlugin', 'update_plugin', ['id']],
|
||||
remove => ['PVE::API2::ACMEPlugin', 'delete_plugin', ['id']],
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
wakeonlan => [
|
||||
'PVE::API2::Nodes::Nodeinfo',
|
||||
'wakeonlan',
|
||||
['node'],
|
||||
{},
|
||||
sub {
|
||||
my ($mac_addr) = @_;
|
||||
|
||||
print "Wake on LAN packet send for '$mac_addr'\n";
|
||||
},
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
1;
|
||||
Reference in new issue
Block a user