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