~ewanmellor/nova/xenapi

« back to all changes in this revision

Viewing changes to nova/tests/network_unittest.py

  • Committer: Ewan Mellor
  • Date: 2010-09-28 18:12:13 UTC
  • mfrom: (145.13.135 trunk)
  • Revision ID: ewan.mellor@citrix.com-20100928181213-rnit65ejj20hjvjo
Merged with trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import os
23
23
import logging
24
24
 
 
25
from nova import db
 
26
from nova import exception
25
27
from nova import flags
26
28
from nova import test
27
29
from nova import utils
28
30
from nova.auth import manager
29
 
from nova.network import model
30
 
from nova.network import service
31
 
from nova.network import vpn
32
 
from nova.network.exception import NoMoreAddresses
 
31
from nova.api.ec2 import context
33
32
 
34
33
FLAGS = flags.FLAGS
35
34
 
41
40
        # NOTE(vish): if you change these flags, make sure to change the
42
41
        #             flags in the corresponding section in nova-dhcpbridge
43
42
        self.flags(connection_type='fake',
44
 
                   fake_storage=True,
45
43
                   fake_network=True,
46
44
                   auth_driver='nova.auth.ldapdriver.FakeLdapDriver',
47
 
                   network_size=32)
 
45
                   network_size=16,
 
46
                   num_networks=5)
48
47
        logging.getLogger().setLevel(logging.DEBUG)
49
48
        self.manager = manager.AuthManager()
50
49
        self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
51
50
        self.projects = []
52
 
        self.projects.append(self.manager.create_project('netuser',
53
 
                                                         'netuser',
54
 
                                                         'netuser'))
55
 
        for i in range(0, 6):
 
51
        self.network = utils.import_object(FLAGS.network_manager)
 
52
        self.context = context.APIRequestContext(project=None, user=self.user)
 
53
        for i in range(5):
56
54
            name = 'project%s' % i
57
55
            self.projects.append(self.manager.create_project(name,
58
56
                                                             'netuser',
59
57
                                                             name))
60
 
            vpn.NetworkData.create(self.projects[i].id)
61
 
        self.service = service.VlanNetworkService()
 
58
            # create the necessary network data for the project
 
59
            self.network.set_network_host(self.context, self.projects[i].id)
 
60
        instance_ref = db.instance_create(None,
 
61
                                         {'mac_address': utils.generate_mac()})
 
62
        self.instance_id = instance_ref['id']
 
63
        instance_ref = db.instance_create(None,
 
64
                                         {'mac_address': utils.generate_mac()})
 
65
        self.instance2_id = instance_ref['id']
62
66
 
63
67
    def tearDown(self):  # pylint: disable-msg=C0103
64
68
        super(NetworkTestCase, self).tearDown()
 
69
        # TODO(termie): this should really be instantiating clean datastores
 
70
        #               in between runs, one failure kills all the tests
 
71
        db.instance_destroy(None, self.instance_id)
 
72
        db.instance_destroy(None, self.instance2_id)
65
73
        for project in self.projects:
66
74
            self.manager.delete_project(project)
67
75
        self.manager.delete_user(self.user)
68
76
 
69
 
    def test_public_network_allocation(self):
 
77
    def _create_address(self, project_num, instance_id=None):
 
78
        """Create an address in given project num"""
 
79
        if instance_id is None:
 
80
            instance_id = self.instance_id
 
81
        self.context.project = self.projects[project_num]
 
82
        return self.network.allocate_fixed_ip(self.context, instance_id)
 
83
 
 
84
    def test_public_network_association(self):
70
85
        """Makes sure that we can allocaate a public ip"""
 
86
        # TODO(vish): better way of adding floating ips
71
87
        pubnet = IPy.IP(flags.FLAGS.public_range)
72
 
        address = self.service.allocate_elastic_ip(self.user.id,
73
 
                                           self.projects[0].id)
74
 
        self.assertTrue(IPy.IP(address) in pubnet)
 
88
        address = str(pubnet[0])
 
89
        try:
 
90
            db.floating_ip_get_by_address(None, address)
 
91
        except exception.NotFound:
 
92
            db.floating_ip_create(None, {'address': address,
 
93
                                         'host': FLAGS.host})
 
94
        float_addr = self.network.allocate_floating_ip(self.context,
 
95
                                                       self.projects[0].id)
 
96
        fix_addr = self._create_address(0)
 
97
        self.assertEqual(float_addr, str(pubnet[0]))
 
98
        self.network.associate_floating_ip(self.context, float_addr, fix_addr)
 
