]> git.proxmox.com Git - pmg-api.git/blame - PMG/API2/Cluster.pm
implement cluster join - first version
[pmg-api.git] / PMG / API2 / Cluster.pm
CommitLineData
fb5f2d1e 1package PMG::API2::Cluster;
5ac6bd0e
DM
2
3use strict;
4use warnings;
5use Data::Dumper;
6
7use PVE::SafeSyslog;
8use PVE::Tools qw(extract_param);
9use HTTP::Status qw(:constants);
10use Storable qw(dclone);
11use PVE::JSONSchema qw(get_standard_option);
12use PVE::RESTHandler;
13use PVE::INotify;
e16a9efc 14use PVE::APIClient::LWP;
5ac6bd0e
DM
15
16use PMG::ClusterConfig;
e16a9efc 17use PMG::Cluster;
5ac6bd0e
DM
18
19use base qw(PVE::RESTHandler);
20
e16a9efc
DM
21sub cluster_join {
22 my ($conn_setup) = @_;
23
24 my $conn = PVE::APIClient::LWP->new(%$conn_setup);
25
26 my $info = PMG::Cluster::read_local_cluster_info();
27
28 my $res = $conn->post("/config/cluster/nodes", $info);
29}
30
5ac6bd0e
DM
31__PACKAGE__->register_method({
32 name => 'index',
33 path => '',
34 method => 'GET',
fb5f2d1e
DM
35 description => "Directory index.",
36 permissions => { user => 'all' },
37 parameters => {
38 additionalProperties => 0,
39 properties => {},
40 },
41 returns => {
42 type => 'array',
43 items => {
44 type => "object",
45 properties => {},
46 },
47 links => [ { rel => 'child', href => "{name}" } ],
48 },
49 code => sub {
50 my ($param) = @_;
51
52 my $result = [
53 { name => 'nodes' },
54 { name => 'create' },
55 { name => 'join' },
56 ];
57
58 return $result;
59 }});
60
61__PACKAGE__->register_method({
62 name => 'nodes',
63 path => 'nodes',
64 method => 'GET',
5ac6bd0e
DM
65 description => "Cluster node index.",
66 # alway read local file
67 parameters => {
68 additionalProperties => 0,
69 properties => {},
70 },
cba17aeb 71 permissions => { check => [ 'admin' ] },
5ac6bd0e
DM
72 returns => {
73 type => 'array',
74 items => {
75 type => "object",
76 properties => {
77 cid => { type => 'integer' },
78 },
79 },
80 links => [ { rel => 'child', href => "{cid}" } ],
81 },
82 code => sub {
83 my ($param) = @_;
84
85 my $cfg = PVE::INotify::read_file('cluster.conf');
86
3862c23d
DM
87 if (scalar(keys %{$cfg->{ids}})) {
88 my $role = $cfg->{local}->{type} // '-';
89 if ($role eq '-') {
90 die "local node '$cfg->{local}->{name}' not part of cluster\n";
91 }
92 }
93
5ac6bd0e
DM
94 return PVE::RESTHandler::hash_to_array($cfg->{ids}, 'cid');
95 }});
96
e16a9efc
DM
97my $add_node_schema = PMG::ClusterConfig::Node->createSchema(1);
98delete $add_node_schema->{properties}->{cid};
99
100__PACKAGE__->register_method({
101 name => 'add_node',
102 path => 'nodes',
103 method => 'POST',
104 description => "Add an node to the cluster config.",
105 proxyto => 'master',
106 protected => 1,
107 parameters => $add_node_schema,
108 returns => { type => 'null' },
109 code => sub {
110 my ($param) = @_;
111
112 my $code = sub {
113 my $cfg = PMG::ClusterConfig->new();
114
115 die "no cluster defined\n" if !scalar(keys %{$cfg->{ids}});
116
117 my $master = $cfg->{master} || die "unable to lookup master node\n";
118
119 $master->{maxcid}++;
120
121 my $node = {
122 type => 'node',
123 cid => $master->{maxcid},
124 };
125
126 foreach my $k (qw(ip name hostrsapubkey rootrsapubkey fingerprint)) {
127 $node->{$k} = $param->{$k};
128 }
129
130 # fixme: test if IP or name already exists
131
132 $cfg->{ids}->{$node->{cid}} = $node;
133
134 $cfg->write();
135 };
136
137 PMG::ClusterConfig::lock_config($code, "create cluster failed");
138
139 return undef;
140 }});
141
cba17aeb 142__PACKAGE__->register_method({
fb5f2d1e
DM
143 name => 'create',
144 path => 'create',
cba17aeb
DM
145 method => 'POST',
146 description => "Create initial cluster config with current node as master.",
147 # alway read local file
148 parameters => {
149 additionalProperties => 0,
150 properties => {},
151 },
152 returns => { type => 'null' },
153 code => sub {
154 my ($param) = @_;
155
156 my $code = sub {
157 my $cfg = PMG::ClusterConfig->new();
158
159 die "cluster alreayd defined\n" if scalar(keys %{$cfg->{ids}});
160
161 my $info = PMG::Cluster::read_local_cluster_info();
162
163 $info->{type} = 'master';
164 $info->{maxcid} = 1,
165
166 $cfg->{ids}->{$info->{maxcid}} = $info;
167
168 $cfg->write();
169 };
170
171 PMG::ClusterConfig::lock_config($code, "create cluster failed");
172
173 return undef;
174 }});
175
fb5f2d1e
DM
176__PACKAGE__->register_method({
177 name => 'join',
178 path => 'join',
179 method => 'POST',
180 description => "Join local node to an existing cluster.",
181 # alway read local file
182 parameters => {
183 additionalProperties => 0,
184 properties => {
185 master_ip => {
186 description => "IP address.",
187 type => 'string', format => 'ip',
188 },
189 fingerprint => {
190 description => "SSL certificate fingerprint.",
191 type => 'string',
192 pattern => '^(:?[A-Z0-9][A-Z0-9]:){31}[A-Z0-9][A-Z0-9]$',
193 },
e16a9efc
DM
194 password => {
195 description => "Superuser password.",
196 type => 'string',
197 maxLength => 128,
198 },
fb5f2d1e
DM
199 },
200 },
201 returns => { type => 'null' },
202 code => sub {
203 my ($param) = @_;
204
205 my $code = sub {
206 my $cfg = PMG::ClusterConfig->new();
207
208 die "cluster alreayd defined\n" if scalar(keys %{$cfg->{ids}});
209
e16a9efc
DM
210 my $setup = {
211 username => 'root@pam',
212 password => $param->{password},
213 cookie_name => 'PMGAuthCookie',
214 host => $param->{master_ip},
215 cached_fingerprints => {
216 $param->{fingerprint} => 1,
217 }
218 };
219
220 cluster_join($setup);
fb5f2d1e
DM
221 };
222
223 PMG::ClusterConfig::lock_config($code, "cluster join failed");
224
225 return undef;
226 }});
227
cba17aeb 228
5ac6bd0e 2291;