]> git.proxmox.com Git - pmg-api.git/blame - PMG/ClusterConfig.pm
do not use 'last' inside do/while
[pmg-api.git] / PMG / ClusterConfig.pm
CommitLineData
9f67f5b3
DM
1package PMG::ClusterConfig::Base;
2
3use strict;
4use warnings;
5use Data::Dumper;
6
7use PVE::Tools;
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::SectionConfig;
10
11use base qw(PVE::SectionConfig);
12
13my $defaultData = {
14 propertyList => {
15 type => { description => "Cluster node type." },
16 cid => {
17 description => "Cluster Node ID.",
18 type => 'integer',
19 minimum => 1,
20 },
21 },
22};
23
24sub private {
25 return $defaultData;
26}
27
28sub parse_section_header {
29 my ($class, $line) = @_;
30
31 if ($line =~ m/^(node|master):\s*(\d+)\s*$/) {
32 my ($type, $sectionId) = ($1, $2);
33 my $errmsg = undef; # set if you want to skip whole section
34 my $config = {}; # to return additional attributes
35 return ($type, $sectionId, $errmsg, $config);
36 }
37 return undef;
38}
39
9f67f5b3
DM
40package PMG::ClusterConfig::Node;
41
42use strict;
43use warnings;
44
45use base qw(PMG::ClusterConfig::Base);
46
47sub type {
48 return 'node';
49}
50sub properties {
51 return {
52 ip => {
53 description => "IP address.",
b9b02806 54 type => 'string', format => 'ip',
9f67f5b3
DM
55 },
56 name => {
57 description => "Node name.",
58 type => 'string', format =>'pve-node',
59 },
60 hostrsapubkey => {
61 description => "Public SSH RSA key for the host.",
62 type => 'string',
cba17aeb 63 pattern => '^[A-Za-z0-9\.\/\+]{200,}$',
9f67f5b3
DM
64 },
65 rootrsapubkey => {
66 description => "Public SSH RSA key for the root user.",
67 type => 'string',
cba17aeb
DM
68 pattern => '^[A-Za-z0-9\.\/\+]{200,}$',
69 },
70 fingerprint => {
71 description => "SSL certificate fingerprint.",
72 type => 'string',
73 pattern => '^(:?[A-Z0-9][A-Z0-9]:){31}[A-Z0-9][A-Z0-9]$',
9f67f5b3
DM
74 },
75 };
76}
77
78sub options {
79 return {
80 ip => { fixed => 1 },
81 name => { fixed => 1 },
82 hostrsapubkey => {},
83 rootrsapubkey => {},
cba17aeb 84 fingerprint => {},
9f67f5b3
DM
85 };
86}
87
88package PMG::ClusterConfig::Master;
89
90use strict;
91use warnings;
92
93use base qw(PMG::ClusterConfig::Base);
94
95sub type {
96 return 'master';
97}
98
99sub properties {
100 return {
101 maxcid => {
102 description => "Maximum used cluster node ID (used internally, do not modify).",
103 type => 'integer',
104 minimum => 1,
105 },
106 };
107}
108
109sub options {
110 return {
111 maxcid => { fixed => 1 },
112 ip => { fixed => 1 },
113 name => { fixed => 1 },
114 hostrsapubkey => {},
115 rootrsapubkey => {},
cba17aeb 116 fingerprint => {},
9f67f5b3
DM
117 };
118}
119
120package PMG::ClusterConfig;
121
122use strict;
123use warnings;
124use Data::Dumper;
125
126use PVE::SafeSyslog;
127use PVE::Tools;
128use PVE::INotify;
129
130use PMG::Utils;
131
132PMG::ClusterConfig::Node->register;
133PMG::ClusterConfig::Master->register;
134PMG::ClusterConfig::Base->init();
135
136
137sub new {
138 my ($type) = @_;
139
140 my $class = ref($type) || $type;
141
142 my $cfg = PVE::INotify::read_file("cluster.conf");
143
144 return bless $cfg, $class;
145}
146
147sub write {
148 my ($self) = @_;
149
150 PVE::INotify::write_file("cluster.conf", $self);
151}
152
153my $lockfile = "/var/lock/pmgcluster.lck";
154
155sub lock_config {
156 my ($code, $errmsg) = @_;
157
275d6d6d 158 my $res = PVE::Tools::lock_file($lockfile, undef, $code);
9f67f5b3
DM
159 if (my $err = $@) {
160 $errmsg ? die "$errmsg: $err" : die $err;
161 }
275d6d6d 162 return $res;
9f67f5b3
DM
163}
164
165sub read_cluster_conf {
166 my ($filename, $fh) = @_;
167
168 local $/ = undef; # slurp mode
169
170 my $raw = defined($fh) ? <$fh> : undef;
171
172 my $cinfo = PMG::ClusterConfig::Base->parse_config($filename, $raw);
9f67f5b3
DM
173
174 my $localname = PVE::INotify::nodename();
175 my $localip = PMG::Utils::lookup_node_ip($localname);
176
177 $cinfo->{remnodes} = [];
9f67f5b3
DM
178
179 $cinfo->{local} = {
180 cid => 0,
181 ip => $localip,
182 name => $localname,
183 };
184
185 my $maxcid = 0;
186 my $names_hash = {};
187
188 my $errprefix = "unable to parse $filename";
189
190 foreach my $cid (keys %{$cinfo->{ids}}) {
191 my $d = $cinfo->{ids}->{$cid};
192
193 die "$errprefix: duplicate use of name '$d->{name}'\n" if $names_hash->{$d->{name}};
194 $names_hash->{$d->{name}} = 1;
195
196 $d->{cid} = $cid;
197 $maxcid = $cid > $maxcid ? $cid : $maxcid;
198 $maxcid = $d->{maxcid} if defined($d->{maxcid}) && $d->{maxcid} > $maxcid;
199 $cinfo->{master} = $d if $d->{type} eq 'master';
200 $cinfo->{'local'} = $d if $d->{name} eq $localname;
201 }
202
203 if ($maxcid) {
204 die "$errprefix: cluster without master node\n"
205 if !defined($cinfo->{master});
206 $cinfo->{master}->{maxcid} = $maxcid;
207 }
208
e09e2f54 209 my $local_cid = $cinfo->{local}->{cid};
9f67f5b3 210 foreach my $cid (sort keys %{$cinfo->{ids}}) {
e09e2f54 211 if ($local_cid != $cid) {
cf07e7c3 212 push @{$cinfo->{remnodes}}, $cid;
9f67f5b3
DM
213 }
214 }
215
216 return $cinfo;
217}
218
219sub write_cluster_conf {
220 my ($filename, $fh, $cfg) = @_;
221
222 my $raw = PMG::ClusterConfig::Base->write_config($filename, $cfg);
223
224 PVE::Tools::safe_print($filename, $fh, $raw);
225}
226
3278b571 227PVE::INotify::register_file('cluster.conf', "/etc/pmg/cluster.conf",
9f67f5b3
DM
228 \&read_cluster_conf,
229 \&write_cluster_conf,
230 undef,
231 always_call_parser => 1);
232
2331;