mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
177 lines
6.3 KiB
Python
177 lines
6.3 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
import CsHelper
|
|
import logging
|
|
from netaddr import *
|
|
from CsGuestNetwork import CsGuestNetwork
|
|
from cs.CsDatabag import CsDataBag
|
|
|
|
NO_PRELOAD = False
|
|
LEASES = "/var/lib/misc/dnsmasq.leases"
|
|
DHCP_HOSTS = "/etc/dhcphosts.txt"
|
|
DHCP_OPTS = "/etc/dhcpopts.txt"
|
|
DNSMASQ_CONF = "/etc/dnsmasq.conf"
|
|
CLOUD_CONF = "/etc/dnsmasq.d/cloud.conf"
|
|
|
|
|
|
class CsDhcp(CsDataBag):
|
|
""" Manage dhcp entries """
|
|
|
|
def process(self):
|
|
dnsmasq = CsDnsMasq(self.config)
|
|
for item in self.dbag:
|
|
if item == "id":
|
|
continue
|
|
dnsmasq.add(self.dbag[item])
|
|
dnsmasqb4 = CsDnsMasq(self.config, NO_PRELOAD)
|
|
dnsmasqb4.parse_hosts()
|
|
dnsmasqb4.parse_dnsmasq()
|
|
if not dnsmasq.compare_hosts(dnsmasqb4):
|
|
logging.info("Updating hosts file")
|
|
dnsmasq.write_hosts()
|
|
else:
|
|
logging.debug("Hosts file is up to date")
|
|
diff = dnsmasq.compare_dnsmasq(dnsmasqb4)
|
|
if len(diff) > 0:
|
|
dnsmasq.updated = True
|
|
dnsmasq.delete_leases(diff)
|
|
dnsmasq.write_dnsmasq()
|
|
dnsmasq.first_host = dnsmasqb4.first_host
|
|
dnsmasq.configure_server()
|
|
|
|
|
|
class CsDnsMasq(object):
|
|
|
|
def __init__(self, config, preload=True):
|
|
self.list = []
|
|
self.hosts = []
|
|
self.leases = []
|
|
self.config = config
|
|
self.updated = False
|
|
self.devinfo = CsHelper.get_device_info()
|
|
self.devs = []
|
|
self.first_host = False
|
|
if preload:
|
|
self.add_host("127.0.0.1", "localhost")
|
|
self.add_host("::1", "localhost ip6-localhost ip6-loopback")
|
|
self.add_host("ff02::1", "ip6-allnodes")
|
|
self.add_host("ff02::2", "ip6-allrouters")
|
|
self.add_host("127.0.0.1", CsHelper.get_hostname())
|
|
|
|
def delete_leases(self, clist):
|
|
try:
|
|
for line in open(LEASES):
|
|
bits = line.strip().split(' ')
|
|
to = {"device": bits[0],
|
|
"mac": bits[1],
|
|
"ip": bits[2],
|
|
"host": bits[3],
|
|
"del": False
|
|
}
|
|
for l in clist:
|
|
lbits = l.split(',')
|
|
if lbits[0] == to['mac'] or \
|
|
lbits[1] == to['ip']:
|
|
to['del'] is True
|
|
break
|
|
self.leases.append(to)
|
|
for o in self.leases:
|
|
if o['del']:
|
|
cmd = "dhcp_release %s %s %s" % (o.device, o.ip, o.mac)
|
|
logging.info(cmd)
|
|
CsHelper.execute(cmd)
|
|
# Finally add the new lease
|
|
except IOError:
|
|
return
|
|
|
|
def configure_server(self):
|
|
self.updated = self.updated | CsHelper.addifmissing(DNSMASQ_CONF, "dhcp-hostsfile=/etc/dhcphosts.txt")
|
|
# self.updated = self.updated | CsHelper.addifmissing(DNSMASQ_CONF, "dhcp-optsfile=%s:" % DHCP_OPTS)
|
|
for i in self.devinfo:
|
|
if not i['dnsmasq']:
|
|
continue
|
|
device = i['dev']
|
|
ip = i['ip'].split('/')[0]
|
|
line = "dhcp-range=interface:%s,set:interface-%s,%s,static" % (device, device, ip)
|
|
self.updated = self.updated | CsHelper.addifmissing(CLOUD_CONF, line)
|
|
# Next add the domain
|
|
# if this is a guest network get it there otherwise use the value in resolv.conf
|
|
gn = CsGuestNetwork(device, self.config)
|
|
line = "dhcp-option=tag:interface-%s,15,%s" % (device, gn.get_domain())
|
|
self.updated = self.updated | CsHelper.addifmissing(CLOUD_CONF, line)
|
|
if self.updated:
|
|
if self.first_host:
|
|
CsHelper.service("dnsmasq", "restart")
|
|
else:
|
|
CsHelper.hup_dnsmasq("dnsmasq", "dnsmasq")
|
|
|
|
def parse_dnsmasq(self):
|
|
self.first_host = False
|
|
try:
|
|
for line in open(DHCP_HOSTS):
|
|
self.list.append(line.strip())
|
|
if len(self.list) == 0:
|
|
self.first_host = True
|
|
except IOError:
|
|
self.first_host = True
|
|
|
|
def parse_hosts(self):
|
|
for line in open("/etc/hosts"):
|
|
line = line.rstrip().lstrip()
|
|
if line == '':
|
|
continue
|
|
if line.startswith("#"):
|
|
continue
|
|
bits = ' '.join(line.split()).split(' ', 1)
|
|
self.add_host(bits[0], bits[1])
|
|
|
|
def compare_hosts(self, obj):
|
|
return set(self.hosts) == set(obj.hosts)
|
|
|
|
def compare_dnsmasq(self, obj):
|
|
return list(set(self.list).symmetric_difference(set(obj.list)))
|
|
|
|
def write_hosts(self):
|
|
logging.debug("Updating hosts file")
|
|
handle = open("/etc/hosts", 'w+')
|
|
for line in self.hosts:
|
|
handle.write("%s\n" % line)
|
|
handle.close()
|
|
|
|
def write_dnsmasq(self):
|
|
logging.debug("Updating %s", DHCP_HOSTS)
|
|
handle = open(DHCP_HOSTS, 'w+')
|
|
for line in self.list:
|
|
handle.write("%s\n" % line)
|
|
b = line.split(',')
|
|
handle.close()
|
|
|
|
def add(self, entry):
|
|
self.add_host(entry['ipv4_adress'], entry['host_name'])
|
|
self.add_dnsmasq(entry['ipv4_adress'], entry['host_name'], entry['mac_address'])
|
|
i = IPAddress(entry['ipv4_adress'])
|
|
# Calculate the device
|
|
for v in self.devinfo:
|
|
if i > v['network'].network and i < v['network'].broadcast:
|
|
v['dnsmasq'] = True
|
|
|
|
def add_dnsmasq(self, ip, host, mac):
|
|
self.list.append("%s,%s,%s,infinite" % (mac, ip, host))
|
|
|
|
def add_host(self, ip, host):
|
|
self.hosts.append("%s\t%s" % (ip, host))
|