also for now, use classic sectionconfig format vnet: vnet1 ipv4 10.0.0.1 ipv6 2a03:2880:f003:c07:face:b00c::2 mtu 1500 tag 2
vnet: vnet2 ipv6 2a03:2880:f003:c07:face:b00c::2 name network2 tag 3 transportzone vlanzone1 --- PVE/API2/Network/Makefile | 2 +- PVE/API2/Network/Vnet.pm | 218 +++++++++++++++++++++++++++++++++++++++++++++ PVE/Network/Makefile | 2 + PVE/Network/Vnet.pm | 121 ++++++++++--------------- PVE/Network/Vnet/Makefile | 9 ++ PVE/Network/Vnet/Plugin.pm | 99 ++++++++++++++++++++ 6 files changed, 378 insertions(+), 73 deletions(-) create mode 100644 PVE/API2/Network/Vnet.pm create mode 100644 PVE/Network/Vnet/Makefile create mode 100644 PVE/Network/Vnet/Plugin.pm diff --git a/PVE/API2/Network/Makefile b/PVE/API2/Network/Makefile index 92fa5a7..b563481 100644 --- a/PVE/API2/Network/Makefile +++ b/PVE/API2/Network/Makefile @@ -1,4 +1,4 @@ -SOURCES=Transport.pm +SOURCES=Transport.pm Vnet.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/PVE/API2/Network/Vnet.pm b/PVE/API2/Network/Vnet.pm new file mode 100644 index 0000000..74f59fc --- /dev/null +++ b/PVE/API2/Network/Vnet.pm @@ -0,0 +1,218 @@ +package PVE::API2::Network::Vnet; + +use strict; +use warnings; + +use PVE::SafeSyslog; +use PVE::Tools qw(extract_param); +use PVE::Cluster qw(cfs_read_file cfs_write_file); +use PVE::Network::Vnet; +use PVE::Network::Vnet::Plugin; +use Storable qw(dclone); +use PVE::JSONSchema qw(get_standard_option); +use PVE::RPCEnvironment; + +use PVE::RESTHandler; + +use base qw(PVE::RESTHandler); + +my $api_vnet_config = sub { + my ($cfg, $vnetid) = @_; + + my $scfg = dclone(PVE::Network::Vnet::vnet_config($cfg, $vnetid)); + $scfg->{vnet} = $vnetid; + $scfg->{digest} = $cfg->{digest}; + + return $scfg; +}; + +__PACKAGE__->register_method ({ + name => 'index', + path => '', + method => 'GET', + description => "Vnet index.", + permissions => { + description => "Only list entries where you have 'NetworkVnet.Audit' or 'NetworkVnet.Allocate' permissions on '/cluster/network/vnet/<vnet>'", + user => 'all', + }, + parameters => { + additionalProperties => 0, + properties => { + type => { + description => "Only list vnet of specific type", + type => 'string', + optional => 1, + }, + }, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => { vnet => { type => 'string'} }, + }, + links => [ { rel => 'child', href => "{vnet}" } ], + }, + code => sub { + my ($param) = @_; + + my $rpcenv = PVE::RPCEnvironment::get(); + my $authuser = $rpcenv->get_user(); + + + my $cfg = PVE::Network::Vnet::config(); + + my @sids = PVE::Network::Vnet::vnets_ids($cfg); + my $res = []; + foreach my $vnetid (@sids) { +# my $privs = [ 'NetworkVnet.Audit', 'NetworkVnet.Allocate' ]; +# next if !$rpcenv->check_any($authuser, "/cluster/network/vnet/$vnetid", $privs, 1); + + my $scfg = &$api_vnet_config($cfg, $vnetid); + next if $param->{type} && $param->{type} ne $scfg->{type}; + push @$res, $scfg; + } + + return $res; + }}); + +__PACKAGE__->register_method ({ + name => 'read', + path => '{vnet}', + method => 'GET', + description => "Read vnet configuration.", +# permissions => { +# check => ['perm', '/cluster/network/vnet/{vnet}', ['NetworkVnet.Allocate']], +# }, + + parameters => { + additionalProperties => 0, + properties => { + vnet => get_standard_option('pve-vnet-id'), + }, + }, + returns => { type => 'object' }, + code => sub { + my ($param) = @_; + + my $cfg = PVE::Network::Vnet::config(); + + return &$api_vnet_config($cfg, $param->{vnet}); + }}); + +__PACKAGE__->register_method ({ + name => 'create', + protected => 1, + path => '', + method => 'POST', + description => "Create a new network vnet.", +# permissions => { +# check => ['perm', '/cluster/network/vnet', ['NetworkVnet.Allocate']], +# }, + parameters => PVE::Network::Vnet::Plugin->createSchema(), + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $vnetid = extract_param($param, 'vnet'); + my $type = "vnet"; + my $plugin = PVE::Network::Vnet::Plugin->lookup($type); + my $opts = $plugin->check_config($vnetid, $param, 1, 1); + + PVE::Network::Vnet::lock_vnet_config( + sub { + + my $cfg = PVE::Network::Vnet::config(); + + if (my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid, 1)) { + die "network vnet ID '$vnetid' already defined\n"; + } + + $cfg->{ids}->{$vnetid} = $opts; + + PVE::Network::Vnet::write_config($cfg); + + }, "create network vnet failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'update', + protected => 1, + path => '{vnet}', + method => 'PUT', + description => "Update network vnet configuration.", +# permissions => { +# check => ['perm', '/cluster/network/vnet', ['NetworkVnet.Allocate']], +# }, + parameters => PVE::Network::Vnet::Plugin->updateSchema(), + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $vnetid = extract_param($param, 'vnet'); + my $digest = extract_param($param, 'digest'); + + PVE::Network::Vnet::lock_vnet_config( + sub { + + my $cfg = PVE::Network::Vnet::config(); + + PVE::SectionConfig::assert_if_modified($cfg, $digest); + + my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid); + my $plugin = PVE::Network::Vnet::Plugin->lookup($scfg->{type}); + my $opts = $plugin->check_config($vnetid, $param, 0, 1); + + foreach my $k (%$opts) { + $scfg->{$k} = $opts->{$k}; + } + PVE::Network::Vnet::write_config($cfg); + + }, "update network vnet failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'delete', + protected => 1, + path => '{vnet}', # /networkvnets/{vnet} + method => 'DELETE', + description => "Delete network vnet configuration.", +# permissions => { +# check => ['perm', '/networkvnets', ['NetworkVnet.Allocate']], +# }, + parameters => { + additionalProperties => 0, + properties => { + vnet => get_standard_option('pve-vnet-id', { + completion => \&PVE::Network::Vnet::complete_vnet, + }), + }, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $vnetid = extract_param($param, 'vnet'); + + PVE::Network::Vnet::lock_vnet_config( + sub { + + my $cfg = PVE::Network::Vnet::config(); + + my $scfg = PVE::Network::Vnet::vnet_config($cfg, $vnetid); + + delete $cfg->{ids}->{$vnetid}; + + PVE::Network::Vnet::write_config($cfg); + + }, "delete network vnet failed"); + + + return undef; + }}); + +1; diff --git a/PVE/Network/Makefile b/PVE/Network/Makefile index eeda1d4..dd74a2a 100644 --- a/PVE/Network/Makefile +++ b/PVE/Network/Makefile @@ -6,3 +6,5 @@ PERL5DIR=${DESTDIR}/usr/share/perl5 .PHONY: install install: for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/$$i; done + make -C Vnet install + diff --git a/PVE/Network/Vnet.pm b/PVE/Network/Vnet.pm index c20a35d..947dae6 100644 --- a/PVE/Network/Vnet.pm +++ b/PVE/Network/Vnet.pm @@ -2,93 +2,70 @@ package PVE::Network::Vnet; use strict; use warnings; +use Data::Dumper; +use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); -use PVE::JSONSchema qw(get_standard_option); -use PVE::SectionConfig; -use base qw(PVE::SectionConfig); +sub vnet_config { + my ($cfg, $vnetid, $noerr) = @_; -PVE::Cluster::cfs_register_file('network/vnet.cfg', - sub { __PACKAGE__->parse_config(@_); }, - sub { __PACKAGE__->write_config(@_); }); + die "no vnet ID specified\n" if !$vnetid; + my $scfg = $cfg->{ids}->{$vnetid}; + die "vnet '$vnetid' does not exists\n" if (!$noerr && !$scfg); -sub options { - return { - transportzone => { fixed => 1 }, - tag => { fixed => 1 }, - name => { optional => 1 }, - ipv4 => { optional => 1 }, - ipv6 => { optional => 1 }, - name => { optional => 1 }, - mtu => { optional => 1 }, - }; + return $scfg; } -my $defaultData = { - propertyList => { - transportzone => { - type => 'string', - description => "transportzone id", - optional => 1, - }, - tag => { - type => 'integer', - description => "vlan or vxlan id", - optional => 1, - }, - name => { - type => 'string', - description => "name of the network", - optional => 1, - }, - mtu => { - type => 'integer', - description => "mtu", - optional => 1, - }, - ipv4 => { - description => "Anycast router ipv4 address.", - type => 'string', format => 'ipv4', - optional => 1, - }, - ipv6 => { - description => "Anycast router ipv6 address.", - type => 'string', format => 'ipv6', - optional => 1, - }, - mac => { - type => 'boolean', - description => "Anycast router mac address", - optional => 1, - } - }, -}; +sub config { -sub type { - return 'vnet'; + return cfs_read_file("network/vnet.cfg"); } -sub private { - return $defaultData; +sub write_config { + my ($cfg) = @_; + cfs_write_file("network/vnet.cfg", $cfg); } +sub lock_vnet_config { + my ($code, $errmsg) = @_; -sub parse_section_header { - my ($class, $line) = @_; - - if ($line =~ m/^(vnet(\d+)):$/) { - my $type = 'vnet'; - my $errmsg = undef; # set if you want to skip whole section - eval { PVE::JSONSchema::pve_verify_configid($type); }; - $errmsg = $@ if $@; - my $config = {}; # to return additional attributes - return ($type, $1, $errmsg, $config); + cfs_lock_file("network/vnet.cfg", undef, $code); + my $err = $@; + if ($err) { + $errmsg ? die "$errmsg: $err" : die $err; } - return undef; } -__PACKAGE__->register(); -__PACKAGE__->init(); +sub vnets_ids { + my ($cfg) = @_; + + return keys %{$cfg->{ids}}; +} + +sub complete_vnet { + my ($cmdname, $pname, $cvalue) = @_; + + my $cfg = PVE::Network::Vnet::config(); + + return $cmdname eq 'add' ? [] : [ PVE::Network::Vnet::vnets_ids($cfg) ]; +} + + +my $format_config_line = sub { + my ($schema, $key, $value) = @_; + + my $ct = $schema->{type}; + + die "property '$key' contains a line feed\n" + if ($key =~ m/[\n\r]/) || ($value =~ m/[\n\r]/); + + if ($ct eq 'boolean') { + return "\t$key " . ($value ? 1 : 0) . "\n" + if defined($value); + } else { + return "\t$key $value\n" if "$value" ne ''; + } +}; 1; diff --git a/PVE/Network/Vnet/Makefile b/PVE/Network/Vnet/Makefile new file mode 100644 index 0000000..bac1a8c --- /dev/null +++ b/PVE/Network/Vnet/Makefile @@ -0,0 +1,9 @@ +SOURCES=Plugin.pm VlanPlugin.pm + + +PERL5DIR=${DESTDIR}/usr/share/perl5 + +.PHONY: install +install: + for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/Vnet/$$i; done + diff --git a/PVE/Network/Vnet/Plugin.pm b/PVE/Network/Vnet/Plugin.pm new file mode 100644 index 0000000..0a7053c --- /dev/null +++ b/PVE/Network/Vnet/Plugin.pm @@ -0,0 +1,99 @@ +package PVE::Network::Vnet::Plugin; + +use strict; +use warnings; + +use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); +use PVE::JSONSchema qw(get_standard_option); +use PVE::SectionConfig; + +use base qw(PVE::SectionConfig); + +PVE::Cluster::cfs_register_file('network/vnet.cfg', + sub { __PACKAGE__->parse_config(@_); }, + sub { __PACKAGE__->write_config(@_); }); + + +sub options { + return { + vnet => { optional => 1 }, + transportzone => { optional => 1 }, + tag => { optional => 1 }, + name => { optional => 1 }, + ipv4 => { optional => 1 }, + ipv6 => { optional => 1 }, + name => { optional => 1 }, + mtu => { optional => 1 }, + }; +} + +my $defaultData = { + propertyList => { + vnet => get_standard_option('pve-vnet-id', + { completion => \&PVE::Network::Vnet::complete_vnet }), + + transportzone => { + type => 'string', + description => "transportzone id", + optional => 1, + }, + tag => { + type => 'integer', + description => "vlan or vxlan id", + optional => 1, + }, + name => { + type => 'string', + description => "name of the network", + optional => 1, + }, + mtu => { + type => 'integer', + description => "mtu", + optional => 1, + }, + ipv4 => { + description => "Anycast router ipv4 address.", + type => 'string', format => 'ipv4', + optional => 1, + }, + ipv6 => { + description => "Anycast router ipv6 address.", + type => 'string', format => 'ipv6', + optional => 1, + }, + mac => { + type => 'boolean', + description => "Anycast router mac address", + optional => 1, + } + }, +}; + +sub type { + return 'vnet'; +} + +sub private { + return $defaultData; +} + + +sub parse_section_header { + my ($class, $line) = @_; + + if ($line =~ m/^(\S+):\s*(\S+)\s*$/) { + my ($type, $vnetid) = (lc($1), $2); + my $errmsg = undef; # set if you want to skip whole section + eval { PVE::JSONSchema::pve_verify_configid($type); }; + $errmsg = $@ if $@; + my $config = {}; # to return additional attributes + return ($type, $vnetid, $errmsg, $config); + } + return undef; +} + +__PACKAGE__->register(); +__PACKAGE__->init(); + +1; -- 2.11.0 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel