]> git.proxmox.com Git - ceph.git/blame - ceph/src/ceph-create-keys
update sources to v12.1.0
[ceph.git] / ceph / src / ceph-create-keys
CommitLineData
7c673cae
FG
1#!/usr/bin/env python
2import argparse
3import errno
4import json
5import logging
6import os
7import subprocess
8import sys
9import time
10import pwd
11import grp
12
13
14LOG = logging.getLogger(os.path.basename(sys.argv[0]))
15
16QUORUM_STATES = ['leader', 'peon']
17
18def get_ceph_uid():
19 try:
20 uid = pwd.getpwnam('ceph').pw_uid
21 except:
22 uid = -1
23 return uid
24
25def get_ceph_gid():
26 try:
27 gid = grp.getgrnam('ceph').gr_gid
28 except:
29 gid = -1
30 return gid
31
32def wait_for_quorum(cluster, mon_id):
33 wait_count = 600 # 10 minutes
34 while wait_count > 0:
35 p = subprocess.Popen(
36 args=[
37 'ceph',
38 '--cluster={cluster}'.format(cluster=cluster),
39 '--admin-daemon=/var/run/ceph/{cluster}-mon.{mon_id}.asok'.format(
40 cluster=cluster,
41 mon_id=mon_id,
42 ),
43 'mon_status',
44 ],
45 stdout=subprocess.PIPE,
46 )
47 out = p.stdout.read()
48 returncode = p.wait()
49 if returncode != 0:
50 LOG.info('ceph-mon admin socket not ready yet.')
51 time.sleep(1)
52 wait_count -= 1
53 continue
54
55 if out == '':
56 LOG.info('ceph-mon admin socket returned no data')
57 time.sleep(1)
58 wait_count -= 1
59 continue
60
61 try:
62 data = json.loads(out)
63 except:
64 LOG.info('failed to parse json %s', out)
65 sys.exit(errno.EINVAL)
66
67 state = data['state']
68 if state not in QUORUM_STATES:
69 LOG.info('ceph-mon is not in quorum: %r', state)
70 time.sleep(1)
71 wait_count -= 1
72 continue
73
74 break
75
76 if wait_count == 0:
77 raise SystemExit("ceph-mon was not able to join quorum within 10 minutes")
78
79
80def get_key(cluster, mon_id):
81 path = '/etc/ceph/{cluster}.client.admin.keyring'.format(
82 cluster=cluster,
83 )
84 if os.path.exists(path):
85 LOG.info('Key exists already: %s', path)
86 return
87 tmp = '{path}.{pid}.tmp'.format(
88 path=path,
89 pid=os.getpid(),
90 )
91 pathdir = os.path.dirname(path)
92 if not os.path.exists(pathdir):
93 os.makedirs(pathdir)
94 os.chmod(pathdir, 0770)
95 os.chown(pathdir, get_ceph_uid(), get_ceph_gid())
96 wait_count = 600 # 10 minutes
97 while wait_count > 0:
98 try:
99 with file(tmp, 'w') as f:
100 os.fchmod(f.fileno(), 0600)
101 os.fchown(f.fileno(), get_ceph_uid(), get_ceph_gid())
102 LOG.info('Talking to monitor...')
103
104 args_prefix = [
105 "ceph",
106 '--connect-timeout=20',
107 '--cluster={cluster}'.format(cluster=cluster),
108 '--name=mon.',
109 '--keyring=/var/lib/ceph/mon/{cluster}-{mon_id}/keyring'.format(
110 cluster=cluster,
111 mon_id=mon_id,
112 ),
113 ]
114
115 # First try getting the key if it already exists, to handle
116 # the case where it exists but doesn't match the caps
117 # we would pass into get-or-create.
118 returncode = subprocess.call(
119 args=args_prefix + [
120 'auth',
121 'get',
122 'client.admin',
123 ],
124 stdout=f,
125 )
126 if returncode == errno.ENOENT:
127 returncode = subprocess.call(
128 args=args_prefix + [
129 'auth',
130 'get-or-create',
131 'client.admin',
132 'mon', 'allow *',
133 'osd', 'allow *',
134 'mds', 'allow *',
135 'mgr', 'allow *',
136 ],
137 stdout=f,
138 )
31f18b77
FG
139 else:
140 returncode = subprocess.call(
141 args=args_prefix + [
142 'auth',
143 'caps',
144 'client.admin',
145 'mon', 'allow *',
146 'osd', 'allow *',
147 'mds', 'allow *',
148 'mgr', 'allow *',
149 ],
150 stdout=f,
151 )
7c673cae
FG
152
153 if returncode != 0:
154 if returncode == errno.EPERM or returncode == errno.EACCES:
155 LOG.info('Cannot get or create admin key, permission denied')
156 sys.exit(returncode)
157 else:
158 LOG.info('Cannot get or create admin key')
159 time.sleep(1)
160 wait_count -= 1
161 continue
162
163 os.rename(tmp, path)
164 break
165 finally:
166 try:
167 os.unlink(tmp)
168 except OSError as e:
169 if e.errno == errno.ENOENT:
170 pass
171 else:
172 raise
173
174 if wait_count == 0:
175 raise SystemExit("Could not get or create the admin key after 10 minutes")
176
177
178def bootstrap_key(cluster, type_):
179 path = '/var/lib/ceph/bootstrap-{type}/{cluster}.keyring'.format(
180 type=type_,
181 cluster=cluster,
182 )
183 if os.path.exists(path):
184 LOG.info('Key exists already: %s', path)
185 return
186 tmp = '{path}.{pid}.tmp'.format(
187 path=path,
188 pid=os.getpid(),
189 )
190
191 args = [
192 'ceph',
193 '--connect-timeout=20',
194 '--cluster={cluster}'.format(cluster=cluster),
195 'auth',
196 'get-or-create',
197 'client.bootstrap-{type}'.format(type=type_),
198 'mon',
199 'allow profile bootstrap-{type}'.format(type=type_),
200 ]
201
202 pathdir = os.path.dirname(path)
203 if not os.path.exists(pathdir):
204 os.makedirs(pathdir)
205 os.chmod(pathdir, 0770)
206 os.chown(pathdir, get_ceph_uid(), get_ceph_gid())
207
208 wait_count = 600 # 10 minutes
209 while wait_count > 0:
210 try:
211 with file(tmp, 'w') as f:
212 os.fchmod(f.fileno(), 0600)
213 os.fchown(f.fileno(), get_ceph_uid(), get_ceph_gid())
214 LOG.info('Talking to monitor...')
215 returncode = subprocess.call(
216 args=args,
217 stdout=f,
218 )
219 if returncode != 0:
220 if returncode == errno.EPERM or returncode == errno.EACCES:
221 LOG.info('Cannot get or create bootstrap key for %s, permission denied', type_)
222 break
223 else:
224 LOG.info('Cannot get or create bootstrap key for %s', type_)
225 time.sleep(1)
226 wait_count -= 1
227 continue
228
229 os.rename(tmp, path)
230 break
231 finally:
232 try:
233 os.unlink(tmp)
234 except OSError as e:
235 if e.errno == errno.ENOENT:
236 pass
237 else:
238 raise
239 if wait_count == 0:
240 raise SystemExit("Could not get or create %s bootstrap key after 10 minutes" % type_)
241
242
243def parse_args():
244 parser = argparse.ArgumentParser(
245 description='Create Ceph client.admin key when ceph-mon is ready',
246 )
247 parser.add_argument(
248 '-v', '--verbose',
249 action='store_true', default=None,
250 help='be more verbose',
251 )
252 parser.add_argument(
253 '--cluster',
254 metavar='NAME',
255 help='name of the cluster',
256 )
257 parser.add_argument(
258 '--id', '-i',
259 metavar='ID',
260 help='id of a ceph-mon that is coming up',
261 required=True,
262 )
263 parser.set_defaults(
264 cluster='ceph',
265 )
266 parser.set_defaults(
267 # we want to hold on to this, for later
268 prog=parser.prog,
269 )
270 args = parser.parse_args()
271 return args
272
273
274def main():
275 args = parse_args()
276
277 loglevel = logging.INFO
278 if args.verbose:
279 loglevel = logging.DEBUG
280
281 logging.basicConfig(
282 level=loglevel,
283 )
284
285 wait_for_quorum(cluster=args.cluster, mon_id=args.id)
286 get_key(cluster=args.cluster, mon_id=args.id)
287
288 bootstrap_key(
289 cluster=args.cluster,
290 type_='osd',
291 )
292 bootstrap_key(
293 cluster=args.cluster,
294 type_='rgw',
295 )
296 bootstrap_key(
297 cluster=args.cluster,
298 type_='mds',
299 )
300
301
302if __name__ == '__main__':
303 main()