[pve-devel] [PATCH cluster 1/2] remote.cfg: add new config file

Fabian Grünbichler f.gruenbichler at proxmox.com
Fri Mar 6 11:20:24 CET 2020


Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
the secret 'token' could of course also be split out to a second file,
or just masked when returned via the API

 data/PVE/Makefile                  |   2 +-
 data/src/status.c                  |   1 +
 data/PVE/Cluster.pm                |   1 +
 data/PVE/RemoteConfig.pm           | 226 +++++++++++++++++++++++++++++
 debian/libpve-cluster-perl.install |   1 +
 5 files changed, 230 insertions(+), 1 deletion(-)
 create mode 100644 data/PVE/RemoteConfig.pm

diff --git a/data/PVE/Makefile b/data/PVE/Makefile
index 8ee4900..78a2b02 100644
--- a/data/PVE/Makefile
+++ b/data/PVE/Makefile
@@ -11,7 +11,7 @@ PVE_VENDORARCH=${DESTDIR}/${PERL_VENDORARCH}/auto/PVE/IPCC
 PERL_DOC_INC_DIRS:=..
 
 SUBDIRS=Cluster CLI API2
-SOURCES=IPCC.pm Cluster.pm Corosync.pm RRD.pm DataCenterConfig.pm SSHInfo.pm
+SOURCES=IPCC.pm Cluster.pm Corosync.pm RRD.pm DataCenterConfig.pm SSHInfo.pm RemoteConfig.pm
 
 all:
 
diff --git a/data/src/status.c b/data/src/status.c
index 5e0cebe..9200ad2 100644
--- a/data/src/status.c
+++ b/data/src/status.c
@@ -102,6 +102,7 @@ static memdb_change_t memdb_change_array[] = {
 	{ .path = "sdn/controllers.cfg" },
 	{ .path = "sdn/controllers.cfg.new" },
 	{ .path = "virtual-guest/cpu-models.conf" },
+	{ .path = "remote.cfg" },
 };
 
 static GMutex mutex;
