Exemple #1
0
 def test_get_network_interface_file(self):
     dir = '/etc/network/interfaces.d'
     file = '/etc/network/interfaces'
     interface = 'eth0'
     cfg.CONF.set_override('agent_server_network_dir', dir,
                           group='amphora_agent')
     path = util.get_network_interface_file(interface)
     expected_path = os.path.join(dir, interface + '.cfg')
     self.assertEqual(expected_path, path)
     cfg.CONF.set_override('agent_server_network_file', file,
                           group='amphora_agent')
     path = util.get_network_interface_file(interface)
     self.assertEqual(file, path)
Exemple #2
0
    def test_get_network_interface_file(self):
        interface = 'eth0'

        self.conf.config(group="amphora_agent",
                         agent_server_network_file=None)
        path = util.get_network_interface_file(interface)
        expected_path = os.path.join(self.dir, interface + '.cfg')
        self.assertEqual(expected_path, path)

        self.conf.config(group="amphora_agent",
                         agent_server_network_file=self.file)
        path = util.get_network_interface_file(interface)
        self.assertEqual(self.file, path)
Exemple #3
0
 def test_get_network_interface_file(self):
     dir = '/etc/network/interfaces.d'
     file = '/etc/network/interfaces'
     interface = 'eth0'
     cfg.CONF.set_override('agent_server_network_dir',
                           dir,
                           group='amphora_agent')
     path = util.get_network_interface_file(interface)
     expected_path = os.path.join(dir, interface + '.cfg')
     self.assertEqual(expected_path, path)
     cfg.CONF.set_override('agent_server_network_file',
                           file,
                           group='amphora_agent')
     path = util.get_network_interface_file(interface)
     self.assertEqual(file, path)
Exemple #4
0
def plug_network(mac_address):
    interface = _interface_by_mac(mac_address)

    # write interface file
    with open(util.get_network_interface_file(interface), 'w') as text_file:
        text = template_port.render(interface=interface)
        text_file.write(text)

    _bring_if_down(interface)
    _bring_if_up(interface, 'network')

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="Plugged on interface {interface}".format(
            interface=interface))), 202)
Exemple #5
0
def plug_network(mac_address):
    interface = _interface_by_mac(mac_address)

    # write interface file
    with open(util.get_network_interface_file(interface), 'w') as text_file:
        text = template_port.render(interface=interface)
        text_file.write(text)

    _bring_if_down(interface)
    _bring_if_up(interface, 'network')

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="Plugged on interface {interface}".format(
            interface=interface))), 202)
Exemple #6
0
def plug_network(mac_address):
    # This is the interface as it was initially plugged into the
    # default network namespace, this will likely always be eth1
    default_netns_interface = _interface_by_mac(mac_address)

    # We need to determine the interface name when inside the namespace
    # to avoid name conflicts
    with pyroute2.NetNS(consts.AMPHORA_NAMESPACE, flags=os.O_CREAT) as netns:

        # 1 means just loopback, but we should already have a VIP
        # This works for the add/delete/add case as we don't delete interfaces
        # Note, eth0 is skipped because that is the VIP interface
        netns_interface = 'eth{0}'.format(len(netns.get_links()))

    LOG.info(_LI('Plugged interface {0} will become {1} in the '
                 'namespace {2}').format(default_netns_interface,
                                         netns_interface,
                                         consts.AMPHORA_NAMESPACE))
    interface_file_path = util.get_network_interface_file(netns_interface)

    # write interface file
    flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
    # mode 00644
    mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH

    with os.fdopen(os.open(interface_file_path, flags, mode),
                   'w') as text_file:
        text = template_port.render(interface=netns_interface)
        text_file.write(text)

    # Update the list of interfaces to add to the namespace
    _update_plugged_interfaces_file(netns_interface, mac_address)

    with pyroute2.IPRoute() as ipr:
        # Move the interfaces into the namespace
        idx = ipr.link_lookup(ifname=default_netns_interface)[0]
        ipr.link('set', index=idx,
                 net_ns_fd=consts.AMPHORA_NAMESPACE,
                 IFLA_IFNAME=netns_interface)

    _bring_if_down(netns_interface)
    _bring_if_up(netns_interface, 'network')

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="Plugged on interface {interface}".format(
            interface=netns_interface))), 202)
