diff options
| -rw-r--r-- | debian/control | 1 | ||||
| -rw-r--r-- | src/PVE/Network/SDN.pm | 54 | ||||
| -rwxr-xr-x | src/test/run_test_vnets_blackbox.pl | 26 |
3 files changed, 73 insertions, 8 deletions
diff --git a/debian/control b/debian/control index f64a2d4..b45d126 100644 --- a/debian/control +++ b/debian/control @@ -26,6 +26,7 @@ Depends: libpve-common-perl (>= 9.0.2), libnet-ip-perl, libnetaddr-ip-perl, libpve-rs-perl (>= 0.10.3), + libuuid-perl, ${misc:Depends}, ${perl:Depends}, Recommends: frr-pythontools (>= 10.3.1-1+pve2~), diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm index 0e7d1df..9f18f76 100644 --- a/src/PVE/Network/SDN.pm +++ b/src/PVE/Network/SDN.pm @@ -8,12 +8,13 @@ use IO::Socket::SSL; # important for SSL_verify_callback use JSON qw(decode_json from_json to_json); use LWP::UserAgent; use Net::SSLeay; +use UUID; use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); use PVE::INotify; use PVE::RESTEnvironment qw(log_warn); use PVE::RPCEnvironment; -use PVE::Tools qw(extract_param dir_glob_regex run_command); +use PVE::Tools qw(file_get_contents file_set_contents extract_param dir_glob_regex run_command); use PVE::Network::SDN::Vnets; use PVE::Network::SDN::Zones; @@ -48,6 +49,8 @@ my $write_running_cfg = sub { PVE::Cluster::cfs_register_file($running_cfg, $parse_running_cfg, $write_running_cfg); +my $LOCK_TOKEN_FILE = "/etc/pve/sdn/.lock"; + # improve me : move status code inside plugins ? sub ifquery_check { @@ -197,14 +200,57 @@ sub commit_config { cfs_write_file($running_cfg, $cfg); } +sub generate_lock_token { + my $str; + my $uuid; + + UUID::generate_v7($uuid); + UUID::unparse($uuid, $str); + + return $str; +} + +sub create_global_lock { + my $token = generate_lock_token(); + PVE::Tools::file_set_contents($LOCK_TOKEN_FILE, $token); + return $token; +} + +sub delete_global_lock { + unlink $LOCK_TOKEN_FILE if -e $LOCK_TOKEN_FILE; +} + sub lock_sdn_config { - my ($code, $errmsg) = @_; + my ($code, $errmsg, $lock_token_user) = @_; - cfs_lock_file($running_cfg, undef, $code); + my $lock_wrapper = sub { + my $lock_token = undef; + if (-e $LOCK_TOKEN_FILE) { + $lock_token = PVE::Tools::file_get_contents($LOCK_TOKEN_FILE); + } + + if ( + defined($lock_token) + && (!defined($lock_token_user) || $lock_token ne $lock_token_user) + ) { + die "invalid lock token provided!"; + } + + return $code->(); + }; - if (my $err = $@) { + return lock_sdn_domain($lock_wrapper, $errmsg); +} + +sub lock_sdn_domain { + my ($code, $errmsg) = @_; + + my $res = PVE::Cluster::cfs_lock_domain("sdn", undef, $code); + my $err = $@; + if ($err) { $errmsg ? die "$errmsg: $err" : die $err; } + return $res; } sub get_local_vnets { diff --git a/src/test/run_test_vnets_blackbox.pl b/src/test/run_test_vnets_blackbox.pl index 2e1c505..468b1ed 100755 --- a/src/test/run_test_vnets_blackbox.pl +++ b/src/test/run_test_vnets_blackbox.pl @@ -33,7 +33,10 @@ my $test_state = undef; sub clear_test_state { $test_state = { - locks => {}, + locks => { + file => {}, + domain => {}, + }, datacenter_config => {}, subnets_config => {}, controller_config => {}, @@ -57,13 +60,27 @@ clear_test_state(); my $mocked_cfs_lock_file = sub { my ($filename, $timeout, $code, @param) = @_; - die "$filename already locked\n" if ($test_state->{locks}->{$filename}); + die "$filename already locked\n" if $test_state->{locks}->{file}->{$filename}; - $test_state->{locks}->{$filename} = 1; + $test_state->{locks}->{file}->{$filename} = 1; my $res = eval { $code->(@param); }; - delete $test_state->{locks}->{$filename}; + delete $test_state->{locks}->{file}->{$filename}; + + return $res; +}; + +my $mocked_cfs_lock_domain = sub { + my ($domain, $timeout, $code, @param) = @_; + + die "domain '$domain' already locked\n" if $test_state->{locks}->{domain}->{$domain}; + + $test_state->{locks}->{domain}->{$domain} = 1; + + my $res = eval { $code->(@param) }; + + delete $test_state->{locks}->{domain}->{$domain}; return $res; }; @@ -224,6 +241,7 @@ $mocked_rpc_env_obj->mock( my $mocked_pve_cluster_obj = Test::MockModule->new('PVE::Cluster'); $mocked_pve_cluster_obj->mock( check_cfs_quorum => sub { return 1; }, + cfs_lock_domain => $mocked_cfs_lock_domain, ); # ------- TEST FUNCTIONS -------------- |