99
        address = db.instance_get_floating_address(None, self.instance_id)
 
100
        self.assertEqual(address, float_addr)
 
101
        self.network.disassociate_floating_ip(self.context, float_addr)
 
102
        address = db.instance_get_floating_address(None, self.instance_id)
 
103
        self.assertEqual(address, None)
 
104
        self.network.deallocate_floating_ip(self.context, float_addr)
 
105
        self.network.deallocate_fixed_ip(self.context, fix_addr)
75
106
 
76
107
    def test_allocate_deallocate_fixed_ip(self):
77
108
        """Makes sure that we can allocate and deallocate a fixed ip"""
78
 
        result = self.service.allocate_fixed_ip(
79
 
                self.user.id, self.projects[0].id)
80
 
        address = result['private_dns_name']
81
 
        mac = result['mac_address']
82
 
        net = model.get_project_network(self.projects[0].id, "default")
83
 
        self.assertEqual(True, is_in_project(address, self.projects[0].id))
84
 
        hostname = "test-host"
85
 
        issue_ip(mac, address, hostname, net.bridge_name)
86
 
        self.service.deallocate_fixed_ip(address)
 
109
        address = self._create_address(0)
 
110
        self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
 
111
        lease_ip(address)
 
112
        self.network.deallocate_fixed_ip(self.context, address)
87
113
 
88
114
        # Doesn't go away until it's dhcp released
89
 
        self.assertEqual(True, is_in_project(address, self.projects[0].id))
 
115
        self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
90
116
 
91
 
        release_ip(mac, address, hostname, net.bridge_name)
92
 
        self.assertEqual(False, is_in_project(address, self.projects[0].id))
 
117
        release_ip(address)
 
118
        self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
93
119
 
94
120
    def test_side_effects(self):
95
121
        """Ensures allocating and releasing has no side effects"""
96
 
        hostname = "side-effect-host"
97
 
        result = self.service.allocate_fixed_ip(self.user.id,
98
 
                                                self.projects[0].id)
99
 
        mac = result['mac_address']
100
 
        address = result['private_dns_name']
101
 
        result = self.service.allocate_fixed_ip(self.user,
102
 
                                                self.projects[1].id)
103
 
        secondmac = result['mac_address']
104
 
        secondaddress = result['private_dns_name']
105
 
 
106
 
        net = model.get_project_network(self.projects[0].id, "default")
107
 
        secondnet = model.get_project_network(self.projects[1].id, "default")
108
 
 
109
 
        self.assertEqual(True, is_in_project(address, self.projects[0].id))
110
 
        self.assertEqual(True, is_in_project(secondaddress,
111
 
                                             self.projects[1].id))
112
 
        self.assertEqual(False, is_in_project(address, self.projects[1].id))
 
122
        address = self._create_address(0)
 
123
        address2 = self._create_address(1, self.instance2_id)
 
124
 
 
125
        self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
 
126
        self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
 
127
        self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
113
128
 
114
129
        # Addresses are allocated before they're issued
115
 
        issue_ip(mac, address, hostname, net.bridge_name)
116
 
        issue_ip(secondmac, secondaddress, hostname, secondnet.bridge_name)
 
130
        lease_ip(address)
 
131
        lease_ip(address2)
117
132
 
118
 
        self.service.deallocate_fixed_ip(address)
119
 
        release_ip(mac, address, hostname, net.bridge_name)
120
 
        self.assertEqual(False, is_in_project(address, self.projects[0].id))
 
133
        self.network.deallocate_fixed_ip(self.context, address)
 
134
        release_ip(address)
 
135
        self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
121
136
 
122
137
        # First address release shouldn't affect the second
123
 
        self.assertEqual(True, is_in_project(secondaddress,
124
 
                                             self.projects[1].id))
 
138
        self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
125
139
 
126
 
        self.service.deallocate_fixed_ip(secondaddress)
127
 
        release_ip(secondmac, secondaddress, hostname, secondnet.bridge_name)
128
 
        self.assertEqual(False, is_in_project(secondaddress,
129
 
                                              self.projects[1].id))
 
140
        self.network.deallocate_fixed_ip(self.context, address2)
 
141
        release_ip(address2)
 
142
        self.assertFalse(is_allocated_in_project(address2,
 
143
                                                 self.projects[1].id))
130
144
 
131
145
    def test_subnet_edge(self):
132
146
        """Makes sure that private ips don't overlap"""
133
 
        result = self.service.allocate_fixed_ip(self.user.id,
134
 
                                                       self.projects[0].id)