Exemple #7
0
def plug_vip(vip, subnet_cidr, gateway, mac_address):
    # validate vip
    try:
        socket.inet_aton(vip)
    except socket.error:
        return flask.make_response(flask.jsonify(dict(
            message="Invalid VIP")), 400)

    interface = _interface_by_mac(mac_address)

    # assume for now only a fixed subnet size
    sections = vip.split('.')[:3]
    sections.append('255')
    broadcast = '.'.join(sections)

    # write interface file
    with open(util.get_network_interface_file(interface), 'w') as text_file:
        text = template_vip.render(
            interface=interface,
            vip=vip,
            broadcast=broadcast,
            # assume for now only a fixed subnet size
            netmask='255.255.255.0')
        text_file.write(text)

    # bring interfaces up
    _bring_if_down("{interface}".format(interface=interface))
    _bring_if_down("{interface}:0".format(interface=interface))
    _bring_if_up("{interface}".format(interface=interface), 'VIP')
    _bring_if_up("{interface}:0".format(interface=interface), 'VIP')

    # Setup policy based routes for the amphora

    ip = pyroute2.IPRoute()

    cidr_split = subnet_cidr.split('/')

    num_interface = ip.link_lookup(ifname=interface)

    ip.route('add',
             dst=cidr_split[0],
             mask=int(cidr_split[1]),
             oif=num_interface,
             table=1,
             rtproto='RTPROT_BOOT',
             rtscope='RT_SCOPE_LINK')

    ip.route('add',
             dst='0.0.0.0',
             gateway=gateway,
             oif=num_interface,
             table=1,
             rtproto='RTPROT_BOOT')

    ip.rule('add',
            table=1,
            action='FR_ACT_TO_TBL',
            src=cidr_split[0],
            src_len=int(cidr_split[1]))

    ip.rule('add',
            table=1,
            action='FR_ACT_TO_TBL',
            dst=cidr_split[0],
            dst_len=int(cidr_split[1]))

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="VIP {vip} plugged on interface {interface}".format(
            vip=vip, interface=interface))), 202)
Exemple #8
0
    def plug_vip(self, vip, subnet_cidr, gateway,
                 mac_address, mtu=None, vrrp_ip=None, host_routes=None):
        # Validate vip and subnet_cidr, calculate broadcast address and netmask
        try:
            render_host_routes = []
            ip = ipaddress.ip_address(
                vip if six.text_type == type(vip) else six.u(vip))
            network = ipaddress.ip_network(
                subnet_cidr if six.text_type == type(subnet_cidr)
                else six.u(subnet_cidr))
            vip = ip.exploded
            broadcast = network.broadcast_address.exploded
            netmask = (network.prefixlen if ip.version is 6
                       else network.netmask.exploded)
            vrrp_version = None
            if vrrp_ip:
                vrrp_ip_obj = ipaddress.ip_address(
                    vrrp_ip if six.text_type == type(vrrp_ip)
                    else six.u(vrrp_ip)
                )
                vrrp_version = vrrp_ip_obj.version
            if host_routes:
                for hr in host_routes:
                    network = ipaddress.ip_network(
                        hr['destination'] if isinstance(
                            hr['destination'], six.text_type) else
                        six.u(hr['destination']))
                    render_host_routes.append({'network': network,
                                               'gw': hr['nexthop']})
        except ValueError:
            return flask.make_response(flask.jsonify(dict(
                message="Invalid VIP")), 400)

        # Check if the interface is already in the network namespace
        # Do not attempt to re-plug the VIP if it is already in the
        # network namespace
        if self._netns_interface_exists(mac_address):
            return flask.make_response(flask.jsonify(dict(
                message="Interface already exists")), 409)

        # This is the interface prior to moving into the netns
        default_netns_interface = self._interface_by_mac(mac_address)

        # Always put the VIP interface as eth1
        primary_interface = consts.NETNS_PRIMARY_INTERFACE
        secondary_interface = "{interface}:0".format(
            interface=primary_interface)

        # We need to setup the netns network directory so that the ifup
        # commands used here and in the startup scripts "sees" the right
        # interfaces and scripts.
        interface_file_path = util.get_network_interface_file(
            primary_interface)
        os.makedirs('/etc/netns/' + consts.AMPHORA_NAMESPACE)
        shutil.copytree(
            '/etc/network',
            '/etc/netns/{}/network'.format(consts.AMPHORA_NAMESPACE),
            symlinks=True,
            ignore=shutil.ignore_patterns('eth0*', 'openssh*'))
        name = '/etc/netns/{}/network/interfaces'.format(
            consts.AMPHORA_NAMESPACE)
        flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
        # mode 00644
        mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
        with os.fdopen(os.open(name, flags, mode), 'w') as int_file:
            int_file.write('auto lo\n')
            int_file.write('iface lo inet loopback\n')
            if not CONF.amphora_agent.agent_server_network_file:
                int_file.write('source /etc/netns/{}/network/'
                               'interfaces.d/*.cfg\n'.format(
                                   consts.AMPHORA_NAMESPACE))

        # write interface file

        mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH

        # If we are using a consolidated interfaces file, just append
        # otherwise clear the per interface file as we are rewriting it
        # TODO(johnsom): We need a way to clean out old interfaces records
        if CONF.amphora_agent.agent_server_network_file:
            flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND
        else:
            flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC

        with os.fdopen(os.open(interface_file_path, flags, mode),
                       'w') as text_file:
            text = template_vip.render(
                interface=primary_interface,
                vip=vip,
                vip_ipv6=ip.version is 6,
                broadcast=broadcast,
                netmask=netmask,
                gateway=gateway,
                mtu=mtu,
                vrrp_ip=vrrp_ip,
                vrrp_ipv6=vrrp_version is 6,
                host_routes=render_host_routes,
            )
            text_file.write(text)

        # Update the list of interfaces to add to the namespace
        # This is used in the amphora reboot case to re-establish the namespace
        self._update_plugged_interfaces_file(primary_interface, mac_address)

        # Create the namespace
        netns = pyroute2.NetNS(consts.AMPHORA_NAMESPACE, flags=os.O_CREAT)
        netns.close()

        # Load sysctl in new namespace
        sysctl = pyroute2.NSPopen(consts.AMPHORA_NAMESPACE,
                                  [consts.SYSCTL_CMD, '--system'],
                                  stdout=subprocess.PIPE)
        sysctl.communicate()
        sysctl.wait()
        sysctl.release()

        with pyroute2.IPRoute() as ipr:
            # Move the interfaces into the namespace
            idx = ipr.link_lookup(ifname=default_netns_interface)[0]
        ipr.link('set', index=idx, net_ns_fd=consts.AMPHORA_NAMESPACE,
                 IFLA_IFNAME=primary_interface)

        # bring interfaces up
        self._bring_if_down(primary_interface)
        self._bring_if_down(secondary_interface)
        self._bring_if_up(primary_interface, 'VIP')
        self._bring_if_up(secondary_interface, 'VIP')

        return flask.make_response(flask.jsonify(dict(
            message="OK",
            details="VIP {vip} plugged on interface {interface}".format(
                vip=vip, interface=primary_interface))), 202)
