A set of Neutron drivers for the VMware NSX.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

558 lines
26 KiB

# Copyright 2014 VMware, Inc
#
# 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 mock
from oslo_config import cfg
from oslo_utils import uuidutils
from six import moves
from neutron.common import exceptions as n_exc
from neutron import context
from neutron.plugins.common import constants as plugin_const
from neutron.tests.unit import testlib_api
from vmware_nsx.neutron.plugins.vmware.common import nsxv_constants
from vmware_nsx.neutron.plugins.vmware.dbexts import nsxv_db
from vmware_nsx.neutron.plugins.vmware.vshield.common import (
constants as vcns_const)
from vmware_nsx.neutron.plugins.vmware.vshield import edge_utils
from vmware_nsx.tests.unit import vmware
_uuid = uuidutils.generate_uuid
#Four types of backup edge with different status
EDGE_AVAIL = 'available-'
EDGE_CREATING = 'creating-'
EDGE_ERROR1 = 'error1-'
EDGE_ERROR2 = 'error2-'
EDGE_DELETING = 'deleting-'
class EdgeUtilsTestCaseMixin(testlib_api.SqlTestCase):
def setUp(self):
super(EdgeUtilsTestCaseMixin, self).setUp()
nsxv_manager_p = mock.patch(vmware.VCNS_DRIVER_NAME, autospec=True)
self.nsxv_manager = nsxv_manager_p.start()
task = mock.Mock()
nsxv_manager_p.return_value = task
self.nsxv_manager.callbacks = mock.Mock()
self.nsxv_manager.vcns = mock.Mock()
get_ver = mock.patch.object(self.nsxv_manager.vcns,
'get_version').start()
get_ver.return_value = '6.1.4'
self.ctx = context.get_admin_context()
self.addCleanup(nsxv_manager_p.stop)
def _create_router(self, name='router1'):
return {'name': name,
'id': _uuid()}
def _create_network(self, name='network'):
return {'name': name,
'id': _uuid()}
def _create_subnet(self, name='subnet'):
return {'name': name,
'id': _uuid()}
def _populate_vcns_router_binding(self, bindings):
for binding in bindings:
nsxv_db.init_edge_vnic_binding(self.ctx.session,
binding['edge_id'])
nsxv_db.add_nsxv_router_binding(
self.ctx.session, binding['router_id'],
binding['edge_id'], None, binding['status'],
appliance_size=binding['appliance_size'],
edge_type=binding['edge_type'])
class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
def setUp(self):
super(EdgeDHCPManagerTestCase, self).setUp()
self.edge_manager = edge_utils.EdgeManager(self.nsxv_manager, None)
self.check = mock.patch.object(self.edge_manager,
'check_edge_active_at_backend').start()
self.check.return_value = True
def test_create_dhcp_edge_service(self):
fake_edge_pool = [{'status': plugin_const.ACTIVE,
'edge_id': 'edge-1',
'router_id': 'backup-11111111-1111',
'appliance_size': 'compact',
'edge_type': 'service'},
{'status': plugin_const.PENDING_DELETE,
'edge_id': 'edge-2',
'router_id': 'dhcp-22222222-2222',
'appliance_size': 'compact',
'edge_type': 'service'},
{'status': plugin_const.PENDING_DELETE,
'edge_id': 'edge-3',
'router_id': 'backup-33333333-3333',
'appliance_size': 'compact',
'edge_type': 'service'}]
self._populate_vcns_router_binding(fake_edge_pool)
fake_network = self._create_network()
fake_subnet = self._create_subnet(fake_network['id'])
with mock.patch.object(self.edge_manager,
'_get_used_edges', return_value=([], [])):
self.edge_manager.create_dhcp_edge_service(self.ctx,
fake_network['id'],
fake_subnet)
resource_id = (vcns_const.DHCP_EDGE_PREFIX + fake_network['id'])[:36]
self.nsxv_manager.update_edge.assert_called_once_with(
resource_id, 'edge-1', mock.ANY, None,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
dist=False)
class EdgeUtilsTestCase(EdgeUtilsTestCaseMixin):
def test_create_lrouter(self):
lrouter = self._create_router()
edge_utils.create_lrouter(self.nsxv_manager, self.ctx, lrouter,
lswitch=None, dist=False)
self.nsxv_manager.deploy_edge.assert_called_once_with(
lrouter['id'], (lrouter['name'] + '-' + lrouter['id']),
internal_network=None, dist=False,
jobdata={'router_id': lrouter['id'],
'lrouter': lrouter,
'lswitch': None,
'context': self.ctx},
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router'])
class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
def setUp(self):
super(EdgeManagerTestCase, self).setUp()
cfg.CONF.set_override('backup_edge_pool', [], 'nsxv')
self.edge_manager = edge_utils.EdgeManager(self.nsxv_manager, None)
self.check = mock.patch.object(self.edge_manager,
'check_edge_active_at_backend').start()
self.check.side_effect = self.check_edge_active_at_backend
self.default_edge_pool_dicts = {
nsxv_constants.SERVICE_EDGE: {
nsxv_constants.LARGE: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3},
nsxv_constants.COMPACT: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3}},
nsxv_constants.VDR_EDGE: {}}
self.vdr_edge_pool_dicts = {
nsxv_constants.SERVICE_EDGE: {},
nsxv_constants.VDR_EDGE: {
nsxv_constants.LARGE: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3}}}
def check_edge_active_at_backend(self, edge_id):
# workaround to let edge_id None pass since we wrapped router binding
# db update op.
if edge_id is None:
edge_id = ""
return not (edge_id.startswith(EDGE_ERROR1) or
edge_id.startswith(EDGE_ERROR2))
def test_backup_edge_pool_with_default(self):
cfg.CONF.set_override('backup_edge_pool',
['service:large:1:3', 'service:compact:1:3'],
'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
self.assertEqual(self.default_edge_pool_dicts, edge_pool_dicts)
def test_backup_edge_pool_with_empty_conf(self):
cfg.CONF.set_override('backup_edge_pool', [], 'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
expect_edge_pool_dicts = {
nsxv_constants.SERVICE_EDGE: {},
nsxv_constants.VDR_EDGE: {}}
self.assertEqual(expect_edge_pool_dicts, edge_pool_dicts)
def test_backup_edge_pool_with_vdr_conf(self):
cfg.CONF.set_override('backup_edge_pool', ['vdr::1:3'], 'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
expect_edge_pool_dicts = self.vdr_edge_pool_dicts
self.assertEqual(expect_edge_pool_dicts, edge_pool_dicts)
def test_backup_edge_pool_with_duplicate_conf(self):
cfg.CONF.set_override('backup_edge_pool',
['service:large:1:3', 'service::3:4'],
'nsxv')
self.assertRaises(n_exc.Invalid, edge_utils.parse_backup_edge_pool_opt)
def _create_available_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
id_prefix = EDGE_AVAIL + size + '-' + edge_type
return [{'status': plugin_const.ACTIVE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
for i in moves.range(num)]
def _create_creating_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
id_prefix = EDGE_CREATING + size + '-' + edge_type
return [{'status': plugin_const.PENDING_CREATE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
for i in moves.range(num)]
def _create_error_router_bindings(
self, num, status=plugin_const.ERROR,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
id_prefix = EDGE_ERROR1 + size + '-' + edge_type
return [{'status': status,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
for i in moves.range(num)]
def _create_error_router_bindings_at_backend(
self, num, status=plugin_const.ACTIVE,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
id_prefix = EDGE_ERROR2 + size + '-' + edge_type
return [{'status': status,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
for i in moves.range(num)]
def _create_deleting_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
id_prefix = EDGE_DELETING + size + '-' + edge_type
return [{'status': plugin_const.PENDING_DELETE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
for i in moves.range(num)]
def _create_edge_pools(self, avail, creating, error,
error_at_backend, deleting,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
"""Create a backup edge pool with different status of edges.
Backup edges would be edges with avail, creating and error_at_backend,
while available edges would only be edges with avail status.
"""
return (
self._create_error_router_bindings(
error, size=size, edge_type=edge_type) +
self._create_deleting_router_bindings(
deleting, size=size, edge_type=edge_type) +
self._create_error_router_bindings_at_backend(
error_at_backend, size=size, edge_type=edge_type) +
self._create_creating_router_bindings(
creating, size=size, edge_type=edge_type) +
self._create_available_router_bindings(
avail, size=size, edge_type=edge_type))
def _create_backup_router_bindings(
self, avail, creating, error, error_at_backend, deleting,
error_status=plugin_const.PENDING_DELETE,
error_at_backend_status=plugin_const.PENDING_DELETE,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
return (
self._create_error_router_bindings(
error, status=error_status, size=size, edge_type=edge_type) +
self._create_error_router_bindings_at_backend(
error_at_backend, status=error_at_backend_status,
size=size, edge_type=edge_type) +
self._create_creating_router_bindings(
creating, size=size, edge_type=edge_type) +
self._create_available_router_bindings(
avail, size=size, edge_type=edge_type) +
self._create_deleting_router_bindings(
deleting, size=size, edge_type=edge_type))
def _verify_router_bindings(self, exp_bindings, act_db_bindings):
exp_dict = dict(zip([binding['router_id']
for binding in exp_bindings], exp_bindings))
act_bindings = [{'router_id': binding['router_id'],
'edge_id': binding['edge_id'],
'status': binding['status'],
'appliance_size': binding['appliance_size'],
'edge_type': binding['edge_type']}
for binding in act_db_bindings]
act_dict = dict(zip([binding['router_id']
for binding in act_bindings], act_bindings))
self.assertEqual(exp_dict, act_dict)
def test_get_backup_edge_bindings(self):
"""Test get backup edges filtering out deleting and error edges."""
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT))
self._populate_vcns_router_binding(pool_edges)
expect_backup_bindings = self._create_backup_router_bindings(
1, 2, 0, 4, 0,
error_at_backend_status=plugin_const.ACTIVE,
size=nsxv_constants.LARGE)
backup_bindings = self.edge_manager._get_backup_edge_bindings(self.ctx)
self._verify_router_bindings(expect_backup_bindings, backup_bindings)
def test_get_available_router_bindings(self):
appliance_size = nsxv_constants.LARGE
edge_type = nsxv_constants.SERVICE_EDGE
pool_edges = (self._create_edge_pools(1, 2, 3, 0, 5) +
self._create_edge_pools(
1, 2, 3, 0, 5, size=nsxv_constants.COMPACT))
self._populate_vcns_router_binding(pool_edges)
expect_backup_bindings = self._create_backup_router_bindings(
1, 2, 3, 0, 5, error_status=plugin_const.ERROR)
binding = self.edge_manager._get_available_router_binding(
self.ctx, appliance_size=appliance_size, edge_type=edge_type)
router_bindings = [
binding_db
for binding_db in nsxv_db.get_nsxv_router_bindings(
self.ctx.session)
if (binding_db['appliance_size'] == appliance_size and
binding_db['edge_type'] == edge_type)]
self._verify_router_bindings(expect_backup_bindings, router_bindings)
edge_id = (EDGE_AVAIL + appliance_size + '-' +
edge_type + '-edge-' + str(0))
self.assertEqual(edge_id, binding['edge_id'])
def test_check_backup_edge_pool_with_max(self):
appliance_size = nsxv_constants.LARGE
edge_type = nsxv_constants.SERVICE_EDGE
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT))
self._populate_vcns_router_binding(pool_edges)
expect_pool_bindings = self._create_backup_router_bindings(
1, 2, 3, 4, 5,
error_status=plugin_const.ERROR,
error_at_backend_status=plugin_const.PENDING_DELETE)
self.edge_manager._check_backup_edge_pool(
0, 3,
appliance_size=appliance_size, edge_type=edge_type)
router_bindings = [
binding
for binding in nsxv_db.get_nsxv_router_bindings(self.ctx.session)
if (binding['appliance_size'] == appliance_size and
binding['edge_type'] == edge_type)]
self._verify_router_bindings(expect_pool_bindings, router_bindings)
def test_check_backup_edge_pool_with_min(self):
appliance_size = nsxv_constants.LARGE
edge_type = nsxv_constants.SERVICE_EDGE
pool_edges = (self._create_edge_pools(1, 2, 3, 0, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT))
self._populate_vcns_router_binding(pool_edges)
edge_utils.eventlet = mock.Mock()
edge_utils.eventlet.spawn_n.return_value = None
self.edge_manager._check_backup_edge_pool(
5, 10, appliance_size=appliance_size, edge_type=edge_type)
router_bindings = [
binding
for binding in nsxv_db.get_nsxv_router_bindings(self.ctx.session)
if binding['edge_id'] is None
and binding['status'] == plugin_const.PENDING_CREATE]
binding_ids = [bind.router_id for bind in router_bindings]
self.assertEqual(2, len(router_bindings))
edge_utils.eventlet.spawn_n.assert_called_with(
mock.ANY, mock.ANY, binding_ids, appliance_size, edge_type)
def test_check_backup_edge_pools_with_empty_conf(self):
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._check_backup_edge_pools()
router_bindings = nsxv_db.get_nsxv_router_bindings(self.ctx.session)
for binding in router_bindings:
self.assertEqual(plugin_const.PENDING_DELETE, binding['status'])
def test_check_backup_edge_pools_with_default(self):
self.edge_manager.edge_pool_dicts = self.default_edge_pool_dicts
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._check_backup_edge_pools()
router_bindings = nsxv_db.get_nsxv_router_bindings(self.ctx.session)
expect_large_bindings = self._create_backup_router_bindings(
1, 2, 3, 4, 5,
error_status=plugin_const.PENDING_DELETE,
error_at_backend_status=plugin_const.PENDING_DELETE)
large_bindings = [
binding
for binding in router_bindings
if (binding['appliance_size'] == nsxv_constants.LARGE and
binding['edge_type'] == nsxv_constants.SERVICE_EDGE)]
self._verify_router_bindings(expect_large_bindings, large_bindings)
expect_compact_bindings = self._create_backup_router_bindings(
1, 2, 3, 4, 5,
error_status=plugin_const.PENDING_DELETE,
error_at_backend_status=plugin_const.PENDING_DELETE,
size=nsxv_constants.COMPACT)
compact_bindings = [
binding
for binding in router_bindings
if (binding['appliance_size'] == nsxv_constants.COMPACT and
binding['edge_type'] == nsxv_constants.SERVICE_EDGE)]
self._verify_router_bindings(expect_compact_bindings, compact_bindings)
vdr_bindings = [
binding
for binding in router_bindings
if (binding['appliance_size'] == nsxv_constants.LARGE and
binding['edge_type'] == nsxv_constants.VDR_EDGE)]
for binding in vdr_bindings:
self.assertEqual(plugin_const.PENDING_DELETE, binding['status'])
def test_check_backup_edge_pools_with_vdr(self):
self.edge_manager.edge_pool_dicts = self.vdr_edge_pool_dicts
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._check_backup_edge_pools()
router_bindings = nsxv_db.get_nsxv_router_bindings(self.ctx.session)
expect_vdr_bindings = self._create_backup_router_bindings(
1, 2, 3, 4, 5,
error_status=plugin_const.PENDING_DELETE,
error_at_backend_status=plugin_const.PENDING_DELETE,
edge_type=nsxv_constants.VDR_EDGE)
vdr_bindings = [
binding
for binding in router_bindings
if (binding['appliance_size'] == nsxv_constants.LARGE and
binding['edge_type'] == nsxv_constants.VDR_EDGE)]
self._verify_router_bindings(expect_vdr_bindings, vdr_bindings)
service_bindings = [
binding
for binding in router_bindings
if binding['edge_type'] == nsxv_constants.SERVICE_EDGE]
for binding in service_bindings:
self.assertEqual(plugin_const.PENDING_DELETE, binding['status'])
def test_allocate_edge_appliance_with_empty(self):
self.edge_manager._clean_all_error_edge_bindings = mock.Mock()
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name')
assert not self.edge_manager._clean_all_error_edge_bindings.called
def test_allocate_large_edge_appliance_with_default(self):
self.edge_manager.edge_pool_dicts = self.default_edge_pool_dicts
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name')
edge_id = (EDGE_AVAIL + nsxv_constants.LARGE + '-' +
nsxv_constants.SERVICE_EDGE + '-edge-' + str(0))
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
appliance_size=nsxv_constants.LARGE, dist=False)])
def test_allocate_compact_edge_appliance_with_default(self):
self.edge_manager.edge_pool_dicts = self.default_edge_pool_dicts
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name',
appliance_size=nsxv_constants.COMPACT)
edge_id = (EDGE_AVAIL + nsxv_constants.COMPACT + '-' +
nsxv_constants.SERVICE_EDGE + '-edge-' + str(0))
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
appliance_size=nsxv_constants.COMPACT, dist=False)])
def test_allocate_large_edge_appliance_with_vdr(self):
self.edge_manager.edge_pool_dicts = self.vdr_edge_pool_dicts
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
self._create_edge_pools(
1, 2, 3, 4, 5, size=nsxv_constants.COMPACT) +
self._create_edge_pools(
1, 2, 3, 4, 5, edge_type=nsxv_constants.VDR_EDGE))
self._populate_vcns_router_binding(pool_edges)
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name', dist=True)
edge_id = (EDGE_AVAIL + nsxv_constants.LARGE + '-' +
nsxv_constants.VDR_EDGE + '-edge-' + str(0))
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
appliance_size=nsxv_constants.LARGE, dist=True)])
def test_free_edge_appliance_with_empty(self):
self.edge_manager._clean_all_error_edge_bindings = mock.Mock()
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name')
self.edge_manager._free_edge_appliance(
self.ctx, 'fake_id')
assert not self.edge_manager._clean_all_error_edge_bindings.called
def test_free_edge_appliance_with_default(self):
self.edge_manager.edge_pool_dicts = self.default_edge_pool_dicts
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name')
self.edge_manager._free_edge_appliance(
self.ctx, 'fake_id')
assert not self.nsxv_manager.delete_edge.called
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', mock.ANY, mock.ANY, None,
appliance_size=nsxv_constants.LARGE, dist=False)])
def test_free_edge_appliance_with_default_with_full(self):
self.edge_pool_dicts = {
nsxv_constants.SERVICE_EDGE: {
nsxv_constants.LARGE: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 1},
nsxv_constants.COMPACT: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3}},
nsxv_constants.VDR_EDGE: {}}
self.edge_manager._allocate_edge_appliance(
self.ctx, 'fake_id', 'fake_name')
self.edge_manager._free_edge_appliance(
self.ctx, 'fake_id')
assert self.nsxv_manager.delete_edge.called
assert not self.nsxv_manager.update_edge.called