135
 
        firstaddress = result['private_dns_name']
136
 
        hostname = "toomany-hosts"
 
147
        first = self._create_address(0)
 
148
        lease_ip(first)
 
149
        instance_ids = []
137
150
        for i in range(1, 5):
138
 
            project_id = self.projects[i].id
139
 
            result = self.service.allocate_fixed_ip(
140
 
                    self.user, project_id)
141
 
            mac = result['mac_address']
142
 
            address = result['private_dns_name']
143
 
            result = self.service.allocate_fixed_ip(
144
 
                    self.user, project_id)
145
 
            mac2 = result['mac_address']
146
 
            address2 = result['private_dns_name']
147
 
            result = self.service.allocate_fixed_ip(
148
 
                   self.user, project_id)
149
 
            mac3 = result['mac_address']
150
 
            address3 = result['private_dns_name']
151
 
            net = model.get_project_network(project_id, "default")
152
 
            issue_ip(mac, address, hostname, net.bridge_name)
153
 
            issue_ip(mac2, address2, hostname, net.bridge_name)
154
 
            issue_ip(mac3, address3, hostname, net.bridge_name)
155
 
            self.assertEqual(False, is_in_project(address,
156
 
                                                  self.projects[0].id))
157
 
            self.assertEqual(False, is_in_project(address2,
158
 
                                                  self.projects[0].id))
159
 
            self.assertEqual(False, is_in_project(address3,
160
 
                                                  self.projects[0].id))
161
 
            self.service.deallocate_fixed_ip(address)
162
 
            self.service.deallocate_fixed_ip(address2)
163
 
            self.service.deallocate_fixed_ip(address3)
164
 
            release_ip(mac, address, hostname, net.bridge_name)
165
 
            release_ip(mac2, address2, hostname, net.bridge_name)
166
 
            release_ip(mac3, address3, hostname, net.bridge_name)
167
 
        net = model.get_project_network(self.projects[0].id, "default")
168
 
        self.service.deallocate_fixed_ip(firstaddress)
 
151
            mac = utils.generate_mac()
 
152
            instance_ref = db.instance_create(None,
 
153
                                              {'mac_address': mac})
 
154
            instance_ids.append(instance_ref['id'])
 
155
            address = self._create_address(i, instance_ref['id'])
 
156
            mac = utils.generate_mac()
 
157
            instance_ref = db.instance_create(None,
 
158
                                              {'mac_address': mac})
 
159
            instance_ids.append(instance_ref['id'])
 
160
            address2 = self._create_address(i, instance_ref['id'])
 
161
            mac = utils.generate_mac()
 
162
            instance_ref = db.instance_create(None,
 
163
                                              {'mac_address': mac})
 
164
            instance_ids.append(instance_ref['id'])
 
165
            address3 = self._create_address(i, instance_ref['id'])
 
166
            lease_ip(address)
 
167
            lease_ip(address2)
 
168
            lease_ip(address3)
 
169
            self.assertFalse(is_allocated_in_project(address,
 
170
                                                     self.projects[0].id))
 
171
            self.assertFalse(is_allocated_in_project(address2,
 
172
                                                     self.projects[0].id))
 
173
            self.assertFalse(is_allocated_in_project(address3,
 
174
                                                     self.projects[0].id))
 
175
            self.network.deallocate_fixed_ip(self.context, address)
 
176
            self.network.deallocate_fixed_ip(self.context, address2)
 
177
            self.network.deallocate_fixed_ip(self.context, address3)
 
178
            release_ip(address)
 
179
            release_ip(address2)
 
180
            release_ip(address3)
 
181
        for instance_id in instance_ids:
 
182
            db.instance_destroy(None, instance_id)
 
183
        release_ip(first)
 
184
        self.network.deallocate_fixed_ip(self.context, first)
169
185
 
170
186
    def test_vpn_ip_and_port_looks_valid(self):
171
187
        """Ensure the vpn ip and port are reasonable"""
172
188
        self.assert_(self.projects[0].vpn_ip)
173
 
        self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start_port)
174
 
        self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_end_port)
 
189
        self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start)
 
190
        self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_start +
 
191
                                                  FLAGS.num_networks)
175
192
 
176
 
    def test_too_many_vpns(self):
177
 
        """Ensure error is raised if we run out of vpn ports"""
178
 
        vpns = []
179
 
        for i in xrange(vpn.NetworkData.num_ports_for_ip(FLAGS.vpn_ip)):
