]> git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/samba.py
import quincy beta 17.1.0
[ceph.git] / ceph / qa / tasks / samba.py
1 """
2 Samba
3 """
4 import contextlib
5 import logging
6 import time
7
8 from teuthology import misc as teuthology
9 from teuthology.orchestra import run
10 from teuthology.orchestra.daemon import DaemonGroup
11
12 log = logging.getLogger(__name__)
13
14
15 def get_sambas(ctx, roles):
16 """
17 Scan for roles that are samba. Yield the id of the the samba role
18 (samba.0, samba.1...) and the associated remote site
19
20 :param ctx: Context
21 :param roles: roles for this test (extracted from yaml files)
22 """
23 for role in roles:
24 assert isinstance(role, str)
25 PREFIX = 'samba.'
26 assert role.startswith(PREFIX)
27 id_ = role[len(PREFIX):]
28 (remote,) = ctx.cluster.only(role).remotes.keys()
29 yield (id_, remote)
30
31
32 @contextlib.contextmanager
33 def task(ctx, config):
34 """
35 Setup samba smbd with ceph vfs module. This task assumes the samba
36 package has already been installed via the install task.
37
38 The config is optional and defaults to starting samba on all nodes.
39 If a config is given, it is expected to be a list of
40 samba nodes to start smbd servers on.
41
42 Example that starts smbd on all samba nodes::
43
44 tasks:
45 - install:
46 - install:
47 project: samba
48 extra_packages: ['samba']
49 - ceph:
50 - samba:
51 - interactive:
52
53 Example that starts smbd on just one of the samba nodes and cifs on the other::
54
55 tasks:
56 - samba: [samba.0]
57 - cifs: [samba.1]
58
59 An optional backend can be specified, and requires a path which smbd will
60 use as the backend storage location:
61
62 roles:
63 - [osd.0, osd.1, osd.2, mon.0, mon.1, mon.2, mds.a]
64 - [client.0, samba.0]
65
66 tasks:
67 - ceph:
68 - ceph-fuse: [client.0]
69 - samba:
70 samba.0:
71 cephfuse: "{testdir}/mnt.0"
72
73 This mounts ceph to {testdir}/mnt.0 using fuse, and starts smbd with
74 a UNC of //localhost/cephfuse. Access through that UNC will be on
75 the ceph fuse mount point.
76
77 If no arguments are specified in the samba
78 role, the default behavior is to enable the ceph UNC //localhost/ceph
79 and use the ceph vfs module as the smbd backend.
80
81 :param ctx: Context
82 :param config: Configuration
83 """
84 log.info("Setting up smbd with ceph vfs...")
85 assert config is None or isinstance(config, list) or isinstance(config, dict), \
86 "task samba got invalid config"
87
88 if config is None:
89 config = dict(('samba.{id}'.format(id=id_), None)
90 for id_ in teuthology.all_roles_of_type(ctx.cluster, 'samba'))
91 elif isinstance(config, list):
92 config = dict((name, None) for name in config)
93
94 samba_servers = list(get_sambas(ctx=ctx, roles=config.keys()))
95
96 testdir = teuthology.get_testdir(ctx)
97
98 if not hasattr(ctx, 'daemons'):
99 ctx.daemons = DaemonGroup()
100
101 for id_, remote in samba_servers:
102
103 rolestr = "samba.{id_}".format(id_=id_)
104
105 confextras = """vfs objects = ceph
106 ceph:config_file = /etc/ceph/ceph.conf"""
107
108 unc = "ceph"
109 backend = "/"
110
111 if config[rolestr] is not None:
112 # verify that there's just one parameter in role
113 if len(config[rolestr]) != 1:
114 log.error("samba config for role samba.{id_} must have only one parameter".format(id_=id_))
115 raise Exception('invalid config')
116 confextras = ""
117 (unc, backendstr) = config[rolestr].items()[0]
118 backend = backendstr.format(testdir=testdir)
119
120 # on first samba role, set ownership and permissions of ceph root
121 # so that samba tests succeed
122 if config[rolestr] is None and id_ == samba_servers[0][0]:
123 remote.run(
124 args=[
125 'mkdir', '-p', '/tmp/cmnt', run.Raw('&&'),
126 'sudo', 'ceph-fuse', '/tmp/cmnt', run.Raw('&&'),
127 'sudo', 'chown', 'ubuntu:ubuntu', '/tmp/cmnt/', run.Raw('&&'),
128 'sudo', 'chmod', '1777', '/tmp/cmnt/', run.Raw('&&'),
129 'sudo', 'umount', '/tmp/cmnt/', run.Raw('&&'),
130 'rm', '-rf', '/tmp/cmnt',
131 ],
132 )
133 else:
134 remote.run(
135 args=[
136 'sudo', 'chown', 'ubuntu:ubuntu', backend, run.Raw('&&'),
137 'sudo', 'chmod', '1777', backend,
138 ],
139 )
140
141 remote.sudo_write_file("/usr/local/samba/etc/smb.conf", """
142 [global]
143 workgroup = WORKGROUP
144 netbios name = DOMAIN
145
146 [{unc}]
147 path = {backend}
148 {extras}
149 writeable = yes
150 valid users = ubuntu
151 """.format(extras=confextras, unc=unc, backend=backend))
152
153 # create ubuntu user
154 remote.run(
155 args=[
156 'sudo', '/usr/local/samba/bin/smbpasswd', '-e', 'ubuntu',
157 run.Raw('||'),
158 'printf', run.Raw('"ubuntu\nubuntu\n"'),
159 run.Raw('|'),
160 'sudo', '/usr/local/samba/bin/smbpasswd', '-s', '-a', 'ubuntu'
161 ])
162
163 smbd_cmd = [
164 'sudo',
165 'daemon-helper',
166 'term',
167 'nostdin',
168 '/usr/local/samba/sbin/smbd',
169 '-F',
170 ]
171 ctx.daemons.add_daemon(remote, 'smbd', id_,
172 args=smbd_cmd,
173 logger=log.getChild("smbd.{id_}".format(id_=id_)),
174 stdin=run.PIPE,
175 wait=False,
176 )
177
178 # let smbd initialize, probably a better way...
179 seconds_to_sleep = 100
180 log.info('Sleeping for %s seconds...' % seconds_to_sleep)
181 time.sleep(seconds_to_sleep)
182 log.info('Sleeping stopped...')
183
184 try:
185 yield
186 finally:
187 log.info('Stopping smbd processes...')
188 exc = None
189 for d in ctx.daemons.iter_daemons_of_role('smbd'):
190 try:
191 d.stop()
192 except (run.CommandFailedError,
193 run.CommandCrashedError,
194 run.ConnectionLostError) as e:
195 exc = e
196 log.exception('Saw exception from %s.%s', d.role, d.id_)
197 if exc is not None:
198 raise exc
199
200 for id_, remote in samba_servers:
201 remote.run(
202 args=[
203 'sudo',
204 'rm', '-rf',
205 '/usr/local/samba/etc/smb.conf',
206 '/usr/local/samba/private/*',
207 '/usr/local/samba/var/run/',
208 '/usr/local/samba/var/locks',
209 '/usr/local/samba/var/lock',
210 ],
211 )
212 # make sure daemons are gone
213 try:
214 remote.run(
215 args=[
216 'while',
217 'sudo', 'killall', '-9', 'smbd',
218 run.Raw(';'),
219 'do', 'sleep', '1',
220 run.Raw(';'),
221 'done',
222 ],
223 )
224
225 remote.run(
226 args=[
227 'sudo',
228 'lsof',
229 backend,
230 ],
231 check_status=False
232 )
233 remote.run(
234 args=[
235 'sudo',
236 'fuser',
237 '-M',
238 backend,
239 ],
240 check_status=False
241 )
242 except Exception:
243 log.exception("Saw exception")
244 pass