1 # Copyright 2015 Red Hat, Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
19 from neutronclient.common import exceptions as nc_exc
20 from oslo_config import cfg
22 from neutron.agent.linux import utils
23 from neutron.common import utils as common_utils
24 from neutron.tests.common import net_helpers
25 from neutron.tests.fullstack.resources import config
26 from neutron.tests.fullstack.resources import process
29 class EnvironmentDescription(object):
30 """A set of characteristics of an environment setup.
32 Does the setup, as a whole, support tunneling? How about l2pop?
34 def __init__(self, network_type='vxlan', l2_pop=True, qos=False):
35 self.network_type = network_type
40 def tunneling_enabled(self):
41 return self.network_type in ('vxlan', 'gre')
44 class HostDescription(object):
45 """A set of characteristics of an environment Host.
47 What agents should the host spawn? What mode should each agent operate
50 def __init__(self, l3_agent=False, of_interface='ovs-ofctl'):
51 self.l3_agent = l3_agent
52 self.of_interface = of_interface
55 class Host(fixtures.Fixture):
56 """The Host class models a physical host running agents, all reporting with
59 OpenStack installers or administrators connect compute nodes to the
60 physical tenant network by connecting the provider bridges to their
61 respective physical NICs. Or, if using tunneling, by configuring an
62 IP address on the appropriate physical NIC. The Host class does the same
63 with the connect_* methods.
65 TODO(amuller): Add start/stop/restart methods that will start/stop/restart
66 all of the agents on this host. Add a kill method that stops all agents
67 and disconnects the host from other hosts.
70 def __init__(self, env_desc, host_desc,
71 test_name, neutron_config,
72 central_data_bridge, central_external_bridge):
73 self.env_desc = env_desc
74 self.host_desc = host_desc
75 self.test_name = test_name
76 self.neutron_config = neutron_config
77 # Use reserved class E addresses
78 self.local_ip = self.get_random_ip('240.0.0.1', '255.255.255.254')
79 self.central_data_bridge = central_data_bridge
80 self.central_external_bridge = central_external_bridge
84 agent_cfg_fixture = config.OVSConfigFixture(
85 self.env_desc, self.host_desc, self.neutron_config.temp_dir,
87 self.useFixture(agent_cfg_fixture)
89 if self.env_desc.tunneling_enabled:
91 net_helpers.OVSBridgeFixture(
92 agent_cfg_fixture.get_br_tun_name())).bridge
93 self.connect_to_internal_network_via_tunneling()
95 br_phys = self.useFixture(
96 net_helpers.OVSBridgeFixture(
97 agent_cfg_fixture.get_br_phys_name())).bridge
98 self.connect_to_internal_network_via_vlans(br_phys)
100 self.ovs_agent = self.useFixture(
101 process.OVSAgentFixture(
102 self.env_desc, self.host_desc,
103 self.test_name, self.neutron_config, agent_cfg_fixture))
105 if self.host_desc.l3_agent:
106 l3_agent_cfg_fixture = self.useFixture(
107 config.L3ConfigFixture(
108 self.env_desc, self.host_desc,
109 self.neutron_config.temp_dir,
110 self.ovs_agent.agent_cfg_fixture.get_br_int_name()))
111 br_ex = self.useFixture(
112 net_helpers.OVSBridgeFixture(
113 l3_agent_cfg_fixture.get_external_bridge())).bridge
114 self.connect_to_external_network(br_ex)
115 self.l3_agent = self.useFixture(
116 process.L3AgentFixture(
117 self.env_desc, self.host_desc,
120 l3_agent_cfg_fixture))
122 def connect_to_internal_network_via_tunneling(self):
123 veth_1, veth_2 = self.useFixture(
124 net_helpers.VethFixture()).ports
126 # NOTE: This sets an IP address on the host's root namespace
127 # which is cleaned up when the device is deleted.
128 veth_1.addr.add(common_utils.ip_to_cidr(self.local_ip, 32))
133 def connect_to_internal_network_via_vlans(self, host_data_bridge):
134 # If using VLANs as a segmentation device, it's needed to connect
135 # a provider bridge to a centralized, shared bridge.
136 net_helpers.create_patch_ports(
137 self.central_data_bridge, host_data_bridge)
139 def connect_to_external_network(self, host_external_bridge):
140 net_helpers.create_patch_ports(
141 self.central_external_bridge, host_external_bridge)
144 def get_random_ip(low, high):
145 parent_range = netaddr.IPRange(low, high)
146 return str(random.choice(parent_range))
150 return self.neutron_config.config.DEFAULT.host
154 return self.agents['l3']
157 def l3_agent(self, agent):
158 self.agents['l3'] = agent
162 return self.agents['ovs']
165 def ovs_agent(self, agent):
166 self.agents['ovs'] = agent
169 class Environment(fixtures.Fixture):
170 """Represents a deployment topology.
172 Environment is a collection of hosts. It starts a Neutron server
173 and a parametrized number of Hosts, each a collection of agents.
174 The Environment accepts a collection of HostDescription, each describing
175 the type of Host to create.
178 def __init__(self, env_desc, hosts_desc):
180 :param env_desc: An EnvironmentDescription instance.
181 :param hosts_desc: A list of HostDescription instances.
184 super(Environment, self).__init__()
185 self.env_desc = env_desc
186 self.hosts_desc = hosts_desc
189 def wait_until_env_is_up(self):
190 utils.wait_until_true(self._processes_are_ready)
192 def _processes_are_ready(self):
194 running_agents = self.neutron_server.client.list_agents()['agents']
195 agents_count = sum(len(host.agents) for host in self.hosts)
196 return len(running_agents) == agents_count
197 except nc_exc.NeutronClientException:
200 def _create_host(self, host_desc):
201 temp_dir = self.useFixture(fixtures.TempDir()).path
202 neutron_config = config.NeutronConfigFixture(
203 self.env_desc, host_desc, temp_dir,
204 cfg.CONF.database.connection, self.rabbitmq_environment)
205 self.useFixture(neutron_config)
207 return self.useFixture(
212 self.central_data_bridge,
213 self.central_external_bridge))
216 self.temp_dir = self.useFixture(fixtures.TempDir()).path
218 self.rabbitmq_environment = self.useFixture(
219 process.RabbitmqEnvironmentFixture())
221 plugin_cfg_fixture = self.useFixture(
222 config.ML2ConfigFixture(
223 self.env_desc, None, self.temp_dir,
224 self.env_desc.network_type))
225 neutron_cfg_fixture = self.useFixture(
226 config.NeutronConfigFixture(
227 self.env_desc, None, self.temp_dir,
228 cfg.CONF.database.connection, self.rabbitmq_environment))
229 self.neutron_server = self.useFixture(
230 process.NeutronServerFixture(
232 self.test_name, neutron_cfg_fixture, plugin_cfg_fixture))
234 self.central_data_bridge = self.useFixture(
235 net_helpers.OVSBridgeFixture('cnt-data')).bridge
236 self.central_external_bridge = self.useFixture(
237 net_helpers.OVSBridgeFixture('cnt-ex')).bridge
239 self.hosts = [self._create_host(desc) for desc in self.hosts_desc]
241 self.wait_until_env_is_up()