]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Ceph/MDS.pm
1948969026482a6b92cf741281fd4e83abfd84eb
[pve-manager.git] / PVE / API2 / Ceph / MDS.pm
1 package PVE::API2::Ceph::MDS;
2
3 use strict;
4 use warnings;
5
6 use PVE::Ceph::Tools;
7 use PVE::Ceph::Services;
8 use PVE::Cluster qw(cfs_read_file cfs_write_file);
9 use PVE::INotify;
10 use PVE::JSONSchema qw(get_standard_option);
11 use PVE::RADOS;
12 use PVE::RESTHandler;
13 use PVE::RPCEnvironment;
14
15 use base qw(PVE::RESTHandler);
16
17 __PACKAGE__->register_method ({
18 name => 'index',
19 path => '',
20 method => 'GET',
21 description => "MDS directory index.",
22 permissions => {
23 check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
24 },
25 proxyto => 'node',
26 protected => 1,
27 parameters => {
28 additionalProperties => 0,
29 properties => {
30 node => get_standard_option('pve-node'),
31 },
32 },
33 returns => {
34 type => 'array',
35 items => {
36 type => "object",
37 properties => {
38 name => {
39 description => "The name (ID) for the MDS",
40 },
41 addr => {
42 type => 'string',
43 optional => 1,
44 },
45 host => {
46 type => 'string',
47 optional => 1,
48 },
49 state => {
50 type => 'string',
51 description => 'State of the MDS',
52 },
53 standby_replay => {
54 type => 'boolean',
55 optional => 1,
56 description => 'If true, the standby MDS is polling the active MDS for faster recovery (hot standby).',
57 },
58 rank => {
59 type => 'integer',
60 optional => 1,
61 },
62 },
63 },
64 links => [ { rel => 'child', href => "{name}" } ],
65 },
66 code => sub {
67 my ($param) = @_;
68
69 PVE::Ceph::Tools::check_ceph_inited();
70
71 my $res = [];
72
73 my $cfg = cfs_read_file('ceph.conf');
74
75 my $mds_hash = {};
76
77 foreach my $section (keys %$cfg) {
78 my $d = $cfg->{$section};
79
80 if ($section =~ m/^mds\.(\S+)$/) {
81 my $mds_id = $1;
82 if (defined($d->{host})) {
83 $mds_hash->{$mds_id} = {
84 name => $mds_id,
85 state => 'unknown',
86 addr => $d->{host},
87 host => $d->{host},
88 };
89 }
90 }
91 }
92
93 my $mds_state = PVE::Ceph::Services::get_cluster_mds_state();
94 foreach my $name (keys %$mds_state) {
95 my $d = $mds_state->{$name};
96 # just overwrite, this always provides more info
97 $mds_hash->{$name}->{$_} = $d->{$_} for keys %$d;
98 }
99
100 return PVE::RESTHandler::hash_to_array($mds_hash, 'name');
101 }
102 });
103
104 __PACKAGE__->register_method ({
105 name => 'createmds',
106 path => '{name}',
107 method => 'POST',
108 description => "Create Ceph Metadata Server (MDS)",
109 proxyto => 'node',
110 protected => 1,
111 permissions => {
112 check => ['perm', '/', [ 'Sys.Modify' ]],
113 },
114 parameters => {
115 additionalProperties => 0,
116 properties => {
117 node => get_standard_option('pve-node'),
118 name => {
119 type => 'string',
120 optional => 1,
121 default => 'nodename',
122 pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
123 description => "The ID for the mds, when omitted the same as the nodename",
124 },
125 hotstandby => {
126 type => 'boolean',
127 optional => 1,
128 default => '0',
129 description => "Determines whether a ceph-mds daemon should poll and replay the log of an active MDS. ".
130 "Faster switch on MDS failure, but needs more idle resources.",
131 },
132 },
133 },
134 returns => { type => 'string' },
135 code => sub {
136 my ($param) = @_;
137
138 PVE::Ceph::Tools::check_ceph_installed('ceph_mds');
139
140 PVE::Ceph::Tools::check_ceph_inited();
141
142 my $rpcenv = PVE::RPCEnvironment::get();
143 my $authuser = $rpcenv->get_user();
144
145 my $nodename = $param->{node};
146 $nodename = INotify::nodename() if $nodename eq 'localhost';
147
148 my $mds_id = $param->{name} // $nodename;
149
150 my $worker = sub {
151 my $timeout = PVE::Ceph::Tools::get_config('long_rados_timeout');
152 my $rados = PVE::RADOS->new(timeout => $timeout);
153
154 my $cfg = cfs_read_file('ceph.conf');
155
156 my $section = "mds.$mds_id";
157
158 if (defined($cfg->{$section})) {
159 die "MDS '$mds_id' already referenced in ceph config, abort!\n"
160 }
161
162 if (!defined($cfg->{mds}->{keyring})) {
163 # $id isn't a perl variable but a ceph metavariable
164 my $keyring = '/var/lib/ceph/mds/ceph-$id/keyring';
165
166 $cfg->{mds}->{keyring} = $keyring;
167 }
168
169 $cfg->{$section}->{host} = $nodename;
170 $cfg->{$section}->{"mds standby for name"} = 'pve';
171
172 if ($param->{hotstandby}) {
173 $cfg->{$section}->{"mds standby replay"} = 'true';
174 }
175
176 cfs_write_file('ceph.conf', $cfg);
177
178 eval { PVE::Ceph::Services::create_mds($mds_id, $rados) };
179 if (my $err = $@) {
180 # we abort early if the section is defined, so we know that we
181 # wrote it at this point. Do not auto remove the service, could
182 # do real harm for previously manual setup MDS
183 warn "Encountered error, remove '$section' from ceph.conf\n";
184 my $cfg = cfs_read_file('ceph.conf');
185 delete $cfg->{$section};
186 cfs_write_file('ceph.conf', $cfg);
187
188 die "$err\n";
189 }
190 };
191
192 return $rpcenv->fork_worker('cephcreatemds', "mds.$mds_id", $authuser, $worker);
193 }
194 });
195
196 __PACKAGE__->register_method ({
197 name => 'destroymds',
198 path => '{name}',
199 method => 'DELETE',
200 description => "Destroy Ceph Metadata Server",
201 proxyto => 'node',
202 protected => 1,
203 permissions => {
204 check => ['perm', '/', [ 'Sys.Modify' ]],
205 },
206 parameters => {
207 additionalProperties => 0,
208 properties => {
209 node => get_standard_option('pve-node'),
210 name => {
211 description => 'The name (ID) of the mds',
212 type => 'string',
213 pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
214 },
215 },
216 },
217 returns => { type => 'string' },
218 code => sub {
219 my ($param) = @_;
220
221 my $rpcenv = PVE::RPCEnvironment::get();
222
223 my $authuser = $rpcenv->get_user();
224
225 PVE::Ceph::Tools::check_ceph_inited();
226
227 my $mds_id = $param->{name};
228
229 my $worker = sub {
230 my $timeout = PVE::Ceph::Tools::get_config('long_rados_timeout');
231 my $rados = PVE::RADOS->new(timeout => $timeout);
232
233 my $cfg = cfs_read_file('ceph.conf');
234
235 if (defined($cfg->{"mds.$mds_id"})) {
236 delete $cfg->{"mds.$mds_id"};
237 cfs_write_file('ceph.conf', $cfg);
238 }
239
240 PVE::Ceph::Services::destroy_mds($mds_id, $rados);
241 };
242
243 return $rpcenv->fork_worker('cephdestroymds', "mds.$mds_id", $authuser, $worker);
244 }
245 });
246
247 1;