180
 
            vpns.append(vpn.NetworkData.create("vpnuser%s" % i))
181
 
        self.assertRaises(vpn.NoMorePorts, vpn.NetworkData.create, "boom")
182
 
        for network_datum in vpns:
183
 
            network_datum.destroy()
 
193
    def test_too_many_networks(self):
 
194
        """Ensure error is raised if we run out of networks"""
 
195
        projects = []
 
196
        networks_left = FLAGS.num_networks - db.network_count(None)
 
197
        for i in range(networks_left):
 
198
            project = self.manager.create_project('many%s' % i, self.user)
 
199
            projects.append(project)
 
200
        self.assertRaises(db.NoMoreNetworks,
 
201
                          self.manager.create_project,
 
202
                          'boom',
 
203
                          self.user)
 
204
        for project in projects:
 
205
            self.manager.delete_project(project)
184
206
 
185
207
    def test_ips_are_reused(self):
186
208
        """Makes sure that ip addresses that are deallocated get reused"""
187
 
        net = model.get_project_network(self.projects[0].id, "default")
188
 
 
189
 
        hostname = "reuse-host"
190
 
        macs = {}
191
 
        addresses = {}
192
 
        num_available_ips = net.num_available_ips
193
 
        for i in range(num_available_ips - 1):
194
 
            result = self.service.allocate_fixed_ip(self.user.id,
195
 
                                                    self.projects[0].id)
196
 
            macs[i] = result['mac_address']
197
 
            addresses[i] = result['private_dns_name']
198
 
            issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
199
 
 
200
 
        result = self.service.allocate_fixed_ip(self.user.id,
201
 
                                                self.projects[0].id)
202
 
        mac = result['mac_address']
203
 
        address = result['private_dns_name']
204
 
 
205
 
        issue_ip(mac, address, hostname, net.bridge_name)
206
 
        self.service.deallocate_fixed_ip(address)
207
 
        release_ip(mac, address, hostname, net.bridge_name)
208
 
 
209
 
        result = self.service.allocate_fixed_ip(
210
 
                self.user, self.projects[0].id)
211
 
        secondmac = result['mac_address']
212
 
        secondaddress = result['private_dns_name']
213
 
        self.assertEqual(address, secondaddress)
214
 
        issue_ip(secondmac, secondaddress, hostname, net.bridge_name)
215
 
        self.service.deallocate_fixed_ip(secondaddress)
216
 
        release_ip(secondmac, secondaddress, hostname, net.bridge_name)
217
 
 
218
 
        for i in range(len(addresses)):
219
 
            self.service.deallocate_fixed_ip(addresses[i])
220
 
            release_ip(macs[i], addresses[i], hostname, net.bridge_name)
 
209
        address = self._create_address(0)
 
210
        lease_ip(address)
 
211
        self.network.deallocate_fixed_ip(self.context, address)
 
212
        release_ip(address)
 
213
 
 
214
        address2 = self._create_address(0)
 
215
        self.assertEqual(address, address2)
 
216
        self.network.deallocate_fixed_ip(self.context, address2)
221
217
 
222
218
    def test_available_ips(self):
223
219
        """Make sure the number of available ips for the network is correct
230
226
        There are ips reserved at the bottom and top of the range.
231
227
        services (network, gateway, CloudPipe, broadcast)
232
228
        """
233
 
        net = model.get_project_network(self.projects[0].id, "default")
234
 
        num_preallocated_ips = len(net.assigned)
 
229
        network = db.project_get_network(None, self.projects[0].id)
235
230
        net_size = flags.FLAGS.network_size
236
 
        num_available_ips = net_size - (net.num_bottom_reserved_ips +
237
 
                                        num_preallocated_ips +
238
 
                                        net.num_top_reserved_ips)
239
 
        self.assertEqual(num_available_ips, net.num_available_ips)
 
231
        total_ips = (db.network_count_available_ips(None, network['id']) +
 
232
                     db.network_count_reserved_ips(None, network['id']) +
 
233
                     db.network_count_allocated_ips(None, network['id']))
 
234
        self.assertEqual(total_ips, net_size)
240
235
 
241
236
    def test_too_many_addresses(self):
242
237
        """Test for a NoMoreAddresses exception when all fixed ips are used.
243
238
        """
244
 
        net = model.get_project_network(self.projects[0].id, "default")
245
 
 
246
 
        hostname = "toomany-hosts"
247
 
        macs = {}
248
 
        addresses = {}
249
 
        num_available_ips = net.num_available_ips
