# Copyright (c) 2015 Thales Services SAS # # Licensed 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 functools import fixtures from neutron.agent.linux import ip_lib from neutron.common import utils from neutron.tests.common import net_helpers class FakeMachineException(Exception): pass class FakeMachineBase(fixtures.Fixture): """Create a fake machine. :ivar bridge: bridge on which the fake machine is bound :ivar ip_cidr: fake machine ip_cidr :type ip_cidr: str :ivar ip: fake machine ip :type ip: str :ivar gateway_ip: fake machine gateway ip :type gateway_ip: str :ivar namespace: namespace emulating the machine :type namespace: str :ivar port: port binding the namespace to the bridge :type port: IPDevice """ def __init__(self): self.port = None def _setUp(self): ns_fixture = self.useFixture( net_helpers.NamespaceFixture()) self.namespace = ns_fixture.name def execute(self, *args, **kwargs): ns_ip_wrapper = ip_lib.IPWrapper(self.namespace) return ns_ip_wrapper.netns.execute(*args, **kwargs) def ping_predicate(self, dst_ip): try: self.assert_ping(dst_ip) except RuntimeError: return False return True def block_until_ping(self, dst_ip): predicate = functools.partial(self.ping_predicate, dst_ip) utils.wait_until_true( predicate, exception=FakeMachineException( "No ICMP reply obtained from IP address %s" % dst_ip) ) def block_until_no_ping(self, dst_ip): predicate = functools.partial( lambda ip: not self.ping_predicate(ip), dst_ip) utils.wait_until_true( predicate, exception=FakeMachineException( "ICMP packets still pass to %s IP address." % dst_ip) ) def assert_ping(self, dst_ip): net_helpers.assert_ping(self.namespace, dst_ip) def assert_no_ping(self, dst_ip): net_helpers.assert_no_ping(self.namespace, dst_ip) @property def ip(self): raise NotImplementedError() @property def ip_cidr(self): raise NotImplementedError() @property def mac_address(self): return self.port.link.address class FakeMachine(FakeMachineBase): def __init__(self, bridge, ip_cidr, gateway_ip=None, ipv6_cidr=None): super(FakeMachine, self).__init__() self.bridge = bridge self._ip_cidr = ip_cidr self._ipv6_cidr = ipv6_cidr self.gateway_ip = gateway_ip def _setUp(self): super(FakeMachine, self)._setUp() self.port = self.useFixture( net_helpers.PortFixture.get(self.bridge, self.namespace)).port self.port.addr.add(self._ip_cidr) if self.gateway_ip: net_helpers.set_namespace_gateway(self.port, self.gateway_ip) @property def ip(self): return self._ip_cidr.partition('/')[0] @property def ip_cidr(self): return self._ip_cidr @ip_cidr.setter def ip_cidr(self, ip_cidr): self.port.addr.add(ip_cidr) self.port.addr.delete(self._ip_cidr) self._ip_cidr = ip_cidr @property def ipv6(self): return self._ipv6_cidr.partition('/')[0] @property def ipv6_cidr(self): return self._ipv6_cidr @ipv6_cidr.setter def ipv6_cidr(self, ipv6_cidr): if self._ipv6_cidr: self.port.addr.delete(self._ipv6_cidr) self.port.addr.add(ipv6_cidr) self._ipv6_cidr = ipv6_cidr @FakeMachineBase.mac_address.setter def mac_address(self, mac_address): self.port.link.set_down() self.port.link.set_address(mac_address) self.port.link.set_up() def set_default_gateway(self, default_gw): self.port.route.add_gateway(default_gw) class PeerMachines(fixtures.Fixture): """Create 'amount' peered machines on an ip_cidr. :ivar bridge: bridge on which peer machines are bound :ivar ip_cidr: ip_cidr on which peer machines have ips :type ip_cidr: str :ivar machines: fake machines :type machines: FakeMachine list """ CIDR = '192.168.0.1/24' def __init__(self, bridge, ip_cidr=None, gateway_ip=None, amount=2): super(PeerMachines, self).__init__() self.bridge = bridge self.ip_cidr = ip_cidr or self.CIDR self.gateway_ip = gateway_ip self.amount = amount def _setUp(self): self.machines = [] for index in range(self.amount): ip_cidr = net_helpers.increment_ip_cidr(self.ip_cidr, index) self.machines.append( self.useFixture( FakeMachine(self.bridge, ip_cidr, self.gateway_ip)))