Exemple #9
0
    def plug_network(self, mac_address, fixed_ips, mtu=None):
        # Check if the interface is already in the network namespace
        # Do not attempt to re-plug the network if it is already in the
        # network namespace
        if self._netns_interface_exists(mac_address):
            return flask.make_response(flask.jsonify(dict(
                message="Interface already exists")), 409)

        # This is the interface as it was initially plugged into the
        # default network namespace, this will likely always be eth1

        try:
            self._check_ip_addresses(fixed_ips=fixed_ips)
        except socket.error:
            return flask.make_response(flask.jsonify(dict(
                message="Invalid network port")), 400)

        default_netns_interface = self._interface_by_mac(mac_address)

        # We need to determine the interface name when inside the namespace
        # to avoid name conflicts
        with pyroute2.NetNS(consts.AMPHORA_NAMESPACE,
                            flags=os.O_CREAT) as netns:

            # 1 means just loopback, but we should already have a VIP. This
            # works for the add/delete/add case as we don't delete interfaces
            # Note, eth0 is skipped because that is the VIP interface
            netns_interface = 'eth{0}'.format(len(netns.get_links()))

        LOG.info(_LI('Plugged interface {0} will become {1} in the '
                     'namespace {2}').format(default_netns_interface,
                                             netns_interface,
                                             consts.AMPHORA_NAMESPACE))
        interface_file_path = util.get_network_interface_file(netns_interface)

        # write interface file

        # If we are using a consolidated interfaces file, just append
        # otherwise clear the per interface file as we are rewriting it
        # TODO(johnsom): We need a way to clean out old interfaces records
        if CONF.amphora_agent.agent_server_network_file:
            flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND
        else:
            flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC

        # mode 00644
        mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH

        with os.fdopen(os.open(interface_file_path, flags, mode),
                       'w') as text_file:
            text = self._generate_network_file_text(netns_interface,
                                                    fixed_ips,
                                                    mtu)
            text_file.write(text)

        # Update the list of interfaces to add to the namespace
        self._update_plugged_interfaces_file(netns_interface, mac_address)

        with pyroute2.IPRoute() as ipr:
            # Move the interfaces into the namespace
            idx = ipr.link_lookup(ifname=default_netns_interface)[0]
            ipr.link('set', index=idx,
                     net_ns_fd=consts.AMPHORA_NAMESPACE,
                     IFLA_IFNAME=netns_interface)

        self._bring_if_down(netns_interface)
        self._bring_if_up(netns_interface, 'network')

        return flask.make_response(flask.jsonify(dict(
            message="OK",
            details="Plugged on interface {interface}".format(
                interface=netns_interface))), 202)