diff --git a/data/PVE/Cluster.pm b/data/PVE/Cluster.pm
index 068d626..78dc703 100644
--- a/data/PVE/Cluster.pm
+++ b/data/PVE/Cluster.pm
@@ -71,6 +71,7 @@ my $observed = {
     'sdn/controllers.cfg' => 1,
     'sdn/controllers.cfg.new' => 1,
     'virtual-guest/cpu-models.conf' => 1,
+    'remote.cfg' => 1,
 };
 
 sub base_dir {
diff --git a/data/PVE/RemoteConfig.pm b/data/PVE/RemoteConfig.pm
new file mode 100644
index 0000000..23274de
--- /dev/null
+++ b/data/PVE/RemoteConfig.pm
@@ -0,0 +1,226 @@
+package PVE::RemoteConfig;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools;
+
+use PVE::SectionConfig;
+
+use base qw(PVE::SectionConfig);
+
+my $remote_cfg_filename = 'remote.cfg';
+
+cfs_register_file($remote_cfg_filename,
+		  sub { __PACKAGE__->parse_config(@_); },
+		  sub { __PACKAGE__->write_config(@_); });
+
+my $defaultData = {
+    propertyList => {
+	type => { description => "Remote type." },
+	id => get_standard_option('pve-node', {
+	    description => "Remote identifier.",
+	}),
+	comment => {
+	    description => "Description.",
+	    type => 'string',
+	    optional => 1,
+	    maxLength => 4096,
+	},
+    },
+};
+
+sub private {
+    return $defaultData;
+}
+
+sub parse_section_header {
+    my ($class, $line) = @_;
+
+    if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+	my ($type, $id) = (lc($1), lc($2));
+	my $errmsg = undef; # set if you want to skip whole section
+	eval { PVE::JSONSchema::pve_verify_node_name($id); };
+	$errmsg = $@ if $@;
+	my $config = {};
+	return ($type, $id, $errmsg, $config);
+    }
+    return undef;
+}
+
+sub decode_value {
+    my ($class, $type, $key, $value) = @_;
+
+    my $def = $defaultData->{plugindata}->{$type};
+
+    if ($key eq 'nodes') {
+	my $res = {};
+
+	foreach my $node (PVE::Tools::split_list($value)) {
+	    if (PVE::JSONSchema::pve_verify_node_name($node)) {
+		$res->{$node} = 1;
+	    }
+	}
+
+	return $res;
+    }
+
+    return $value;
+}
+
+sub encode_value {
+    my ($class, $type, $key, $value) = @_;
+
+    if ($key eq 'nodes') {
+        return join(',', keys(%$value));
+    }
+
+    return $value;
+}
+
+sub parse_config {
+    my ($class, $filename, $raw) = @_;
+
+    my $cfg = $class->SUPER::parse_config($filename, $raw);
+
+    foreach my $id (sort keys %{$cfg->{ids}}) {
+	my $data = $cfg->{ids}->{$id};
+
+	if ($data->{type} eq 'cluster') {
+	    my $nodes = $data->{nodes};
+	    foreach my $node (keys %$nodes) {
+		my $node_data = $cfg->{ids}->{$node};
+		if (!defined($node_data)) {
+		    warn "Ignoring undefined remote node '$node' in remote cluster '$id'!\n";
+		    delete $nodes->{$node};
+		}
+	    }
+	}
+
+	$data->{comment} = PVE::Tools::decode_text($data->{comment})
+	    if defined($data->{comment});
+   }
+
+    return $cfg;
+}
+
+sub write_config {
+    my ($class, $filename, $cfg) = @_;
+
+    my $target_hash = {};
+
+    foreach my $id (keys %{$cfg->{ids}}) {
+	my $data = $cfg->{ids}->{$id};
+
+	if ($data->{type} eq 'cluster') {
+	    my $nodes = $data->{nodes};
+	    foreach my $node (keys %$nodes) {
+		my $node_data = $cfg->{ids}->{$node};
+		if (!defined($node_data)) {
+		    warn "Ignoring undefined remote node '$node' in remote cluster '$id'!\n";
+		    delete $nodes->{$node};
+		}
+	    }
+	}
+
+	$data->{comment} = PVE::Tools::encode_text($data->{comment})
+	    if defined($data->{comment});
+    }
+
+    return $class->SUPER::write_config($filename, $cfg);
+}
+
+sub new {
+    my ($type) = @_;
+
+    my $class = ref($type) || $type;
+
+    my $cfg = cfs_read_file($remote_cfg_filename);
+
+    return bless $cfg, $class;
+}
+
+sub write {
+    my ($cfg) = @_;
+
+    cfs_write_file($remote_cfg_filename, $cfg);
+}
+
+sub lock {
+    my ($code, $errmsg) = @_;
+
+    cfs_lock_file($remote_cfg_filename, undef, $code);
+    my $err = $@;
+    if ($err) {
+	$errmsg ? die "$errmsg: $err" : die $err;
+    }
+}
+
+package PVE::RemoteConfig::Cluster;
+
+use PVE::RemoteConfig;
+use base qw(PVE::RemoteConfig);
+
+sub type {
+    return 'pvecluster';
+}
+
+sub properties {
+    return {
+	nodes => {
+	    description => "Cluster nodes.",
+	    type => 'string', format => 'pve-node-list',
+	},
+	token => {
+	    description => "PVE API Token",
+	    type => 'string',
+	},
+    };
+}
+
+sub options {
+    return {
+	nodes => { optional => 0 },
+	comment => { optional => 1 },
+	token => { optional => 1 },
+    };
+}
+
+package PVE::RemoteConfig::Node;
+
+use PVE::JSONSchema qw(get_standard_option);
+
+use PVE::RemoteConfig;
+use base qw(PVE::RemoteConfig);
+
+sub type {
+    return 'pvenode';
+}
+
+sub properties {
+    return {
+	endpoint => {
+	    description => "Remote IP/FQDN.",
+	    type => 'string',
+	},
+	fingerprint => get_standard_option('fingerprint-sha256'),
+    };
+}
+
+sub options {
+    return {
+	endpoint => { optional => 0 },
+	fingerprint => { optional => 1 },
+	token => { optional => 1 },
+	comment => { optional => 1 },
+    };
+}
+
+
+PVE::RemoteConfig::Cluster->register();
+PVE::RemoteConfig::Node->register();
+PVE::RemoteConfig->init();
+
+1;
diff --git a/debian/libpve-cluster-perl.install b/debian/libpve-cluster-perl.install
index 51223f9..0610384 100644
--- a/debian/libpve-cluster-perl.install
+++ b/debian/libpve-cluster-perl.install
@@ -1,5 +1,6 @@
 usr/share/man/man5/datacenter.cfg.5
 usr/share/perl5/PVE/Corosync.pm
 usr/share/perl5/PVE/DataCenterConfig.pm
+usr/share/perl5/PVE/RemoteConfig.pm
 usr/share/perl5/PVE/RRD.pm
 usr/share/perl5/PVE/SSHInfo.pm
-- 
2.20.1





More information about the pve-devel mailing list