]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/calamari_setup.py
11 from cStringIO
import StringIO
12 from teuthology
.orchestra
import run
13 from teuthology
import contextutil
14 from teuthology
import misc
16 log
= logging
.getLogger(__name__
)
22 'start_browser': False,
25 'calamari_user': 'admin',
26 'calamari_password': 'admin',
30 @contextlib.contextmanager
31 def task(ctx
, config
):
33 Do the setup of a calamari server.
37 test_image: <path to tarball or iso>
39 Options are (see DEFAULTS above):
41 version -- ceph version we are testing against
42 test_image -- Can be an HTTP URL, in which case fetch from this
43 http path; can also be local path
44 start_browser -- If True, start a browser. To be used by runs that will
45 bring up a browser quickly for human use. Set to False
46 for overnight suites that are testing for problems in
47 the installation itself
48 email -- email address for the user
49 no_epel -- indicates if we should remove epel files prior to yum
51 calamari_user -- user name to log into gui
52 calamari_password -- calamari user password
54 local_config
= DEFAULTS
55 local_config
.update(config
)
58 for remote_
, roles
in ctx
.cluster
.remotes
.items():
59 if 'client.0' in roles
:
63 raise RuntimeError('client.0 not found in roles')
64 with contextutil
.nested(
65 lambda: adjust_yum_repos(ctx
, cal_svr
, config
['no_epel']),
66 lambda: calamari_install(config
, cal_svr
),
67 lambda: ceph_install(ctx
, cal_svr
),
68 # do it again because ceph-deploy installed epel for centos
69 lambda: remove_epel(ctx
, config
['no_epel']),
70 lambda: calamari_connect(ctx
, cal_svr
),
71 lambda: browser(config
['start_browser'], cal_svr
.hostname
),
76 @contextlib.contextmanager
77 def adjust_yum_repos(ctx
, cal_svr
, no_epel
):
79 For each remote machine, fix the repos if yum is used.
81 ice_distro
= str(cal_svr
.os
)
82 if ice_distro
.startswith('rhel') or ice_distro
.startswith('centos'):
84 for remote
in ctx
.cluster
.remotes
:
85 fix_yum_repos(remote
, ice_distro
)
89 if ice_distro
.startswith('rhel') or ice_distro
.startswith('centos'):
91 for remote
in ctx
.cluster
.remotes
:
92 restore_yum_repos(remote
)
95 def restore_yum_repos(remote
):
97 Copy the old saved repo back in.
99 if remote
.run(args
=['sudo', 'rm', '-rf', '/etc/yum.repos.d']).exitstatus
:
101 if remote
.run(args
=['sudo', 'mv', '/etc/yum.repos.d.old',
102 '/etc/yum.repos.d']).exitstatus
:
106 def fix_yum_repos(remote
, distro
):
108 For yum calamari installations, the repos.d directory should only
109 contain a repo file named rhel<version-number>.repo
111 if distro
.startswith('centos'):
112 # hack alert: detour: install lttng for ceph
113 # this works because epel is preinstalled on the vpms
114 # this is not a generic solution
115 # this is here solely to test the one-off 1.3.0 release for centos6
116 remote
.run(args
="sudo yum -y install lttng-tools")
118 'sudo mkdir /etc/yum.repos.d.old'.split(),
119 ['sudo', 'cp', run
.Raw('/etc/yum.repos.d/*'),
120 '/etc/yum.repos.d.old'],
121 ['sudo', 'rm', run
.Raw('/etc/yum.repos.d/epel*')],
124 if remote
.run(args
=cmd
).exitstatus
:
128 'sudo mv /etc/yum.repos.d /etc/yum.repos.d.old'.split(),
129 'sudo mkdir /etc/yum.repos.d'.split(),
132 if remote
.run(args
=cmd
).exitstatus
:
135 # map "distroversion" from Remote.os to a tuple of
136 # (repo title, repo name descriptor, apt-mirror repo path chunk)
138 'rhel 6.4': ('rhel6-server', 'RHEL', 'rhel6repo-server'),
139 'rhel 6.5': ('rhel6-server', 'RHEL', 'rhel6repo-server'),
140 'rhel 7.0': ('rhel7-server', 'RHEL', 'rhel7repo/server'),
142 repotitle
, reponame
, path
= yum_repo_params
[distro
]
143 repopath
= '/etc/yum.repos.d/%s.repo' % repotitle
144 # TO DO: Make this data configurable too
145 repo_contents
= '\n'.join(
147 'name=%s $releasever - $basearch' % reponame
,
148 'baseurl=http://apt-mirror.front.sepia.ceph.com/' + path
,
152 misc
.sudo_write_file(remote
, repopath
, repo_contents
)
154 'sudo yum clean all'.split(),
155 'sudo yum makecache'.split(),
158 if remote
.run(args
=cmd
).exitstatus
:
163 @contextlib.contextmanager
164 def remove_epel(ctx
, no_epel
):
166 just remove epel. No undo; assumed that it's used after
167 adjust_yum_repos, and relies on its state-save/restore.
170 for remote
in ctx
.cluster
.remotes
:
171 if remote
.os
.name
.startswith('centos'):
173 'sudo', 'rm', '-f', run
.Raw('/etc/yum.repos.d/epel*')
181 def get_iceball_with_http(url
, destdir
):
183 Copy iceball with http to destdir. Try both .tar.gz and .iso.
185 # stream=True means we don't download until copyfileobj below,
186 # and don't need a temp file
187 r
= requests
.get(url
, stream
=True)
189 raise RuntimeError("Failed to download %s", str(url
))
190 filename
= os
.path
.join(destdir
, url
.split('/')[-1])
191 with
open(filename
, 'w') as f
:
192 shutil
.copyfileobj(r
.raw
, f
)
193 log
.info('saved %s as %s' % (url
, filename
))
197 @contextlib.contextmanager
198 def calamari_install(config
, cal_svr
):
203 -- Get the iceball, locally or from http
204 -- Copy the iceball to the calamari server, and untar/mount it.
205 -- Run ice-setup on the calamari server.
206 -- Run calamari-ctl initialize.
208 client_id
= str(cal_svr
)
209 at_loc
= client_id
.find('@')
211 client_id
= client_id
[at_loc
+ 1:]
213 test_image
= config
['test_image']
216 raise RuntimeError('Must supply test image')
217 log
.info('calamari test image: %s' % test_image
)
218 delete_iceball
= False
220 if test_image
.startswith('http'):
221 iceball_file
= get_iceball_with_http(test_image
, '/tmp')
222 delete_iceball
= True
224 iceball_file
= test_image
226 remote_iceball_file
= os
.path
.join('/tmp', os
.path
.split(iceball_file
)[1])
227 cal_svr
.put_file(iceball_file
, remote_iceball_file
)
228 if iceball_file
.endswith('.tar.gz'): # XXX specify tar/iso in config?
230 elif iceball_file
.endswith('.iso'):
233 raise RuntimeError('Can''t handle iceball {0}'.format(iceball_file
))
235 if icetype
== 'tarball':
236 ret
= cal_svr
.run(args
=['gunzip', run
.Raw('<'), remote_iceball_file
,
237 run
.Raw('|'), 'tar', 'xvf', run
.Raw('-')])
239 raise RuntimeError('remote iceball untar failed')
240 elif icetype
== 'iso':
241 mountpoint
= '/mnt/' # XXX create?
243 args
=['sudo', 'mount', '-o', 'loop', '-r',
244 remote_iceball_file
, mountpoint
]
247 # install ice_setup package
249 'deb': 'sudo dpkg -i /mnt/ice-setup*deb',
250 'rpm': 'sudo yum -y localinstall /mnt/ice_setup*rpm'
251 }.get(cal_svr
.system_type
, None)
253 raise RuntimeError('{0}: unknown system type'.format(cal_svr
))
254 ret
= cal_svr
.run(args
=args
)
256 raise RuntimeError('ice_setup package install failed')
259 icesetdata
= 'yes\n\n%s\nhttp\n' % client_id
260 ice_in
= StringIO(icesetdata
)
262 if icetype
== 'tarball':
263 args
= 'sudo python ice_setup.py'
265 args
= 'sudo ice_setup -d /mnt'
266 ret
= cal_svr
.run(args
=args
, stdin
=ice_in
, stdout
=ice_out
)
267 log
.debug(ice_out
.getvalue())
269 raise RuntimeError('ice_setup failed')
271 # Run calamari-ctl initialize.
272 icesetdata
= '%s\n%s\n%s\n%s\n' % (
273 config
['calamari_user'],
275 config
['calamari_password'],
276 config
['calamari_password'],
278 ice_in
= StringIO(icesetdata
)
279 ret
= cal_svr
.run(args
=['sudo', 'calamari-ctl', 'initialize'],
280 stdin
=ice_in
, stdout
=ice_out
)
281 log
.debug(ice_out
.getvalue())
283 raise RuntimeError('calamari-ctl initialize failed')
287 log
.info('Cleaning up after Calamari installation')
289 cal_svr
.run(args
=['sudo', 'umount', mountpoint
])
291 os
.unlink(iceball_file
)
294 @contextlib.contextmanager
295 def ceph_install(ctx
, cal_svr
):
297 Install ceph if ceph was not previously installed by teuthology. This
298 code tests the case where calamari is installed on a brand new system.
301 if 'install' not in [x
.keys()[0] for x
in ctx
.config
['tasks']]:
303 ret
= deploy_ceph(ctx
, cal_svr
)
305 raise RuntimeError('ceph installs failed')
310 if not undeploy_ceph(ctx
, cal_svr
):
311 log
.error('Cleanup of Ceph installed by Calamari-setup failed')
314 def deploy_ceph(ctx
, cal_svr
):
316 Perform the ceph-deploy actions needed to bring up a Ceph cluster. This
317 test is needed to check the ceph-deploy that comes with the calamari
325 # collect which remotes are osds and which are mons
326 for remote
in ctx
.cluster
.remotes
:
327 all_machines
.add(remote
.shortname
)
328 roles
= ctx
.cluster
.remotes
[remote
]
330 daemon_type
, number
= role
.split('.')
331 if daemon_type
== 'osd':
332 all_osds
.add(remote
.shortname
)
333 osd_to_name
[number
] = remote
.shortname
334 if daemon_type
== 'mon':
335 all_mons
.add(remote
.shortname
)
337 # figure out whether we're in "1.3+" mode: prior to 1.3, there was
338 # only one Ceph repo, and it was all installed on every Ceph host.
339 # with 1.3, we've split that into MON and OSD repos (in order to
340 # be able to separately track subscriptions per-node). This
341 # requires new switches to ceph-deploy to select which locally-served
342 # repo is connected to which cluster host.
344 # (TODO: A further issue is that the installation/setup may not have
345 # created local repos at all, but that is the subject of a future
348 r
= cal_svr
.run(args
='/usr/bin/test -d /mnt/MON', check_status
=False)
349 use_install_repo
= (r
.returncode
== 0)
352 # ceph-deploy new <all_mons>
353 # ceph-deploy install <all_machines>
354 # ceph-deploy mon create-initial
357 # ceph-deploy new <all_mons>
358 # ceph-deploy install --repo --release=ceph-mon <all_mons>
359 # ceph-deploy install <all_mons>
360 # ceph-deploy install --repo --release=ceph-osd <all_osds>
361 # ceph-deploy install <all_osds>
362 # ceph-deploy mon create-initial
364 # one might think the install <all_mons> and install <all_osds>
365 # commands would need --mon and --osd, but #12147 has not yet
366 # made it into RHCS 1.3.0; since the package split also hasn't
367 # landed, we can avoid using the flag and avoid the bug.
369 cmds
= ['ceph-deploy new ' + ' '.join(all_mons
)]
372 cmds
.append('ceph-deploy repo ceph-mon ' +
374 cmds
.append('ceph-deploy install --no-adjust-repos --mon ' +
376 cmds
.append('ceph-deploy repo ceph-osd ' +
378 cmds
.append('ceph-deploy install --no-adjust-repos --osd ' +
380 # We tell users to use `hostname` in our docs. Do the same here.
381 cmds
.append('ceph-deploy install --no-adjust-repos --cli `hostname`')
383 cmds
.append('ceph-deploy install ' + ' '.join(all_machines
))
385 cmds
.append('ceph-deploy mon create-initial')
388 cal_svr
.run(args
=cmd
).exitstatus
390 disk_labels
= '_dcba'
391 # NEEDS WORK assumes disks start with vd (need to check this somewhere)
392 for cmd_pts
in [['disk', 'zap'], ['osd', 'prepare'], ['osd', 'activate']]:
394 for osdn
in osd_to_name
:
395 osd_mac
= osd_to_name
[osdn
]
396 mach_osd_cnt
[osd_mac
] = mach_osd_cnt
.get(osd_mac
, 0) + 1
397 arg_list
= ['ceph-deploy']
398 arg_list
.extend(cmd_pts
)
399 disk_id
= '%s:vd%s' % (osd_to_name
[osdn
],
400 disk_labels
[mach_osd_cnt
[osd_mac
]])
401 if 'activate' in cmd_pts
:
403 arg_list
.append(disk_id
)
404 cal_svr
.run(args
=arg_list
).exitstatus
407 def undeploy_ceph(ctx
, cal_svr
):
409 Cleanup deployment of ceph.
413 for remote
in ctx
.cluster
.remotes
:
414 roles
= ctx
.cluster
.remotes
[remote
]
416 not any('osd' in role
for role
in roles
) and
417 not any('mon' in role
for role
in roles
)
421 args
=['sudo', 'stop', 'ceph-all', run
.Raw('||'),
422 'sudo', 'service', 'ceph', 'stop']
424 all_machines
.append(remote
.shortname
)
425 all_machines
= set(all_machines
)
426 cmd1
= ['ceph-deploy', 'uninstall']
427 cmd1
.extend(all_machines
)
428 ret
&= cal_svr
.run(args
=cmd1
).exitstatus
429 cmd2
= ['ceph-deploy', 'purge']
430 cmd2
.extend(all_machines
)
431 ret
&= cal_svr
.run(args
=cmd2
).exitstatus
432 for remote
in ctx
.cluster
.remotes
:
433 ret
&= remote
.run(args
=['sudo', 'rm', '-rf',
434 '.ssh/known_hosts']).exitstatus
438 @contextlib.contextmanager
439 def calamari_connect(ctx
, cal_svr
):
441 Connect calamari to the ceph nodes.
443 connects
= ['ceph-deploy', 'calamari', 'connect']
444 for machine_info
in ctx
.cluster
.remotes
:
445 if 'client.0' not in ctx
.cluster
.remotes
[machine_info
]:
446 connects
.append(machine_info
.shortname
)
447 ret
= cal_svr
.run(args
=connects
)
449 raise RuntimeError('calamari connect failed')
453 log
.info('Calamari test terminating')
456 @contextlib.contextmanager
457 def browser(start_browser
, web_page
):
459 Bring up a browser, if wanted.
462 webbrowser
.open('http://%s' % web_page
)
467 log
.info('Web browser support terminating')