Exemple #10
0
def plug_vip(vip, subnet_cidr, gateway, mac_address):
    # validate vip
    try:
        socket.inet_aton(vip)
    except socket.error:
        return flask.make_response(flask.jsonify(dict(
            message="Invalid VIP")), 400)

    interface = _interface_by_mac(mac_address)

    # assume for now only a fixed subnet size
    sections = vip.split('.')[:3]
    sections.append('255')
    broadcast = '.'.join(sections)

    # write interface file
    with open(util.get_network_interface_file(interface), 'w') as text_file:
        text = template_vip.render(
            interface=interface,
            vip=vip,
            broadcast=broadcast,
            # assume for now only a fixed subnet size
            netmask='255.255.255.0')
        text_file.write(text)

    # bring interfaces up
    _bring_if_down("{interface}".format(interface=interface))
    _bring_if_down("{interface}:0".format(interface=interface))
    _bring_if_up("{interface}".format(interface=interface), 'VIP')
    _bring_if_up("{interface}:0".format(interface=interface), 'VIP')

    # Setup policy based routes for the amphora

    ip = pyroute2.IPRoute()

    cidr_split = subnet_cidr.split('/')

    num_interface = ip.link_lookup(ifname=interface)

    ip.route('add',
             dst=cidr_split[0],
             mask=int(cidr_split[1]),
             oif=num_interface,
             table=1,
             rtproto='RTPROT_BOOT',
             rtscope='RT_SCOPE_LINK')

    ip.route('add',
             dst='0.0.0.0',
             gateway=gateway,
             oif=num_interface,
             table=1,
             rtproto='RTPROT_BOOT')

    ip.rule('add',
            table=1,
            action='FR_ACT_TO_TBL',
            src=cidr_split[0],
            src_len=int(cidr_split[1]))

    ip.rule('add',
            table=1,
            action='FR_ACT_TO_TBL',
            dst=cidr_split[0],
            dst_len=int(cidr_split[1]))

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="VIP {vip} plugged on interface {interface}".format(
            vip=vip, interface=interface))), 202)
Exemple #11
0
def plug_vip(vip, subnet_cidr, gateway, mac_address):
    # validate vip
    try:
        socket.inet_aton(vip)
    except socket.error:
        return flask.make_response(flask.jsonify(dict(
            message="Invalid VIP")), 400)

    interface = _interface_by_mac(mac_address)
    primary_interface = "{interface}".format(interface=interface)
    secondary_interface = "{interface}:0".format(interface=interface)

    # assume for now only a fixed subnet size
    sections = vip.split('.')[:3]
    sections.append('255')
    broadcast = '.'.join(sections)

    # We need to setup the netns network directory so that the ifup
    # commands used here and in the startup scripts "sees" the right
    # interfaces and scripts.
    interface_file_path = util.get_network_interface_file(interface)
    os.makedirs('/etc/netns/' + consts.AMPHORA_NAMESPACE)
    shutil.copytree('/etc/network',
                    '/etc/netns/{}/network'.format(consts.AMPHORA_NAMESPACE),
                    symlinks=True,
                    ignore=shutil.ignore_patterns('eth0*', 'openssh*'))
    name = '/etc/netns/{}/network/interfaces'.format(consts.AMPHORA_NAMESPACE)
    flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
    # mode 00644
    mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
    with os.fdopen(os.open(name, flags, mode), 'w') as file:
        file.write('auto lo\n')
        file.write('iface lo inet loopback\n')
        file.write('source /etc/netns/{}/network/interfaces.d/*.cfg\n'.format(
            consts.AMPHORA_NAMESPACE))

    # write interface file
    mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
    flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC

    with os.fdopen(os.open(interface_file_path, flags, mode),
                   'w') as text_file:
        text = template_vip.render(
            interface=interface,
            vip=vip,
            broadcast=broadcast,
            # assume for now only a fixed subnet size
            netmask='255.255.255.0')
        text_file.write(text)

    # Update the list of interfaces to add to the namespace
    # This is used in the amphora reboot case to re-establish the namespace
    _update_plugged_interfaces_file(interface, mac_address)

    # Create the namespace
    netns = pyroute2.NetNS(consts.AMPHORA_NAMESPACE, flags=os.O_CREAT)
    netns.close()

    with pyroute2.IPRoute() as ipr:
        # Move the interfaces into the namespace
        idx = ipr.link_lookup(ifname=primary_interface)[0]
        ipr.link('set', index=idx, net_ns_fd=consts.AMPHORA_NAMESPACE)

    # bring interfaces up
    _bring_if_down(primary_interface)
    _bring_if_down(secondary_interface)
    _bring_if_up(primary_interface, 'VIP')
    _bring_if_up(secondary_interface, 'VIP')

    return flask.make_response(flask.jsonify(dict(
        message="OK",
        details="VIP {vip} plugged on interface {interface}".format(
            vip=vip, interface=interface))), 202)