250
 
        for i in range(num_available_ips):
251
 
            result = self.service.allocate_fixed_ip(self.user.id,
252
 
                                                    self.projects[0].id)
253
 
            macs[i] = result['mac_address']
254
 
            addresses[i] = result['private_dns_name']
255
 
            issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
256
 
 
257
 
        self.assertEqual(net.num_available_ips, 0)
258
 
        self.assertRaises(NoMoreAddresses, self.service.allocate_fixed_ip,
259
 
                          self.user.id, self.projects[0].id)
260
 
 
261
 
        for i in range(len(addresses)):
262
 
            self.service.deallocate_fixed_ip(addresses[i])
263
 
            release_ip(macs[i], addresses[i], hostname, net.bridge_name)
264
 
        self.assertEqual(net.num_available_ips, num_available_ips)
265
 
 
266
 
 
267
 
def is_in_project(address, project_id):
 
239
        network = db.project_get_network(None, self.projects[0].id)
 
240
        num_available_ips = db.network_count_available_ips(None,
 
241
                                                           network['id'])
 
242
        addresses = []
 
243
        instance_ids = []
 
244
        for i in range(num_available_ips):
 
245
            mac = utils.generate_mac()
 
246
            instance_ref = db.instance_create(None,
 
247
                                              {'mac_address': mac})
 
248
            instance_ids.append(instance_ref['id'])
 
249
            address = self._create_address(0, instance_ref['id'])
 
250
            addresses.append(address)
 
251
            lease_ip(address)
 
252
 
 
253
        self.assertEqual(db.network_count_available_ips(None,
 
254
                                                        network['id']), 0)
 
255
        self.assertRaises(db.NoMoreAddresses,
 
256
                          self.network.allocate_fixed_ip,
 
257
                          self.context,
 
258
                          'foo')
 
259
 
 
260
        for i in range(num_available_ips):
 
261
            self.network.deallocate_fixed_ip(self.context, addresses[i])
 
262
            release_ip(addresses[i])
 
263
            db.instance_destroy(None, instance_ids[i])
 
264
        self.assertEqual(db.network_count_available_ips(None,
 
265
                                                        network['id']),
 
266
                         num_available_ips)
 
267
 
 
268
 
 
269
def is_allocated_in_project(address, project_id):
268
270
    """Returns true if address is in specified project"""
269
 
    return address in model.get_project_network(project_id).assigned
 
271
    project_net = db.project_get_network(None, project_id)
 
272
    network = db.fixed_ip_get_network(None, address)
 
273
    instance = db.fixed_ip_get_instance(None, address)
 
274
    # instance exists until release
 
275
    return instance is not None and network['id'] == project_net['id']
270
276
 
271
277
 
272
278
def binpath(script):
274
280
    return os.path.abspath(os.path.join(__file__, "../../../bin", script))
275
281
 
276
282
 
277
 
def issue_ip(mac, private_ip, hostname, interface):
 
283
def lease_ip(private_ip):
278
284
    """Run add command on dhcpbridge"""
279
 
    cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
280
 
                               mac, private_ip, hostname)
281
 
    env = {'DNSMASQ_INTERFACE': interface,
 
285
    network_ref = db.fixed_ip_get_network(None, private_ip)
 
286
    instance_ref = db.fixed_ip_get_instance(None, private_ip)
 
287
    cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
 
288
                                 instance_ref['mac_address'],
 
289
                                 private_ip)
 
290
    env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
282
291
           'TESTING': '1',
283
292
           'FLAGFILE': FLAGS.dhcpbridge_flagfile}
284
293
    (out, err) = utils.execute(cmd, addl_env=env)
285
294
    logging.debug("ISSUE_IP: %s, %s ", out, err)
286
295
 
287
296
 
288
 
def release_ip(mac, private_ip, hostname, interface):
 
297
def release_ip(private_ip):
289
298
    """Run del command on dhcpbridge"""
290
 
    cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
291
 
                               mac, private_ip, hostname)
292
 
    env = {'DNSMASQ_INTERFACE': interface,
 
299
    network_ref = db.fixed_ip_get_network(None, private_ip)
 
300
    instance_ref = db.fixed_ip_get_instance(None, private_ip)
 
301
    cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
 
302
                                 instance_ref['mac_address'],
 
303
                                 private_ip)
 
304
    env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
293
305
           'TESTING': '1',
294
306
           'FLAGFILE': FLAGS.dhcpbridge_flagfile}
295
307
    (out, err) = utils.execute(cmd, addl_env=env)