]> git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN.pm
controllers: add generate_controller_rawconfig
[pve-network.git] / PVE / Network / SDN.pm
1 package PVE::Network::SDN;
2
3 use strict;
4 use warnings;
5
6 use Data::Dumper;
7 use JSON;
8
9 use PVE::Network::SDN::Vnets;
10 use PVE::Network::SDN::Zones;
11 use PVE::Network::SDN::Controllers;
12 use PVE::Network::SDN::Subnets;
13
14 use PVE::Tools qw(extract_param dir_glob_regex run_command);
15 use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
16
17
18 my $running_cfg = "sdn/.running-config";
19
20 my $parse_running_cfg = sub {
21 my ($filename, $raw) = @_;
22
23 my $cfg = {};
24
25 return $cfg if !defined($raw) || $raw eq '';
26
27 eval {
28 $cfg = from_json($raw);
29 };
30 return {} if $@;
31
32 return $cfg;
33 };
34
35 my $write_running_cfg = sub {
36 my ($filename, $cfg) = @_;
37
38 my $json = to_json($cfg);
39
40 return $json;
41 };
42
43 PVE::Cluster::cfs_register_file($running_cfg, $parse_running_cfg, $write_running_cfg);
44
45
46 # improve me : move status code inside plugins ?
47
48 sub ifquery_check {
49
50 my $cmd = ['ifquery', '-a', '-c', '-o','json'];
51
52 my $result = '';
53 my $reader = sub { $result .= shift };
54
55 eval {
56 run_command($cmd, outfunc => $reader);
57 };
58
59 my $resultjson = decode_json($result);
60 my $interfaces = {};
61
62 foreach my $interface (@$resultjson) {
63 my $name = $interface->{name};
64 $interfaces->{$name} = {
65 status => $interface->{status},
66 config => $interface->{config},
67 config_status => $interface->{config_status},
68 };
69 }
70
71 return $interfaces;
72 }
73
74 sub status {
75
76 my ($zone_status, $vnet_status) = PVE::Network::SDN::Zones::status();
77 return($zone_status, $vnet_status);
78 }
79
80 sub config {
81 return cfs_read_file($running_cfg);
82 }
83
84 sub pending_config {
85 my ($running_cfg, $cfg, $type) = @_;
86
87 my $pending = {};
88
89 my $running_objects = $running_cfg->{$type}->{ids};
90 my $config_objects = $cfg->{ids};
91
92 foreach my $id (sort keys %{$running_objects}) {
93 my $running_object = $running_objects->{$id};
94 my $config_object = $config_objects->{$id};
95 foreach my $key (sort keys %{$running_object}) {
96 $pending->{$id}->{$key} = $running_object->{$key};
97 if(!keys %{$config_object}) {
98 $pending->{$id}->{state} = "deleted";
99 } elsif (!defined($config_object->{$key})) {
100 $pending->{$id}->{"pending"}->{$key} = 'deleted';
101 $pending->{$id}->{state} = "changed";
102 } elsif (PVE::Network::SDN::encode_value(undef, $key, $running_object->{$key})
103 ne PVE::Network::SDN::encode_value(undef, $key, $config_object->{$key})) {
104 $pending->{$id}->{state} = "changed";
105 }
106 }
107 }
108
109 foreach my $id (sort keys %{$config_objects}) {
110 my $running_object = $running_objects->{$id};
111 my $config_object = $config_objects->{$id};
112
113 foreach my $key (sort keys %{$config_object}) {
114 my $config_value = PVE::Network::SDN::encode_value(undef, $key, $config_object->{$key}) if $config_object->{$key};
115 my $running_value = PVE::Network::SDN::encode_value(undef, $key, $running_object->{$key}) if $running_object->{$key};
116 if($key eq 'type' || $key eq 'vnet') {
117 $pending->{$id}->{$key} = $config_value;
118 } else {
119 $pending->{$id}->{"pending"}->{$key} = $config_value if !defined($running_value) || ($config_value ne $running_value);
120 }
121 if(!keys %{$running_object}) {
122 $pending->{$id}->{state} = "new";
123 } elsif (!defined($running_value) && defined($config_value)) {
124 $pending->{$id}->{state} = "changed";
125 }
126 }
127 }
128
129 return {ids => $pending};
130
131 }
132
133 sub commit_config {
134
135 my $cfg = cfs_read_file($running_cfg);
136 my $version = $cfg->{version};
137
138 if ($version) {
139 $version++;
140 } else {
141 $version = 1;
142 }
143
144 my $vnets_cfg = PVE::Network::SDN::Vnets::config();
145 my $zones_cfg = PVE::Network::SDN::Zones::config();
146 my $controllers_cfg = PVE::Network::SDN::Controllers::config();
147 my $subnets_cfg = PVE::Network::SDN::Subnets::config();
148
149 my $vnets = { ids => $vnets_cfg->{ids} };
150 my $zones = { ids => $zones_cfg->{ids} };
151 my $controllers = { ids => $controllers_cfg->{ids} };
152 my $subnets = { ids => $subnets_cfg->{ids} };
153
154 $cfg = { version => $version, vnets => $vnets, zones => $zones, controllers => $controllers, subnets => $subnets };
155
156 cfs_write_file($running_cfg, $cfg);
157 }
158
159 sub lock_sdn_config {
160 my ($code, $errmsg) = @_;
161
162 cfs_lock_file($running_cfg, undef, $code);
163
164 if (my $err = $@) {
165 $errmsg ? die "$errmsg: $err" : die $err;
166 }
167 }
168
169 sub get_local_vnets {
170
171 my $rpcenv = PVE::RPCEnvironment::get();
172
173 my $authuser = $rpcenv->get_user();
174
175 my $nodename = PVE::INotify::nodename();
176
177 my $cfg = PVE::Network::SDN::config();
178 my $vnets_cfg = $cfg->{vnets};
179 my $zones_cfg = $cfg->{zones};
180
181 my @vnetids = PVE::Network::SDN::Vnets::sdn_vnets_ids($vnets_cfg);
182
183 my $vnets = {};
184
185 foreach my $vnetid (@vnetids) {
186
187 my $vnet = PVE::Network::SDN::Vnets::sdn_vnets_config($vnets_cfg, $vnetid);
188 my $zoneid = $vnet->{zone};
189 my $comments = $vnet->{alias};
190
191 my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
192
193 next if !$zoneid;
194 next if !$rpcenv->check_any($authuser, "/sdn/zones/$zoneid", $privs, 1);
195
196 my $zone_config = PVE::Network::SDN::Zones::sdn_zones_config($zones_cfg, $zoneid);
197
198 next if defined($zone_config->{nodes}) && !$zone_config->{nodes}->{$nodename};
199 $vnets->{$vnetid} = { type => 'vnet', active => '1', comments => $comments };
200 }
201
202 return $vnets;
203 }
204
205 sub generate_zone_config {
206 my $raw_config = PVE::Network::SDN::Zones::generate_etc_network_config();
207 PVE::Network::SDN::Zones::write_etc_network_config($raw_config);
208 }
209
210 sub generate_controller_config {
211 my ($reload) = @_;
212
213 my $raw_config = PVE::Network::SDN::Controllers::generate_controller_config();
214 PVE::Network::SDN::Controllers::write_controller_config($raw_config);
215
216 PVE::Network::SDN::Controllers::reload_controller() if $reload;
217 }
218
219 sub encode_value {
220 my ($type, $key, $value) = @_;
221
222 if ($key eq 'nodes' || $key eq 'exitnodes') {
223 if(ref($value) eq 'HASH') {
224 return join(',', sort keys(%$value));
225 } else {
226 return $value;
227 }
228 }
229
230 return $value;
231 }
232
233 1;
234