]> git.proxmox.com Git - pmg-api.git/blob - PMG/ClusterConfig.pm
ClusterConfig: remnodes is a list of IDs.
[pmg-api.git] / PMG / ClusterConfig.pm
1 package PMG::ClusterConfig::Base;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6
7 use PVE::Tools;
8 use PVE::JSONSchema qw(get_standard_option);
9 use PVE::SectionConfig;
10
11 use base qw(PVE::SectionConfig);
12
13 my $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
24 sub private {
25 return $defaultData;
26 }
27
28 sub 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
40
41 package PMG::ClusterConfig::Node;
42
43 use strict;
44 use warnings;
45
46 use base qw(PMG::ClusterConfig::Base);
47
48 sub type {
49 return 'node';
50 }
51 sub properties {
52 return {
53 ip => {
54 description => "IP address.",
55 type => 'string', format => 'address',
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',
64 },
65 rootrsapubkey => {
66 description => "Public SSH RSA key for the root user.",
67 type => 'string',
68 },
69 };
70 }
71
72 sub options {
73 return {
74 ip => { fixed => 1 },
75 name => { fixed => 1 },
76 hostrsapubkey => {},
77 rootrsapubkey => {},
78 };
79 }
80
81 package PMG::ClusterConfig::Master;
82
83 use strict;
84 use warnings;
85
86 use base qw(PMG::ClusterConfig::Base);
87
88 sub type {
89 return 'master';
90 }
91
92 sub properties {
93 return {
94 maxcid => {
95 description => "Maximum used cluster node ID (used internally, do not modify).",
96 type => 'integer',
97 minimum => 1,
98 },
99 };
100 }
101
102 sub options {
103 return {
104 maxcid => { fixed => 1 },
105 ip => { fixed => 1 },
106 name => { fixed => 1 },
107 hostrsapubkey => {},
108 rootrsapubkey => {},
109 };
110 }
111
112 package PMG::ClusterConfig;
113
114 use strict;
115 use warnings;
116 use Data::Dumper;
117
118 use PVE::SafeSyslog;
119 use PVE::Tools;
120 use PVE::INotify;
121
122 use PMG::Utils;
123
124 PMG::ClusterConfig::Node->register;
125 PMG::ClusterConfig::Master->register;
126 PMG::ClusterConfig::Base->init();
127
128
129 sub new {
130 my ($type) = @_;
131
132 my $class = ref($type) || $type;
133
134 my $cfg = PVE::INotify::read_file("cluster.conf");
135
136 return bless $cfg, $class;
137 }
138
139 sub write {
140 my ($self) = @_;
141
142 PVE::INotify::write_file("cluster.conf", $self);
143 }
144
145 my $lockfile = "/var/lock/pmgcluster.lck";
146
147 sub lock_config {
148 my ($code, $errmsg) = @_;
149
150 my $p = PVE::Tools::lock_file($lockfile, undef, $code);
151 if (my $err = $@) {
152 $errmsg ? die "$errmsg: $err" : die $err;
153 }
154 }
155
156 sub read_cluster_conf {
157 my ($filename, $fh) = @_;
158
159 local $/ = undef; # slurp mode
160
161 my $raw = defined($fh) ? <$fh> : undef;
162
163 my $cinfo = PMG::ClusterConfig::Base->parse_config($filename, $raw);
164 print Dumper($cinfo);
165
166 my $localname = PVE::INotify::nodename();
167 my $localip = PMG::Utils::lookup_node_ip($localname);
168
169 $cinfo->{remnodes} = [];
170 $cinfo->{configport}->{0} = 83;
171 $cinfo->{dbport}->{0} = 5432;
172
173 $cinfo->{local} = {
174 cid => 0,
175 ip => $localip,
176 name => $localname,
177 };
178
179 my $maxcid = 0;
180 my $names_hash = {};
181
182 my $errprefix = "unable to parse $filename";
183
184 foreach my $cid (keys %{$cinfo->{ids}}) {
185 my $d = $cinfo->{ids}->{$cid};
186
187 die "$errprefix: duplicate use of name '$d->{name}'\n" if $names_hash->{$d->{name}};
188 $names_hash->{$d->{name}} = 1;
189
190 $d->{cid} = $cid;
191 $maxcid = $cid > $maxcid ? $cid : $maxcid;
192 $maxcid = $d->{maxcid} if defined($d->{maxcid}) && $d->{maxcid} > $maxcid;
193 $cinfo->{master} = $d if $d->{type} eq 'master';
194 $cinfo->{'local'} = $d if $d->{name} eq $localname;
195 }
196
197 if ($maxcid) {
198 die "$errprefix: cluster without master node\n"
199 if !defined($cinfo->{master});
200 $cinfo->{master}->{maxcid} = $maxcid;
201 }
202
203 my $ind = 0;
204 foreach my $cid (sort keys %{$cinfo->{ids}}) {
205 if ($cinfo->{'local'}->{cid} == $cid) { # local CID
206 $cinfo->{configport}->{$cid} = 83;
207 $cinfo->{dbport}->{$cid} = 5432;
208 } else {
209 my $portid = $ind++;
210 $cinfo->{configport}->{$cid} = 50000 + $portid;
211 $cinfo->{dbport}->{$cid} = 50100 + $portid;
212 push @{$cinfo->{remnodes}}, $cid;
213 }
214 }
215
216 return $cinfo;
217 }
218
219 sub 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
227 PVE::INotify::register_file('cluster.conf', "/etc/proxmox/cluster.conf",
228 \&read_cluster_conf,
229 \&write_cluster_conf,
230 undef,
231 always_call_parser => 1);
232
233 1;