[pve-devel] [PATCH pve-client 5/6] use SectionConfig for PVE::APIClient::Config
Dietmar Maurer
dietmar at proxmox.com
Tue Jun 5 12:17:43 CEST 2018
Signed-off-by: Dietmar Maurer <dietmar at proxmox.com>
---
PVE/APIClient/Commands/lxc.pm | 3 +-
PVE/APIClient/Commands/remote.pm | 128 ++++++++++++++++++----------
PVE/APIClient/Config.pm | 177 ++++++++++++++++++++-------------------
3 files changed, 179 insertions(+), 129 deletions(-)
diff --git a/PVE/APIClient/Commands/lxc.pm b/PVE/APIClient/Commands/lxc.pm
index 7403143..250d5f3 100644
--- a/PVE/APIClient/Commands/lxc.pm
+++ b/PVE/APIClient/Commands/lxc.pm
@@ -147,7 +147,8 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- my $conn = PVE::APIClient::Config->new()->remote_conn($param->{remote});
+ my $config = PVE::APIClient::Config->load();
+ my $conn = PVE::APIClient::Config->remote_conn($config, $param->{remote});
# Get the real node from the resources endpoint
my $resource_list = $conn->get("api2/json/cluster/resources", { type => 'vm'});
diff --git a/PVE/APIClient/Commands/remote.pm b/PVE/APIClient/Commands/remote.pm
index 5d04e3a..06bc1b6 100644
--- a/PVE/APIClient/Commands/remote.pm
+++ b/PVE/APIClient/Commands/remote.pm
@@ -4,6 +4,7 @@ use strict;
use warnings;
use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools qw(extract_param);
use PVE::APIClient::Config;
use PVE::CLIHandler;
@@ -27,14 +28,13 @@ __PACKAGE__->register_method ({
},
returns => { type => 'null' },
code => sub {
- my $config = PVE::APIClient::Config->new();
- my $known_remotes = $config->remote_names;
+ my $config = PVE::APIClient::Config->load();
printf("%10s %10s %10s %10s %100s\n", "Name", "Host", "Port", "Username", "Fingerprint");
- for my $name (@$known_remotes) {
- my $remote = $config->lookup_remote($name);
+ for my $name (keys %{$config->{ids}}) {
+ my $remote = $config->{ids}->{$name};
printf("%10s %10s %10s %10s %100s\n", $name, $remote->{'host'},
- $remote->{'port'}, $remote->{'username'}, $remote->{'fingerprint'});
+ $remote->{'port'} // '-', $remote->{'username'}, $remote->{'fingerprint'} // '-');
}
return undef;
@@ -45,48 +45,42 @@ __PACKAGE__->register_method ({
path => 'add',
method => 'POST',
description => "Add a remote to your config file.",
- parameters => {
- additionalProperties => 0,
- properties => {
- name => get_standard_option('pveclient-remote-name', { completion => sub {} }),
- host => {
- description => "The host.",
- type => 'string',
- format => 'address',
- },
- username => {
- description => "The username.",
- type => 'string',
- },
- password => {
- description => "The users password",
- type => 'string',
- },
- port => {
- description => "The port",
- type => 'integer',
- optional => 1,
- default => 8006,
- }
- },
- },
+ parameters => PVE::APIClient::Config->createSchema(1),
returns => { type => 'null'},
code => sub {
my ($param) = @_;
- my $config = PVE::APIClient::Config->new();
- my $known_remotes = $config->remotes;
+ # fixme: lock config file
- if (exists($known_remotes->{$param->{name}})) {
- die "Remote \"$param->{name}\" exists, remove it first\n";
- }
+ my $remote = $param->{name};
+
+ my $config = PVE::APIClient::Config->load();
+
+ die "Remote '$remote' already exists\n"
+ if $config->{ids}->{$remote};
my $last_fp = 0;
- my $api = PVE::APIClient::LWP->new(
+
+ my $setup = {
username => $param->{username},
password => $param->{password},
host => $param->{host},
port => $param->{port} // 8006,
+ };
+
+ if ($param->{fingerprint}) {
+ $setup->{cached_fingerprints} = {
+ $param->{fingerprint} => 1,
+ };
+ } else {
+ $setup->{manual_verification} = 1;
+ $setup->{register_fingerprint_cb} = sub {
+ my $fp = shift @_;
+ $last_fp = $fp;
+ };
+ }
+
+ my $api = PVE::APIClient::LWP->new(
manual_verification => 1,
register_fingerprint_cb => sub {
my $fp = shift @_;
@@ -95,9 +89,56 @@ __PACKAGE__->register_method ({
);
$api->login();
- $config->add_remote($param->{name}, $param->{host}, $param->{port} // 8006,
- $last_fp, $param->{username}, $param->{password});
- $config->save;
+ $param->{fingerprint} = $last_fp if !defined($param->{fingerprint});
+ my $plugin = PVE::APIClient::Config->lookup('remote');
+ my $opts = $plugin->check_config($remote, $param, 1, 1);
+ $config->{ids}->{$remote} = $opts;
+
+ PVE::APIClient::Config->save($config);
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ path => 'update',
+ method => 'PUT',
+ description => "Update a remote configuration.",
+ parameters => PVE::APIClient::Config->updateSchema(1),
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ # fixme: lock config file
+
+ my $name = extract_param($param, 'name');
+ my $digest = extract_param($param, 'digest');
+ my $delete = extract_param($param, 'delete');
+
+ my $config = PVE::APIClient::Config->load();
+ my $remote = PVE::APIClient::Config->lookup_remote($config, $name);
+
+ my $plugin = PVE::APIClient::Config->lookup('remote');
+ my $opts = $plugin->check_config($name, $param, 0, 1);
+
+ foreach my $k (%$opts) {
+ $remote->{$k} = $opts->{$k};
+ }
+
+ if ($delete) {
+ my $options = $plugin->private()->{options}->{'remote'};
+ foreach my $k (PVE::Tools::split_list($delete)) {
+ my $d = $options->{$k} ||
+ die "no such option '$k'\n";
+ die "unable to delete required option '$k'\n"
+ if !$d->{optional};
+ die "unable to delete fixed option '$k'\n"
+ if $d->{fixed};
+ delete $remote->{$k};
+ }
+ }
+
+ PVE::APIClient::Config->save($config);
return undef;
}});
@@ -117,15 +158,18 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- my $config = PVE::APIClient::Config->new();
- $config->remove_remote($param->{name});
- $config->save;
+ # fixme: lock config
+
+ my $config = PVE::APIClient::Config->load();
+ delete $config->{ids}->{$param->{name}};
+ PVE::APIClient::Config->save($config);
return undef;
}});
our $cmddef = {
add => [ __PACKAGE__, 'add', ['name', 'host', 'username']],
+ update => [ __PACKAGE__, 'update', ['name']],
remove => [ __PACKAGE__, 'remove', ['name']],
list => [__PACKAGE__, 'list'],
};
diff --git a/PVE/APIClient/Config.pm b/PVE/APIClient/Config.pm
index 40caed8..8a77848 100644
--- a/PVE/APIClient/Config.pm
+++ b/PVE/APIClient/Config.pm
@@ -6,12 +6,15 @@ use JSON;
use File::HomeDir ();
use PVE::JSONSchema qw(register_standard_option get_standard_option);
+use PVE::SectionConfig;
use PVE::Tools qw(file_get_contents file_set_contents);
+use base qw(PVE::SectionConfig);
+
my $complete_remote_name = sub {
- my $config = PVE::APIClient::Config->new();
- return $config->remote_names;
+ my $config = PVE::APIClient::Config->load();
+ return [keys %{$config->{ids}}];
};
register_standard_option('pveclient-remote-name', {
@@ -21,118 +24,117 @@ register_standard_option('pveclient-remote-name', {
completion => $complete_remote_name,
});
-sub new {
- my ($class) = @_;
-
- my $self = {
- file => File::HomeDir::home() . '/.pveclient',
- };
- bless $self => $class;
- $self->load();
+my $defaultData = {
+ propertyList => {
+ type => {
+ description => "Section type.",
+ optional => 1,
+ },
+ name => get_standard_option('pveclient-remote-name'),
+ host => {
+ description => "The host.",
+ type => 'string', format => 'address',
+ optional => 1,
+ },
+ username => {
+ description => "The username.",
+ type => 'string',
+ optional => 1,
+ },
+ password => {
+ description => "The users password.",
+ type => 'string',
+ optional => 1,
+ },
+ port => {
+ description => "The port.",
+ type => 'integer',
+ optional => 1,
+ default => 8006,
+ },
+ fingerprint => {
+ description => "Fingerprint.",
+ type => 'string',
+ optional => 1,
+ },
+ comment => {
+ description => "Description.",
+ type => 'string',
+ optional => 1,
+ maxLength => 4096,
+ },
+ },
+};
- return $self;
+sub type {
+ return 'remote';
}
-sub load {
- my ($self) = @_;
-
- if (-e $self->{file}) {
- my $filemode = (stat($self->{file}))[2] & 07777;
- if ($filemode != 0600) {
- die sprintf "wrong permissions on '$self->{file}' %04o (expected 0600)\n", $filemode;
- }
-
- my $contents = file_get_contents($self->{file});
- $self->{data} = from_json($contents);
- } else {
- $self->{data} = {};
- }
-
- if (!exists($self->{data}->{remotes})) {
- $self->{data}->{remotes} = {};
- }
-
- # Verify config
- for my $name (@{$self->remote_names}) {
- my $cfg = $self->{data}->{remotes}->{$name};
-
- foreach my $opt (qw(host port username fingerprint)) {
- die "missing option '$opt' (remote '$name')" if !defined($cfg->{$opt});
- }
- }
+sub options {
+ return {
+ name => { optional => 0 },
+ host => { optional => 0 },
+ comment => { optional => 1 },
+ username => { optional => 0 },
+ password => { optional => 0 },
+ port => { optional => 1 },
+ fingerprint => { optional => 1 },
+ };
}
-sub save {
- my ($self) = @_;
-
- my $contents = to_json($self->{data}, {pretty => 1, canonical => 1});
- file_set_contents($self->{file}, $contents, 0600);
+sub private {
+ return $defaultData;
}
-sub add_remote {
- my ($self, $name, $host, $port, $fingerprint, $username, $password) = @_;
-
- $self->{data}->{remotes}->{$name} = {
- host => $host,
- port => $port,
- fingerprint => $fingerprint,
- username => $username,
- };
+sub config_filename {
+ my ($class) = @_;
- if (defined($password)) {
- $self->{data}->{remotes}->{$name}->{password} = $password;
- }
+ return File::HomeDir::home() . '/.pveclient';
}
-sub remote_names {
- my ($self) = @_;
+sub load {
+ my ($class) = @_;
- return [keys %{$self->{data}->{remotes}}];
-}
+ my $filename = $class->config_filename();
-sub lookup_remote {
- my ($self, $name) = @_;
+ my $raw = '';
- die "Unknown remote \"$name\" given"
- if (!exists($self->{data}->{remotes}->{$name}));
+ if (-e $filename) {
+ my $filemode = (stat($filename))[2] & 07777;
+ if ($filemode != 0600) {
+ die sprintf "wrong permissions on '$filename' %04o (expected 0600)\n", $filemode;
+ }
- return $self->{data}->{remotes}->{$name};
-}
+ $raw = file_get_contents($filename);
+ }
-sub remotes {
- my ($self) = @_;
+ return $class->parse_config($filename, $raw);
+}
- my $res = {};
+sub save {
+ my ($class, $cfg) = @_;
- # Remove the password from each remote.
- for my $name ($self->remote_names) {
- my $cfg = $self->{data}->{remotes}->{$name};
- $res->{$name} = {
- host => $cfg->{host},
- port => $cfg->{port},
- username => $cfg->{username},
- fingerprint => $cfg->{fingerprint},
- };
- }
+ my $filename = $class->config_filename();
+ my $raw = $class->write_config($filename, $cfg);
- return $res;
+ file_set_contents($filename, $raw, 0600);
}
-sub remove_remote {
- my ($self, $remote) = @_;
+sub lookup_remote {
+ my ($class, $cfg, $name, $noerr) = @_;
- $self->lookup_remote($remote);
+ my $data = $cfg->{ids}->{$name};
- delete($self->{data}->{remotes}->{$remote});
+ return $data if $noerr || defined($data);
- $self->save();
+ die "unknown remote \"$name\"\n";
}
sub remote_conn {
- my ($self, $remote) = @_;
+ my ($class, $cfg, $remote) = @_;
- my $section = $self->lookup_remote($remote);
+ my $section = $class->lookup_remote($cfg, $remote);
my $conn = PVE::APIClient::LWP->new(
username => $section->{username},
password => $section->{password},
@@ -148,4 +150,7 @@ sub remote_conn {
return $conn;
}
+__PACKAGE__->register();
+__PACKAGE__->init();
+
1;
--
2.11.0
More information about the pve-devel
mailing list