]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/dnsmasq.py
import 15.2.4
[ceph.git] / ceph / qa / tasks / dnsmasq.py
CommitLineData
31f18b77
FG
1"""
2Task for dnsmasq configuration
3"""
4import contextlib
5import logging
6
7from teuthology import misc
8from teuthology.exceptions import ConfigError
9from teuthology import contextutil
11fdf7f2 10from teuthology import packaging
e306af50 11from tasks.util import get_remote_for_role
31f18b77
FG
12
13log = logging.getLogger(__name__)
14
15@contextlib.contextmanager
11fdf7f2
TL
16def install_dnsmasq(remote):
17 """
18 If dnsmasq is not installed, install it for the duration of the task.
19 """
20 try:
21 existing = packaging.get_package_version(remote, 'dnsmasq')
22 except:
23 existing = None
24
25 if existing is None:
26 packaging.install_package('dnsmasq', remote)
27 try:
28 yield
29 finally:
30 if existing is None:
31 packaging.remove_package('dnsmasq', remote)
32
33@contextlib.contextmanager
34def backup_resolv(remote, path):
35 """
36 Store a backup of resolv.conf in the testdir and restore it after the task.
37 """
38 remote.run(args=['cp', '/etc/resolv.conf', path])
39 try:
40 yield
41 finally:
42 # restore with 'cp' to avoid overwriting its security context
43 remote.run(args=['sudo', 'cp', path, '/etc/resolv.conf'])
44 remote.run(args=['rm', path])
45
46@contextlib.contextmanager
47def replace_resolv(remote, path):
48 """
49 Update resolv.conf to point the nameserver at localhost.
50 """
51 misc.write_file(remote, path, "nameserver 127.0.0.1\n")
52 try:
53 # install it
54 if remote.os.package_type == "rpm":
55 # for centos ovh resolv.conf has immutable attribute set
56 remote.run(args=['sudo', 'chattr', '-i', '/etc/resolv.conf'], check_status=False)
57 remote.run(args=['sudo', 'cp', path, '/etc/resolv.conf'])
58 yield
59 finally:
60 remote.run(args=['rm', path])
61
62@contextlib.contextmanager
63def setup_dnsmasq(remote, testdir, cnames):
31f18b77
FG
64 """ configure dnsmasq on the given remote, adding each cname given """
65 log.info('Configuring dnsmasq on remote %s..', remote.name)
66
11fdf7f2 67 # add address entries for each cname
31f18b77
FG
68 dnsmasq = "server=8.8.8.8\nserver=8.8.4.4\n"
69 address_template = "address=/{cname}/{ip_address}\n"
9f95a23c 70 for cname, ip_address in cnames.items():
31f18b77 71 dnsmasq += address_template.format(cname=cname, ip_address=ip_address)
31f18b77 72
11fdf7f2
TL
73 # write to temporary dnsmasq file
74 dnsmasq_tmp = '/'.join((testdir, 'ceph.tmp'))
75 misc.write_file(remote, dnsmasq_tmp, dnsmasq)
76
77 # move into /etc/dnsmasq.d/
78 dnsmasq_path = '/etc/dnsmasq.d/ceph'
79 remote.run(args=['sudo', 'mv', dnsmasq_tmp, dnsmasq_path])
80 # restore selinux context if necessary
81 remote.run(args=['sudo', 'restorecon', dnsmasq_path], check_status=False)
82
31f18b77
FG
83 # restart dnsmasq
84 remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq'])
31f18b77 85 # verify dns name is set
e306af50 86 remote.run(args=['ping', '-c', '4', next(iter(cnames.keys()))])
31f18b77 87
11fdf7f2
TL
88 try:
89 yield
90 finally:
91 log.info('Removing dnsmasq configuration from remote %s..', remote.name)
92 # remove /etc/dnsmasq.d/ceph
93 remote.run(args=['sudo', 'rm', dnsmasq_path])
94 # restart dnsmasq
95 remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq'])
31f18b77
FG
96
97@contextlib.contextmanager
98def task(ctx, config):
99 """
100 Configures dnsmasq to add cnames for teuthology remotes. The task expects a
101 dictionary, where each key is a role. If all cnames for that role use the
102 same address as that role, the cnames can be given as a list. For example,
103 this entry configures dnsmasq on the remote associated with client.0, adding
104 two cnames for the ip address associated with client.0:
105
106 - dnsmasq:
107 client.0:
108 - client0.example.com
109 - c0.example.com
110
111 If the addresses do not all match the given role, a dictionary can be given
112 to specify the ip address by its target role. For example:
113
114 - dnsmasq:
115 client.0:
116 client.0.example.com: client.0
117 client.1.example.com: client.1
11fdf7f2
TL
118
119 Cnames that end with a . are treated as prefix for the existing hostname.
120 For example, if the remote for client.0 has a hostname of 'example.com',
121 this task will add cnames for dev.example.com and test.example.com:
122
123 - dnsmasq:
124 client.0: [dev., test.]
31f18b77
FG
125 """
126 # apply overrides
127 overrides = config.get('overrides', {})
128 misc.deep_merge(config, overrides.get('dnsmasq', {}))
129
130 # multiple roles may map to the same remote, so collect names by remote
131 remote_names = {}
9f95a23c 132 for role, cnames in config.items():
31f18b77
FG
133 remote = get_remote_for_role(ctx, role)
134 if remote is None:
135 raise ConfigError('no remote for role %s' % role)
136
137 names = remote_names.get(remote, {})
138
139 if isinstance(cnames, list):
140 # when given a list of cnames, point to local ip
141 for cname in cnames:
11fdf7f2
TL
142 if cname.endswith('.'):
143 cname += remote.hostname
31f18b77
FG
144 names[cname] = remote.ip_address
145 elif isinstance(cnames, dict):
146 # when given a dict, look up the remote ip for each
9f95a23c 147 for cname, client in cnames.items():
31f18b77
FG
148 r = get_remote_for_role(ctx, client)
149 if r is None:
150 raise ConfigError('no remote for role %s' % client)
11fdf7f2
TL
151 if cname.endswith('.'):
152 cname += r.hostname
31f18b77
FG
153 names[cname] = r.ip_address
154
155 remote_names[remote] = names
156
11fdf7f2
TL
157 testdir = misc.get_testdir(ctx)
158 resolv_bak = '/'.join((testdir, 'resolv.bak'))
159 resolv_tmp = '/'.join((testdir, 'resolv.tmp'))
160
161 # run subtasks for each unique remote
31f18b77 162 subtasks = []
9f95a23c 163 for remote, cnames in remote_names.items():
11fdf7f2
TL
164 subtasks.extend([ lambda r=remote: install_dnsmasq(r) ])
165 subtasks.extend([ lambda r=remote: backup_resolv(r, resolv_bak) ])
166 subtasks.extend([ lambda r=remote: replace_resolv(r, resolv_tmp) ])
167 subtasks.extend([ lambda r=remote, cn=cnames: setup_dnsmasq(r, testdir, cn) ])
31f18b77
FG
168
169 with contextutil.nested(*subtasks):
170 yield