]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/dnsmasq.py
2bf3feaf083714e490c58f5e6ccca15f168c823d
2 Task for dnsmasq configuration
7 from teuthology
import misc
8 from teuthology
.exceptions
import ConfigError
9 from teuthology
import contextutil
10 from teuthology
import packaging
11 from util
import get_remote_for_role
13 log
= logging
.getLogger(__name__
)
15 @contextlib.contextmanager
16 def install_dnsmasq(remote
):
18 If dnsmasq is not installed, install it for the duration of the task.
21 existing
= packaging
.get_package_version(remote
, 'dnsmasq')
26 packaging
.install_package('dnsmasq', remote
)
31 packaging
.remove_package('dnsmasq', remote
)
33 @contextlib.contextmanager
34 def backup_resolv(remote
, path
):
36 Store a backup of resolv.conf in the testdir and restore it after the task.
38 remote
.run(args
=['cp', '/etc/resolv.conf', path
])
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
])
46 @contextlib.contextmanager
47 def replace_resolv(remote
, path
):
49 Update resolv.conf to point the nameserver at localhost.
51 misc
.write_file(remote
, path
, "nameserver 127.0.0.1\n")
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'])
60 remote
.run(args
=['rm', path
])
62 @contextlib.contextmanager
63 def setup_dnsmasq(remote
, testdir
, cnames
):
64 """ configure dnsmasq on the given remote, adding each cname given """
65 log
.info('Configuring dnsmasq on remote %s..', remote
.name
)
67 # add address entries for each cname
68 dnsmasq
= "server=8.8.8.8\nserver=8.8.4.4\n"
69 address_template
= "address=/{cname}/{ip_address}\n"
70 for cname
, ip_address
in cnames
.items():
71 dnsmasq
+= address_template
.format(cname
=cname
, ip_address
=ip_address
)
73 # write to temporary dnsmasq file
74 dnsmasq_tmp
= '/'.join((testdir
, 'ceph.tmp'))
75 misc
.write_file(remote
, dnsmasq_tmp
, dnsmasq
)
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)
84 remote
.run(args
=['sudo', 'systemctl', 'restart', 'dnsmasq'])
85 # verify dns name is set
86 remote
.run(args
=['ping', '-c', '4', cnames
.keys()[0]])
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
])
95 remote
.run(args
=['sudo', 'systemctl', 'restart', 'dnsmasq'])
97 @contextlib.contextmanager
98 def task(ctx
, config
):
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:
108 - client0.example.com
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:
116 client.0.example.com: client.0
117 client.1.example.com: client.1
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:
124 client.0: [dev., test.]
127 overrides
= config
.get('overrides', {})
128 misc
.deep_merge(config
, overrides
.get('dnsmasq', {}))
130 # multiple roles may map to the same remote, so collect names by remote
132 for role
, cnames
in config
.items():
133 remote
= get_remote_for_role(ctx
, role
)
135 raise ConfigError('no remote for role %s' % role
)
137 names
= remote_names
.get(remote
, {})
139 if isinstance(cnames
, list):
140 # when given a list of cnames, point to local ip
142 if cname
.endswith('.'):
143 cname
+= remote
.hostname
144 names
[cname
] = remote
.ip_address
145 elif isinstance(cnames
, dict):
146 # when given a dict, look up the remote ip for each
147 for cname
, client
in cnames
.items():
148 r
= get_remote_for_role(ctx
, client
)
150 raise ConfigError('no remote for role %s' % client
)
151 if cname
.endswith('.'):
153 names
[cname
] = r
.ip_address
155 remote_names
[remote
] = names
157 testdir
= misc
.get_testdir(ctx
)
158 resolv_bak
= '/'.join((testdir
, 'resolv.bak'))
159 resolv_tmp
= '/'.join((testdir
, 'resolv.tmp'))
161 # run subtasks for each unique remote
163 for remote
, cnames
in remote_names
.items():
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
) ])
169 with contextutil
.nested(*subtasks
):