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