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