1105e8c173052163f41f35a7e82598ed7b6075ea
[openstack-build/neutron-build.git] / neutron / tests / fullstack / resources / environment.py
1 # Copyright 2015 Red Hat, Inc.
2 #
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
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
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
13 #    under the License.
14
15 import random
16
17 import fixtures
18 import netaddr
19 from neutronclient.common import exceptions as nc_exc
20 from oslo_config import cfg
21
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
27
28
29 class EnvironmentDescription(object):
30     """A set of characteristics of an environment setup.
31
32     Does the setup, as a whole, support tunneling? How about l2pop?
33     """
34     def __init__(self, network_type='vxlan', l2_pop=True, qos=False):
35         self.network_type = network_type
36         self.l2_pop = l2_pop
37         self.qos = qos
38
39     @property
40     def tunneling_enabled(self):
41         return self.network_type in ('vxlan', 'gre')
42
43
44 class HostDescription(object):
45     """A set of characteristics of an environment Host.
46
47     What agents should the host spawn? What mode should each agent operate
48     under?
49     """
50     def __init__(self, l3_agent=False, of_interface='ovs-ofctl'):
51         self.l3_agent = l3_agent
52         self.of_interface = of_interface
53
54
55 class Host(fixtures.Fixture):
56     """The Host class models a physical host running agents, all reporting with
57     the same hostname.
58
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.
64
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.
68     """
69
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
81         self.agents = {}
82
83     def _setUp(self):
84         agent_cfg_fixture = config.OVSConfigFixture(
85             self.env_desc, self.host_desc, self.neutron_config.temp_dir,
86             self.local_ip)
87         self.useFixture(agent_cfg_fixture)
88
89         if self.env_desc.tunneling_enabled:
90             self.useFixture(
91                 net_helpers.OVSBridgeFixture(
92                     agent_cfg_fixture.get_br_tun_name())).bridge
93             self.connect_to_internal_network_via_tunneling()
94         else:
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)
99
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))
104
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,
118                     self.test_name,
119                     self.neutron_config,
120                     l3_agent_cfg_fixture))
121
122     def connect_to_internal_network_via_tunneling(self):
123         veth_1, veth_2 = self.useFixture(
124             net_helpers.VethFixture()).ports
125
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))
129
130         veth_1.link.set_up()
131         veth_2.link.set_up()
132
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)
138
139     def connect_to_external_network(self, host_external_bridge):
140         net_helpers.create_patch_ports(
141             self.central_external_bridge, host_external_bridge)
142
143     @staticmethod
144     def get_random_ip(low, high):
145         parent_range = netaddr.IPRange(low, high)
146         return str(random.choice(parent_range))
147
148     @property
149     def hostname(self):
150         return self.neutron_config.config.DEFAULT.host
151
152     @property
153     def l3_agent(self):
154         return self.agents['l3']
155
156     @l3_agent.setter
157     def l3_agent(self, agent):
158         self.agents['l3'] = agent
159
160     @property
161     def ovs_agent(self):
162         return self.agents['ovs']
163
164     @ovs_agent.setter
165     def ovs_agent(self, agent):
166         self.agents['ovs'] = agent
167
168
169 class Environment(fixtures.Fixture):
170     """Represents a deployment topology.
171
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.
176     """
177
178     def __init__(self, env_desc, hosts_desc):
179         """
180         :param env_desc: An EnvironmentDescription instance.
181         :param hosts_desc: A list of HostDescription instances.
182         """
183
184         super(Environment, self).__init__()
185         self.env_desc = env_desc
186         self.hosts_desc = hosts_desc
187         self.hosts = []
188
189     def wait_until_env_is_up(self):
190         utils.wait_until_true(self._processes_are_ready)
191
192     def _processes_are_ready(self):
193         try:
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:
198             return False
199
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)
206
207         return self.useFixture(
208             Host(self.env_desc,
209                  host_desc,
210                  self.test_name,
211                  neutron_config,
212                  self.central_data_bridge,
213                  self.central_external_bridge))
214
215     def _setUp(self):
216         self.temp_dir = self.useFixture(fixtures.TempDir()).path
217
218         self.rabbitmq_environment = self.useFixture(
219             process.RabbitmqEnvironmentFixture())
220
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(
231                 self.env_desc, None,
232                 self.test_name, neutron_cfg_fixture, plugin_cfg_fixture))
233
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
238
239         self.hosts = [self._create_host(desc) for desc in self.hosts_desc]
240
241         self.wait_until_env_is_up()