def _write_notify_script(self, state, script): name = self._get_notifier_path(state) utils.replace_file(name, script) st = os.stat(name) os.chmod(name, st.st_mode | stat.S_IEXEC) return name
def _generate_radvd_conf(self, router_ports): radvd_conf = utils.get_conf_file_name(cfg.CONF.ra_confs, self._router_id, 'radvd.conf', True) buf = six.StringIO() for p in router_ports: subnets = p.get('subnets', []) v6_subnets = [subnet for subnet in subnets if netaddr.IPNetwork(subnet['cidr']).version == 6] if not v6_subnets: continue ra_modes = {subnet['ipv6_ra_mode'] for subnet in v6_subnets} auto_config_prefixes = [subnet['cidr'] for subnet in v6_subnets if subnet['ipv6_ra_mode'] == constants.IPV6_SLAAC or subnet['ipv6_ra_mode'] == constants.DHCPV6_STATELESS] interface_name = self._dev_name_helper(p['id']) buf.write('%s' % CONFIG_TEMPLATE.render( ra_modes=list(ra_modes), interface_name=interface_name, prefixes=auto_config_prefixes, constants=constants)) utils.replace_file(radvd_conf, buf.getvalue()) return radvd_conf
def _output_hosts_file(self): """Writes a dnsmasq compatible dhcp hosts file. The generated file is sent to the --dhcp-hostsfile option of dnsmasq, and lists the hosts on the network which should receive a dhcp lease. Each line in this file is in the form:: 'mac_address,FQDN,ip_address' IMPORTANT NOTE: a dnsmasq instance does not resolve hosts defined in this file if it did not give a lease to a host listed in it (e.g.: multiple dnsmasq instances on the same network if this network is on multiple network nodes). This file is only defining hosts which should receive a dhcp lease, the hosts resolution in itself is defined by the `_output_addn_hosts_file` method. """ buf = six.StringIO() filename = self.get_conf_file_name('host') LOG.debug('Building host file: %s', filename) dhcp_enabled_subnet_ids = [s.id for s in self.network.subnets if s.enable_dhcp] # NOTE(ihrachyshka): the loop should not log anything inside it, to # avoid potential performance drop when lots of hosts are dumped for host_tuple in self._iter_hosts(): port, alloc, hostname, name, no_dhcp, no_opts = host_tuple if no_dhcp: if not no_opts and self._get_port_extra_dhcp_opts(port): buf.write('%s,%s%s\n' % (port.mac_address, 'set:', port.id)) continue # don't write ip address which belongs to a dhcp disabled subnet. if alloc.subnet_id not in dhcp_enabled_subnet_ids: continue ip_address = self._format_address_for_dnsmasq(alloc.ip_address) if self._get_port_extra_dhcp_opts(port): client_id = self._get_client_id(port) if client_id and len(port.extra_dhcp_opts) > 1: buf.write('%s,%s%s,%s,%s,%s%s\n' % (port.mac_address, self._ID, client_id, name, ip_address, 'set:', port.id)) elif client_id and len(port.extra_dhcp_opts) == 1: buf.write('%s,%s%s,%s,%s\n' % (port.mac_address, self._ID, client_id, name, ip_address)) else: buf.write('%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, 'set:', port.id)) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) utils.replace_file(filename, buf.getvalue()) LOG.debug('Done building host file %s with contents:\n%s', filename, buf.getvalue()) return filename
def _output_hosts_file(self): """Writes a dnsmasq compatible hosts file.""" r = re.compile('[:.]') buf = six.StringIO() for port in self.network.ports: for alloc in port.fixed_ips: name = 'host-%s.%s' % (r.sub('-', alloc.ip_address), self.conf.dhcp_domain) set_tag = '' # (dzyu) Check if it is legal ipv6 address, if so, need wrap # it with '[]' to let dnsmasq to distinguish MAC address from # IPv6 address. ip_address = alloc.ip_address if netaddr.valid_ipv6(ip_address): ip_address = '[%s]' % ip_address if getattr(port, 'extra_dhcp_opts', False): if self.version >= self.MINIMUM_VERSION: set_tag = 'set:' buf.write('%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, set_tag, port.id)) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) name = self.get_conf_file_name('host') utils.replace_file(name, buf.getvalue()) return name
def save_config(conf_path, logical_config, socket_path=None): """Convert a logical configuration to the HAProxy version.""" data = [] data.extend(_build_global(logical_config, socket_path=socket_path)) data.extend(_build_defaults(logical_config)) data.extend(_build_frontend(logical_config)) data.extend(_build_backend(logical_config)) utils.replace_file(conf_path, '\n'.join(data))
def ensure_config_file(self, kind, template, vpnservice, file_mode=None): """Update config file, based on current settings for service.""" config_str = self._gen_config_content(template, vpnservice) config_file_name = self._get_config_filename(kind) if file_mode is None: utils.replace_file(config_file_name, config_str) else: utils.replace_file(config_file_name, config_str, file_mode)
def _output_opts_file(self): """Write a dnsmasq compatible options file.""" options, subnet_index_map = self._generate_opts_per_subnet() options += self._generate_opts_per_port(subnet_index_map) name = self.get_conf_file_name('opts') utils.replace_file(name, '\n'.join(options)) return name
def _output_opts_file(self): """Write a dnsmasq compatible options file.""" if self.conf.enable_isolated_metadata: subnet_to_interface_ip = self._make_subnet_interface_ip_map() options = [] for i, subnet in enumerate(self.network.subnets): if not subnet.enable_dhcp: continue if subnet.dns_nameservers: options.append( self._format_option(i, 'dns-server', ','.join(subnet.dns_nameservers))) gateway = subnet.gateway_ip host_routes = [] for hr in subnet.host_routes: if hr.destination == "0.0.0.0/0": gateway = hr.nexthop else: host_routes.append("%s,%s" % (hr.destination, hr.nexthop)) # Add host routes for isolated network segments enable_metadata = ( self.conf.enable_isolated_metadata and not subnet.gateway_ip and subnet.ip_version == 4) if enable_metadata: subnet_dhcp_ip = subnet_to_interface_ip[subnet.id] host_routes.append( '%s/32,%s' % (METADATA_DEFAULT_IP, subnet_dhcp_ip) ) if host_routes: options.append( self._format_option(i, 'classless-static-route', ','.join(host_routes))) options.append( self._format_option(i, WIN2k3_STATIC_DNS, ','.join(host_routes))) if subnet.ip_version == 4: if gateway: options.append(self._format_option(i, 'router', gateway)) else: options.append(self._format_option(i, 'router')) for port in self.network.ports: if getattr(port, 'extra_dhcp_opts', False): options.extend( self._format_option(port.id, opt.opt_name, opt.opt_value) for opt in port.extra_dhcp_opts) name = self.get_conf_file_name('opts') utils.replace_file(name, '\n'.join(options)) return name
def save_config(conf_path, logical_config, socket_path=None, user_group='nogroup'): """Convert a logical configuration to the HAProxy version.""" data = [] data.extend(_build_global(logical_config, socket_path=socket_path, user_group=user_group)) data.extend(_build_defaults(logical_config)) data.extend(_build_frontend(logical_config)) data.extend(_build_backend(logical_config)) utils.replace_file(conf_path, '\n'.join(data)) #替换/var/lib/neutron/lbaas/3195b1f3-a453-4c35-a4a2-aa63b2678765/conf
def _write_intf_file(self): global _devices confs_dir = os.path.abspath(os.path.normpath(self.conf.dhcp_confs)) conf_dir = os.path.join(confs_dir, self.network.id) if not os.path.isdir(conf_dir): os.makedirs(conf_dir, 0o755) intf_filename = os.path.join(conf_dir, 'interface') if self.network.id not in _devices: return ifname = _devices[self.network.id] utils.replace_file(intf_filename, ifname)
def _output_hosts_file(self): """Writes a dnsmasq compatible dhcp hosts file. The generated file is sent to the --dhcp-hostsfile option of dnsmasq, and lists the hosts on the network which should receive a dhcp lease. Each line in this file is in the form:: 'mac_address,FQDN,ip_address' IMPORTANT NOTE: a dnsmasq instance does not resolve hosts defined in this file if it did not give a lease to a host listed in it (e.g.: multiple dnsmasq instances on the same network if this network is on multiple network nodes). This file is only defining hosts which should receive a dhcp lease, the hosts resolution in itself is defined by the `_output_addn_hosts_file` method. """ buf = six.StringIO() filename = self.get_conf_file_name('host') LOG.debug('Building host file: %s', filename) dhcp_enabled_subnet_ids = [s.id for s in self.network.subnets if s.enable_dhcp] # NOTE(ihrachyshka): the loop should not log anything inside it, to # avoid potential performance drop when lots of hosts are dumped for (port, alloc, hostname, name) in self._iter_hosts(): if not alloc: if getattr(port, 'extra_dhcp_opts', False): buf.write('%s,%s%s\n' % (port.mac_address, 'set:', port.id)) continue # don't write ip address which belongs to a dhcp disabled subnet. if alloc.subnet_id not in dhcp_enabled_subnet_ids: continue # (dzyu) Check if it is legal ipv6 address, if so, need wrap # it with '[]' to let dnsmasq to distinguish MAC address from # IPv6 address. ip_address = alloc.ip_address if netaddr.valid_ipv6(ip_address): ip_address = '[%s]' % ip_address if getattr(port, 'extra_dhcp_opts', False): buf.write('%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, 'set:', port.id)) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) utils.replace_file(filename, buf.getvalue()) LOG.debug('Done building host file %s with contents:\n%s', filename, buf.getvalue()) return filename
def test_replace_file(self): # make file to replace with mock.patch("tempfile.NamedTemporaryFile") as ntf: ntf.return_value.name = "/baz" with mock.patch("os.chmod") as chmod: with mock.patch("os.rename") as rename: utils.replace_file("/foo", "bar") expected = [mock.call("w+", dir="/", delete=False), mock.call().write("bar"), mock.call().close()] ntf.assert_has_calls(expected) chmod.assert_called_once_with("/baz", 0o644) rename.assert_called_once_with("/baz", "/foo")
def _store_listener_crt(haproxy_base_dir, listener, cert): """Store TLS certificate :param haproxy_base_dir: location of the instances state data :param listener: the listener object :param cert: the TLS certificate :return: location of the stored certificate """ cert_path = _retrieve_crt_path(haproxy_base_dir, listener, cert.primary_cn) # build a string that represents the pem file to be saved pem = _build_pem(cert) utils.replace_file(cert_path, pem) return cert_path
def save_config(conf_path, loadbalancer, socket_path, user_group, haproxy_base_dir): """Convert a logical configuration to the HAProxy version. :param conf_path: location of Haproxy configuration :param loadbalancer: the load balancer object :param socket_path: location of haproxy socket data :param user_group: user group :param haproxy_base_dir: location of the instances state data """ config_str = render_loadbalancer_obj(loadbalancer, user_group, socket_path, haproxy_base_dir) utils.replace_file(conf_path, config_str)
def test_replace_file(self): # make file to replace with mock.patch('tempfile.NamedTemporaryFile') as ntf: ntf.return_value.name = '/baz' with mock.patch('os.chmod') as chmod: with mock.patch('os.rename') as rename: utils.replace_file('/foo', 'bar') expected = [mock.call('w+', dir='/', delete=False), mock.call().write('bar'), mock.call().close()] ntf.assert_has_calls(expected) chmod.assert_called_once_with('/baz', 0o644) rename.assert_called_once_with('/baz', '/foo')
def _output_hosts_file(self): """Writes a dnsmasq compatible hosts file.""" r = re.compile('[:.]') buf = StringIO.StringIO() for port in self.network.ports: for alloc in port.fixed_ips: name = 'host-%s.%s' % (r.sub('-', alloc.ip_address), self.conf.dhcp_domain) buf.write('%s,%s,%s\n' % (port.mac_address, name, alloc.ip_address)) name = self.get_conf_file_name('host') utils.replace_file(name, buf.getvalue()) return name
def save_config(conf_path, logical_config): """Convert a logical configuration to the SEnginx version.""" protocol = logical_config['vip']['protocol'] if not protocol: return data = [] data.extend(_build_global(logical_config)) # build protocol specified configs if PROTOCOL_MAP[protocol] == "http": data.extend(_build_http(logical_config)) else: data.extend(_build_tcp(logical_config)) utils.replace_file(conf_path, '\n'.join(data))
def _output_hosts_file(self): """Writes a dnsmasq compatible dhcp hosts file. The generated file is sent to the --dhcp-hostsfile option of dnsmasq, and lists the hosts on the network which should receive a dhcp lease. Each line in this file is in the form:: 'mac_address,FQDN,ip_address' IMPORTANT NOTE: a dnsmasq instance does not resolve hosts defined in this file if it did not give a lease to a host listed in it (e.g.: multiple dnsmasq instances on the same network if this network is on multiple network nodes). This file is only defining hosts which should receive a dhcp lease, the hosts resolution in itself is defined by the `_output_addn_hosts_file` method. """ buf = six.StringIO() filename = self.get_conf_file_name('host') LOG.debug(_('Building host file: %s'), filename) for (port, alloc, hostname, name) in self._iter_hosts(): set_tag = '' # (dzyu) Check if it is legal ipv6 address, if so, need wrap # it with '[]' to let dnsmasq to distinguish MAC address from # IPv6 address. ip_address = alloc.ip_address if netaddr.valid_ipv6(ip_address): ip_address = '[%s]' % ip_address LOG.debug(_('Adding %(mac)s : %(name)s : %(ip)s'), {"mac": port.mac_address, "name": name, "ip": ip_address}) if getattr(port, 'extra_dhcp_opts', False): if self.version >= self.MINIMUM_VERSION: set_tag = 'set:' buf.write('%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, set_tag, port.id)) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) utils.replace_file(filename, buf.getvalue()) LOG.debug(_('Done building host file %s'), filename) return filename
def _generate_radvd_conf(router_id, router_ports, dev_name_helper): radvd_conf = utils.get_conf_file_name(cfg.CONF.ra_confs, router_id, "radvd.conf", True) buf = six.StringIO() for p in router_ports: prefix = p["subnet"]["cidr"] if netaddr.IPNetwork(prefix).version == 6: interface_name = dev_name_helper(p["id"]) ra_mode = p["subnet"]["ipv6_ra_mode"] buf.write( "%s" % CONFIG_TEMPLATE.render( ra_mode=ra_mode, interface_name=interface_name, prefix=prefix, constants=constants ) ) utils.replace_file(radvd_conf, buf.getvalue()) return radvd_conf
def _generate_radvd_conf(router_id, router_ports, dev_name_helper): radvd_conf = utils.get_conf_file_name(cfg.CONF.ra_confs, router_id, 'radvd.conf', True) buf = six.StringIO() for p in router_ports: if netaddr.IPNetwork(p['subnet']['cidr']).version == 6: interface_name = dev_name_helper(p['id']) if _is_slaac(p['subnet']['ipv6_ra_mode']): conf_str = prefix_fmt % (interface_name, p['subnet']['cidr']) else: conf_str = default_fmt % interface_name buf.write('%s' % conf_str) utils.replace_file(radvd_conf, buf.getvalue()) return radvd_conf
def _output_addn_hosts_file(self): """Writes a dnsmasq compatible additional hosts file. The generated file is sent to the --addn-hosts option of dnsmasq, and lists the hosts on the network which should be resolved even if the dnsmaq instance did not give a lease to the host (see the `_output_hosts_file` method). Each line in this file is in the same form as a standard /etc/hosts file. """ buf = six.StringIO() for (port, alloc, hostname, fqdn) in self._iter_hosts(): # It is compulsory to write the `fqdn` before the `hostname` in # order to obtain it in PTR responses. buf.write('%s\t%s %s\n' % (alloc.ip_address, fqdn, hostname)) addn_hosts = self.get_conf_file_name('addn_hosts') utils.replace_file(addn_hosts, buf.getvalue()) return addn_hosts
def _test_replace_file_helper(self, explicit_perms=None): # make file to replace with mock.patch("tempfile.NamedTemporaryFile") as ntf: ntf.return_value.name = "/baz" with mock.patch("os.chmod") as chmod: with mock.patch("os.rename") as rename: if explicit_perms is None: expected_perms = 0o644 utils.replace_file("/foo", "bar") else: expected_perms = explicit_perms utils.replace_file("/foo", "bar", explicit_perms) expected = [mock.call("w+", dir="/", delete=False), mock.call().write("bar"), mock.call().close()] ntf.assert_has_calls(expected) chmod.assert_called_once_with("/baz", expected_perms) rename.assert_called_once_with("/baz", "/foo")
def _output_init_lease_file(self): """Write a fake lease file to bootstrap dnsmasq. The generated file is passed to the --dhcp-leasefile option of dnsmasq. This is used as a bootstrapping mechanism to avoid NAKing active leases when a dhcp server is scheduled to another agent. Using a leasefile will also prevent dnsmasq from NAKing or ignoring renewals after a restart. Format is as follows: epoch-timestamp mac_addr ip_addr hostname client-ID """ filename = self.get_conf_file_name('leases') buf = six.StringIO() LOG.debug('Building initial lease file: %s', filename) # we make up a lease time for the database entry if self.conf.dhcp_lease_duration == -1: # Even with an infinite lease, a client may choose to renew a # previous lease on reboot or interface bounce so we should have # an entry for it. # Dnsmasq timestamp format for an infinite lease is 0. timestamp = 0 else: timestamp = int(time.time()) + self.conf.dhcp_lease_duration dhcp_enabled_subnet_ids = [s.id for s in self.network.subnets if s.enable_dhcp] for host_tuple in self._iter_hosts(): port, alloc, hostname, name, no_dhcp, no_opts = host_tuple # don't write ip address which belongs to a dhcp disabled subnet # or an IPv6 SLAAC/stateless subnet if no_dhcp or alloc.subnet_id not in dhcp_enabled_subnet_ids: continue ip_address = self._format_address_for_dnsmasq(alloc.ip_address) # all that matters is the mac address and IP. the hostname and # client ID will be overwritten on the next renewal. buf.write('%s %s %s * *\n' % (timestamp, port.mac_address, ip_address)) contents = buf.getvalue() utils.replace_file(filename, contents) LOG.debug('Done building initial lease file %s with contents:\n%s', filename, contents) return filename
def _generate_radvd_conf(self, router_ports): radvd_conf = utils.get_conf_file_name(cfg.CONF.ra_confs, self._router_id, 'radvd.conf', True) buf = six.StringIO() for p in router_ports: prefix = p['subnet']['cidr'] if netaddr.IPNetwork(prefix).version == 6: interface_name = self._dev_name_helper(p['id']) ra_mode = p['subnet']['ipv6_ra_mode'] buf.write('%s' % CONFIG_TEMPLATE.render( ra_mode=ra_mode, interface_name=interface_name, prefix=prefix, constants=constants)) utils.replace_file(radvd_conf, buf.getvalue()) return radvd_conf
def _output_hosts_file(self): """Writes a dnsmasq compatible dhcp hosts file. The generated file is sent to the --dhcp-hostsfile option of dnsmasq, and lists the hosts on the network which should receive a dhcp lease. Each line in this file is in the form:: 'mac_address,FQDN,ip_address' IMPORTANT NOTE: a dnsmasq instance does not resolve hosts defined in this file if it did not give a lease to a host listed in it (e.g.: multiple dnsmasq instances on the same network if this network is on multiple network nodes). This file is only defining hosts which should receive a dhcp lease, the hosts resolution in itself is defined by the `_output_addn_hosts_file` method. """ buf = six.StringIO() filename = self.get_conf_file_name('host') LOG.debug(_('Building host file: %s'), filename) # NOTE(ihrachyshka): the loop should not log anything inside it, to # avoid potential performance drop when lots of hosts are dumped for (port, alloc, hostname, name) in self._iter_hosts(): if not alloc: if getattr(port, 'extra_dhcp_opts', False): buf.write('%s,%s%s\n' % (port.mac_address, 'set:', port.id)) continue ip_address = self._format_address_for_dnsmasq(alloc.ip_address) if getattr(port, 'extra_dhcp_opts', False): buf.write('%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, 'set:', port.id)) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) utils.replace_file(filename, buf.getvalue()) LOG.debug('Done building host file %s with contents:\n%s', filename, buf.getvalue()) return filename
def _output_hosts_file(self): """Writes a dnsmasq compatible hosts file.""" r = re.compile("[:.]") buf = StringIO.StringIO() for port in self.network.ports: for alloc in port.fixed_ips: name = "host-%s.%s" % (r.sub("-", alloc.ip_address), self.conf.dhcp_domain) set_tag = "" if getattr(port, "extra_dhcp_opts", False): if self.version >= self.MINIMUM_VERSION: set_tag = "set:" buf.write("%s,%s,%s,%s%s\n" % (port.mac_address, name, alloc.ip_address, set_tag, port.id)) else: buf.write("%s,%s,%s\n" % (port.mac_address, name, alloc.ip_address)) name = self.get_conf_file_name("host") utils.replace_file(name, buf.getvalue()) return name
def _test_replace_file_helper(self, explicit_perms=None): # make file to replace with mock.patch('tempfile.NamedTemporaryFile') as ntf: ntf.return_value.name = '/baz' with mock.patch('os.chmod') as chmod: with mock.patch('os.rename') as rename: if explicit_perms is None: expected_perms = 0o644 utils.replace_file('/foo', 'bar') else: expected_perms = explicit_perms utils.replace_file('/foo', 'bar', explicit_perms) expected = [mock.call('w+', dir='/', delete=False), mock.call().write('bar'), mock.call().close()] ntf.assert_has_calls(expected) chmod.assert_called_once_with('/baz', expected_perms) rename.assert_called_once_with('/baz', '/foo')
def _generate_dibbler_conf(self, ex_gw_ifname, lla): dcwa = self.dibbler_client_working_area script_path = utils.get_conf_file_name(dcwa, 'notify', 'sh', True) buf = six.StringIO() buf.write('%s' % SCRIPT_TEMPLATE.render( prefix_path=self.prefix_path, l3_agent_pid=os.getpid())) utils.replace_file(script_path, buf.getvalue()) os.chmod(script_path, 0o744) dibbler_conf = utils.get_conf_file_name(dcwa, 'client', 'conf', False) buf = six.StringIO() buf.write('%s' % CONFIG_TEMPLATE.render( enterprise_number=cfg.CONF.vendor_pen, va_id='0x%s' % self.converted_subnet_id, script_path='"%s/notify.sh"' % dcwa, interface_name='"%s"' % ex_gw_ifname, bind_address='%s' % lla)) utils.replace_file(dibbler_conf, buf.getvalue()) return dcwa
def _spawn(self): try: conf_path = self._get_state_file_path('conf') pid_path = self._get_state_file_path('pid') if not self.pools_config: kill_pids_in_file(self.root_helper, pid_path) return utils.replace_file(conf_path, self.pools_config) cmd = ['haproxy', '-f', conf_path, '-p', pid_path] if self.check_process(): pid_path = self._get_state_file_path('pid') extra_args = ['-sf'] extra_args.extend(p.strip() for p in open(pid_path, 'r')) cmd.extend(extra_args) utils.execute(cmd, root_helper=self.root_helper) except Exception: LOG.exception('Spawn haproxy process failed.') self.needs_resync = True
def ensure_config_file(self, template, vpnservice): """Update config file, based on current settings for service.""" vpn_credential = vpnservice['ssl_vpn_connections'][0]['vpncredential'] config_file_name = self._get_config_filename('ca.crt') utils.replace_file(config_file_name, vpn_credential['ca'], permission=0o600) config_file_name = self._get_config_filename('server.crt') utils.replace_file( config_file_name, vpn_credential['server_certificate'], permission=0o600) config_file_name = self._get_config_filename('server.key') utils.replace_file(config_file_name, vpn_credential['server_key'], permission=0o600) config_file_name = self._get_config_filename('dh1024.pem') utils.replace_file(config_file_name, vpn_credential['dh'], permission=0o600) config_str = self._gen_config_content(template, vpnservice) config_file_name = self._get_config_filename('openvpn.conf') utils.replace_file(config_file_name, config_str)
def interface_name(self, value): interface_file_path = self.get_conf_file_name('interface') utils.replace_file(interface_file_path, value)
def _output_hosts_file(self): """Writes a dnsmasq compatible dhcp hosts file. The generated file is sent to the --dhcp-hostsfile option of dnsmasq, and lists the hosts on the network which should receive a dhcp lease. Each line in this file is in the form:: 'mac_address,FQDN,ip_address' IMPORTANT NOTE: a dnsmasq instance does not resolve hosts defined in this file if it did not give a lease to a host listed in it (e.g.: multiple dnsmasq instances on the same network if this network is on multiple network nodes). This file is only defining hosts which should receive a dhcp lease, the hosts resolution in itself is defined by the `_output_addn_hosts_file` method. """ buf = six.StringIO() filename = self.get_conf_file_name('host') LOG.debug('Building host file: %s', filename) dhcp_enabled_subnet_ids = [ s.id for s in self.network.subnets if s.enable_dhcp ] for (port, alloc, hostname, name) in self._iter_hosts(): if not alloc: if getattr(port, 'extra_dhcp_opts', False): buf.write('%s,%s%s\n' % (port.mac_address, 'set:', port.id)) LOG.debug('Adding %(mac)s : set:%(tag)s', { "mac": port.mac_address, "tag": port.id }) continue # don't write ip address which belongs to a dhcp disabled subnet. if alloc.subnet_id not in dhcp_enabled_subnet_ids: continue # (dzyu) Check if it is legal ipv6 address, if so, need wrap # it with '[]' to let dnsmasq to distinguish MAC address from # IPv6 address. ip_address = alloc.ip_address if netaddr.valid_ipv6(ip_address): ip_address = '[%s]' % ip_address if getattr(port, 'extra_dhcp_opts', False): buf.write( '%s,%s,%s,%s%s\n' % (port.mac_address, name, ip_address, 'set:', port.id)) LOG.debug( 'Adding %(mac)s : %(name)s : %(ip)s : ' 'set:%(tag)s', { "mac": port.mac_address, "name": name, "ip": ip_address, "tag": port.id }) else: buf.write('%s,%s,%s\n' % (port.mac_address, name, ip_address)) LOG.debug('Adding %(mac)s : %(name)s : %(ip)s', { "mac": port.mac_address, "name": name, "ip": ip_address }) utils.replace_file(filename, buf.getvalue()) LOG.debug('Done building host file %s', filename) return filename
def _output_opts_file(self): """Write a dnsmasq compatible options file.""" if self.conf.enable_isolated_metadata: subnet_to_interface_ip = self._make_subnet_interface_ip_map() options = [] dhcp_ips = collections.defaultdict(list) subnet_idx_map = {} for i, subnet in enumerate(self.network.subnets): if not subnet.enable_dhcp: continue if subnet.dns_nameservers: options.append( self._format_option(i, 'dns-server', ','.join(subnet.dns_nameservers))) else: # use the dnsmasq ip as nameservers only if there is no # dns-server submitted by the server subnet_idx_map[subnet.id] = i gateway = subnet.gateway_ip host_routes = [] for hr in subnet.host_routes: if hr.destination == "0.0.0.0/0": if not gateway: gateway = hr.nexthop else: host_routes.append("%s,%s" % (hr.destination, hr.nexthop)) # Add host routes for isolated network segments if self._enable_metadata(subnet): subnet_dhcp_ip = subnet_to_interface_ip[subnet.id] host_routes.append('%s/32,%s' % (METADATA_DEFAULT_IP, subnet_dhcp_ip)) if host_routes: if gateway and subnet.ip_version == 4: host_routes.append("%s,%s" % ("0.0.0.0/0", gateway)) options.append( self._format_option(i, 'classless-static-route', ','.join(host_routes))) options.append( self._format_option(i, WIN2k3_STATIC_DNS, ','.join(host_routes))) if subnet.ip_version == 4: if gateway: options.append(self._format_option(i, 'router', gateway)) else: options.append(self._format_option(i, 'router')) for port in self.network.ports: if getattr(port, 'extra_dhcp_opts', False): options.extend( self._format_option(port.id, opt.opt_name, opt.opt_value) for opt in port.extra_dhcp_opts) # provides all dnsmasq ip as dns-server if there is more than # one dnsmasq for a subnet and there is no dns-server submitted # by the server if port.device_owner == constants.DEVICE_OWNER_DHCP: for ip in port.fixed_ips: i = subnet_idx_map.get(ip.subnet_id) if i is None: continue dhcp_ips[i].append(ip.ip_address) for i, ips in dhcp_ips.items(): if len(ips) > 1: options.append( self._format_option(i, 'dns-server', ','.join(ips))) name = self.get_conf_file_name('opts') utils.replace_file(name, '\n'.join(options)) return name
def _output_config_file(self): config_str = self.config.get_config_str() config_path = self._get_full_config_file_path('keepalived.conf') utils.replace_file(config_path, config_str) return config_path
def interface_name(self, value): interface_file_path = self.get_conf_file_name('interface', ensure_conf_dir=True) utils.replace_file(interface_file_path, value)
def _output_opts_file(self): """Write a dnsmasq compatible options file.""" if self.conf.enable_isolated_metadata: subnet_to_interface_ip = self._make_subnet_interface_ip_map() options = [] isolated_subnets = self.get_isolated_subnets(self.network) dhcp_ips = collections.defaultdict(list) subnet_idx_map = {} for i, subnet in enumerate(self.network.subnets): if (not subnet.enable_dhcp or (subnet.ip_version == 6 and getattr(subnet, 'ipv6_address_mode', None) in [None, constants.IPV6_SLAAC])): continue if subnet.dns_nameservers: options.append( self._format_option( subnet.ip_version, i, 'dns-server', ','.join( Dnsmasq._convert_to_literal_addrs( subnet.ip_version, subnet.dns_nameservers)))) else: # use the dnsmasq ip as nameservers only if there is no # dns-server submitted by the server subnet_idx_map[subnet.id] = i if self.conf.dhcp_domain and subnet.ip_version == 6: options.append('tag:tag%s,option6:domain-search,%s' % (i, ''.join(self.conf.dhcp_domain))) gateway = subnet.gateway_ip host_routes = [] for hr in subnet.host_routes: if hr.destination == "0.0.0.0/0": if not gateway: gateway = hr.nexthop else: host_routes.append("%s,%s" % (hr.destination, hr.nexthop)) # Add host routes for isolated network segments if (isolated_subnets[subnet.id] and self.conf.enable_isolated_metadata and subnet.ip_version == 4): subnet_dhcp_ip = subnet_to_interface_ip[subnet.id] host_routes.append('%s/32,%s' % (METADATA_DEFAULT_IP, subnet_dhcp_ip)) if subnet.ip_version == 4: if host_routes: if gateway: host_routes.append("%s,%s" % ("0.0.0.0/0", gateway)) options.append( self._format_option(subnet.ip_version, i, 'classless-static-route', ','.join(host_routes))) options.append( self._format_option(subnet.ip_version, i, WIN2k3_STATIC_DNS, ','.join(host_routes))) if gateway: options.append( self._format_option(subnet.ip_version, i, 'router', gateway)) else: options.append( self._format_option(subnet.ip_version, i, 'router')) for port in self.network.ports: if getattr(port, 'extra_dhcp_opts', False): for ip_version in (4, 6): if any( netaddr.IPAddress(ip.ip_address).version == ip_version for ip in port.fixed_ips): options.extend( # TODO(xuhanp):Instead of applying extra_dhcp_opts # to both DHCPv4 and DHCPv6, we need to find a new # way to specify options for v4 and v6 # respectively. We also need to validate the option # before applying it. self._format_option(ip_version, port.id, opt.opt_name, opt.opt_value) for opt in port.extra_dhcp_opts) # provides all dnsmasq ip as dns-server if there is more than # one dnsmasq for a subnet and there is no dns-server submitted # by the server if port.device_owner == constants.DEVICE_OWNER_DHCP: for ip in port.fixed_ips: i = subnet_idx_map.get(ip.subnet_id) if i is None: continue dhcp_ips[i].append(ip.ip_address) for i, ips in dhcp_ips.items(): for ip_version in (4, 6): vx_ips = [ ip for ip in ips if netaddr.IPAddress(ip).version == ip_version ] if vx_ips: options.append( self._format_option( ip_version, i, 'dns-server', ','.join( Dnsmasq._convert_to_literal_addrs( ip_version, vx_ips)))) name = self.get_conf_file_name('opts') utils.replace_file(name, '\n'.join(options)) return name
def ensure_config_file(self, kind, template, vpnservice): """Update config file, based on current settings for service.""" config_str = self._gen_config_content(template, vpnservice) config_file_name = self._get_config_filename(kind) utils.replace_file(config_file_name, config_str)