Commit 5f177e1f authored by Alain Takoudjou's avatar Alain Takoudjou

partition can request to update ip route of tap interface

parent 36d19481
...@@ -840,8 +840,10 @@ class Tap(object): ...@@ -840,8 +840,10 @@ class Tap(object):
if self.ipv4_addr: if self.ipv4_addr:
# Check if this route exits # Check if this route exits
code, result = callAndRead(['ip', 'route', 'show', self.ipv4_addr]) code, result = callAndRead(['ip', 'route', 'show', self.ipv4_addr])
if code == 0 and self.ipv4_addr in result and self.name in result: if self.ipv4_addr in result:
# Skip already configured route
return return
code, result = callAndRead(['ip', 'route', 'show'])
callAndRead(['route', 'add', '-host', self.ipv4_addr, 'dev', self.name]) callAndRead(['route', 'add', '-host', self.ipv4_addr, 'dev', self.name])
else: else:
raise ValueError("%s should not be empty. No ipv4 address assigned to %s" % raise ValueError("%s should not be empty. No ipv4 address assigned to %s" %
......
...@@ -42,6 +42,7 @@ import warnings ...@@ -42,6 +42,7 @@ import warnings
import logging import logging
import json import json
import shutil import shutil
import ConfigParser
if sys.version_info < (2, 6): if sys.version_info < (2, 6):
warnings.warn('Used python version (%s) is old and has problems with' warnings.warn('Used python version (%s) is old and has problems with'
...@@ -61,8 +62,10 @@ from slapos.grid.svcbackend import (launchSupervisord, ...@@ -61,8 +62,10 @@ from slapos.grid.svcbackend import (launchSupervisord,
_getSupervisordSocketPath) _getSupervisordSocketPath)
from slapos.grid.utils import (md5digest, dropPrivileges, SlapPopen, updateFile) from slapos.grid.utils import (md5digest, dropPrivileges, SlapPopen, updateFile)
from slapos.human import human2bytes from slapos.human import human2bytes
from slapos.format import callAndRead
import slapos.slap import slapos.slap
from netaddr import valid_ipv4, valid_ipv6 from netaddr import valid_ipv4, valid_ipv6
import netifaces
# XXX: should be moved to SLAP library # XXX: should be moved to SLAP library
...@@ -79,6 +82,7 @@ PROMISE_TIMEOUT = 3 ...@@ -79,6 +82,7 @@ PROMISE_TIMEOUT = 3
COMPUTER_PARTITION_TIMESTAMP_FILENAME = '.timestamp' COMPUTER_PARTITION_TIMESTAMP_FILENAME = '.timestamp'
COMPUTER_PARTITION_LATEST_BANG_TIMESTAMP_FILENAME = '.slapos_latest_bang_timestamp' COMPUTER_PARTITION_LATEST_BANG_TIMESTAMP_FILENAME = '.slapos_latest_bang_timestamp'
COMPUTER_PARTITION_INSTALL_ERROR_FILENAME = '.slapgrid-%s-error.log' COMPUTER_PARTITION_INSTALL_ERROR_FILENAME = '.slapgrid-%s-error.log'
COMPUTER_PARTITION_UPDATE_TAP_ROUTE = '.%s-request-update-route'
# XXX hardcoded watchdog_path # XXX hardcoded watchdog_path
WATCHDOG_PATH = '/opt/slapos/bin/slapos-watchdog' WATCHDOG_PATH = '/opt/slapos/bin/slapos-watchdog'
...@@ -396,6 +400,40 @@ class Slapgrid(object): ...@@ -396,6 +400,40 @@ class Slapgrid(object):
self.ipv4_global_network= "" self.ipv4_global_network= ""
self.firewall_conf = firewall_conf self.firewall_conf = firewall_conf
def _getDefaultNetworkInterface(self):
return netifaces.gateways()['default'][netifaces.AF_INET]
def _checkIpAddressOnIfaces(self, ip):
"""
Check if ip address already exists on server
"""
for iface in netifaces.interfaces():
if iface == 'lo':
continue
address_list = netifaces.ifaddresses(iface)
if address_list.has_key(netifaces.AF_INET):
for address in address_list[netifaces.AF_INET]:
if address['addr'] == ip:
return iface, address
def _checkAndExecuteRouteCmd(self, run_command, check_command, check_list, rule_exists=False):
self.logger.debug("Execute command: %s" % ' '.join(check_command))
_, result = callAndRead(check_command)
rule_found = False
for result_line in result.split('\n'):
if not result_line:
continue
rule_found = True
for item in check_list:
rule_found = rule_found and item in result_line
if rule_found:
break
if not rule_exists and not rule_found:
self.logger.debug("Execute command: %s" % ' '.join(run_command))
return callAndRead(run_command)
elif rule_exists and rule_found:
self.logger.debug("Execute command: %s" % ' '.join(run_command))
return callAndRead(run_command)
def _getWatchdogLine(self): def _getWatchdogLine(self):
invocation_list = [WATCHDOG_PATH] invocation_list = [WATCHDOG_PATH]
...@@ -862,6 +900,141 @@ stderr_logfile_backups=1 ...@@ -862,6 +900,141 @@ stderr_logfile_backups=1
self.logger.warn("IP/Network address %s is not valid. ignored.." % ip) self.logger.warn("IP/Network address %s is not valid. ignored.." % ip)
return valid_list return valid_list
def _restoreSlapTapRoute(self, partition_id, ipv4):
instance_path = os.path.join(self.instance_root, partition_id)
saved_request_file = os.path.join(
instance_path, '.slapos-request-update-route')
if not os.path.exists(saved_request_file):
return
self.logger.debug("Cleaning custom ip routes...")
config_request = ConfigParser.ConfigParser()
try:
config_request.readfp(open(saved_request_file))
except ConfigParser.MissingSectionHeaderError:
self.logger.error("%s: Invalid config file specified." % saved_request_file)
raise
route_section = '%s-routes' % partition_id
if not route_section in config_request.sections():
raise Exception("Section %s required to restore ip route configuration" \
"is not found in file %s" % (route_section, saved_request_file))
gateway_ip = tap_ip = ''
option_list = config_request.options(route_section)
interface = config_request.get(route_section, 'interface')
if 'forward-to-ip' in option_list:
gateway_ip = config_request.get(route_section, 'forward-to-ip')
if 'ip-to-interface' in option_list:
tap_ip = config_request.get(route_section, 'ip-to-interface')
if gateway_ip:
tap_route_cmd = ['route', 'del', ipv4, 'gw', gateway_ip]
tap_default_cmd = ['route', 'add', '-host', ipv4, 'dev', interface]
self._checkAndExecuteRouteCmd(
tap_default_cmd,
['ip', 'route', 'show', ipv4],
[ipv4, interface], False)
self._checkAndExecuteRouteCmd(
tap_route_cmd,
['ip', 'route', 'show', ipv4],
[ipv4, gateway_ip], True)
elif tap_ip:
tap_route_cmd = ['ip', 'route', 'del', tap_ip, 'dev', interface]
self._checkAndExecuteRouteCmd(
tap_route_cmd,
['ip', 'route', 'show', tap_ip],
[tap_ip, interface], True)
os.remove(saved_request_file)
def _updateSlapTapRoute(self, partition_id, ipv4, iface, hosting_ip_list, check_remove=False):
"""
This is used to update route to tap interface in case a instance(vm) is moved to
another computer. Then we add routes to reach the moved instance.
"""
instance_path = os.path.join(self.instance_root, partition_id)
filename = COMPUTER_PARTITION_UPDATE_TAP_ROUTE % partition_id
request_file = os.path.join(instance_path, filename)
saved_request_file = os.path.join(
instance_path, '.slapos-request-update-route')
if os.path.exists(request_file) and not check_remove:
self.logger.debug("File %s found. Configure custom ip routes..." % filename)
else:
return self._restoreSlapTapRoute(partition_id, ipv4)
config_request = ConfigParser.ConfigParser()
try:
config_request.readfp(open(request_file))
except ConfigParser.MissingSectionHeaderError:
self.logger.error("%s: Invalid file specified." % request_file)
raise
route_section = '%s-routes' % partition_id
if not route_section in config_request.sections():
self.logger.debug('Section %s is missing, skiping file %s.' % (
route_section, filename))
return
option_list = config_request.options(route_section)
interface = config_request.get(route_section, 'interface')
if iface != interface:
raise ValueError("Cannot update ip route on unallowed or invalid interface: %s" % interface)
gateway_ip = tap_ip = ''
if 'forward-to-ip' in option_list:
gateway_ip = config_request.get(route_section, 'forward-to-ip')
if not valid_ipv4(gateway_ip):
raise ValueError("Invalid or unallowed IPv4 specified: %s" % gateway_ip)
if 'ip-to-interface' in option_list:
tap_ip = config_request.get(route_section, 'ip-to-interface')
if not tap_ip in hosting_ip_list:
raise ValueError("Invalid or unallowed IPv4 specified: %s" % tap_ip)
# save requested file
shutil.copy(request_file, saved_request_file)
if gateway_ip:
# Forward route from interface to another ip
result = self._checkIpAddressOnIfaces(gateway_ip)
if result is not None:
self.logger.debug("IP address %s found on interface %s, ip route will " \
"not be added!" % (gateway_ip, result[0]))
return
_, default_iface = self._getDefaultNetworkInterface()
tap_route_cmd = ['route', 'add', '-host', ipv4, 'gw', gateway_ip]
tap_default_cmd = ['ip', 'route', 'del', ipv4, 'dev', interface]
self._checkAndExecuteRouteCmd(
['route', 'add', '-host', gateway_ip, 'dev', default_iface],
['ip', 'route', 'show', gateway_ip],
[gateway_ip, default_iface])
# Remove current route to slaptap
self._checkAndExecuteRouteCmd(
tap_default_cmd,
['ip', 'route', 'show', ipv4],
[ipv4, interface], True)
# Add route to new gateway
self._checkAndExecuteRouteCmd(
tap_route_cmd,
['ip', 'route', 'show', ipv4],
[ipv4, gateway_ip], False)
elif tap_ip:
# add new route to tap interface
tap_route_cmd = ['route', 'add', '-host', tap_ip, 'dev', interface]
self._checkAndExecuteRouteCmd(
tap_route_cmd,
['ip', 'route', 'show', tap_ip],
[tap_ip, interface], False)
if 'ip-to-interface-dnat' in option_list:
set_dnat = config_request.get(route_section, 'ip-to-interface-dnat')
if set_dnat in ['True', 'true', 'yes', '1']:
# Add firewall rule to forward to another ip
command = '--permanent --direct --add-rule ipv4 nat '
command += 'PREROUTING 800 -d %s -j DNAT --to-destination %s' % (
ipv4, tap_ip)
return [command]
def _setupComputerPartitionFirewall(self, computer_partition, ip_list, drop_entries=False): def _setupComputerPartitionFirewall(self, computer_partition, ip_list, drop_entries=False):
""" """
Using linux iptables, limit access to IP of this partition to all Using linux iptables, limit access to IP of this partition to all
...@@ -869,10 +1042,10 @@ stderr_logfile_backups=1 ...@@ -869,10 +1042,10 @@ stderr_logfile_backups=1
""" """
ipv4_list = [] ipv4_list = []
ipv6_list = [] ipv6_list = []
tap_interface = ''
tap_route_ipv4 = ''
source_ipv4_list = [] source_ipv4_list = []
source_ipv6_list = []
hosting_ipv4_list = [] hosting_ipv4_list = []
hosting_ipv6_list = []
getFirewallRules = getattr(self, '_getFirewallAcceptRules') getFirewallRules = getattr(self, '_getFirewallAcceptRules')
if not drop_entries: if not drop_entries:
...@@ -886,19 +1059,16 @@ stderr_logfile_backups=1 ...@@ -886,19 +1059,16 @@ stderr_logfile_backups=1
iface, ip = (net_ip[0], net_ip[1]) iface, ip = (net_ip[0], net_ip[1])
if not iface.startswith('route_'): if not iface.startswith('route_'):
continue continue
tap_interface = iface.lstrip('route_')
tap_route_ipv4 = ip
if valid_ipv4(ip): if valid_ipv4(ip):
ipv4_list.append(ip) ipv4_list.append(ip)
elif valid_ipv6(ip):
ipv6_list.append(ip)
hosting_ip_list = computer_partition.getFullHostingIpAddressList() hosting_ip_list = computer_partition.getFullHostingIpAddressList()
for iface, ip in hosting_ip_list: for iface, ip in hosting_ip_list:
if valid_ipv4(ip): if valid_ipv4(ip):
if not ip in ipv4_list: if not ip in ipv4_list:
hosting_ipv4_list.append(ip) hosting_ipv4_list.append(ip)
elif valid_ipv6(ip):
if not ip in ipv6_list:
hosting_ipv6_list.append(ip)
filter_dict = getattr(computer_partition, '_filter_dict', None) filter_dict = getattr(computer_partition, '_filter_dict', None)
extra_list = [] extra_list = []
...@@ -916,10 +1086,17 @@ stderr_logfile_backups=1 ...@@ -916,10 +1086,17 @@ stderr_logfile_backups=1
source_ipv4_list = self._getValidIpv4FromList(extra_list, True) source_ipv4_list = self._getValidIpv4FromList(extra_list, True)
hosting_ipv4_list.extend(self._getValidIpv4FromList(accept_ip_list, True)) hosting_ipv4_list.extend(self._getValidIpv4FromList(accept_ip_list, True))
# XXX - ipv6_list and source_ipv6_list ignored for the moment # In case route need to update route of instance
result_list = self._updateSlapTapRoute(computer_partition.getId(),
tap_route_ipv4,
tap_interface,
hosting_ipv4_list,
drop_entries)
for ip in ipv4_list: for ip in ipv4_list:
cmd_list = getFirewallRules(ip, hosting_ipv4_list, cmd_list = getFirewallRules(ip, hosting_ipv4_list,
source_ipv4_list, ip_type='ipv4') source_ipv4_list, ip_type='ipv4')
if ip == tap_route_ipv4 and result_list is not None:
cmd_list.extend(result_list)
self._checkAddFirewallRules(computer_partition.getId(), self._checkAddFirewallRules(computer_partition.getId(),
cmd_list, add=add_rules) cmd_list, add=add_rules)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment