290 lines
11 KiB
Python
290 lines
11 KiB
Python
# Copyright 2015 VMware, Inc. All rights reserved.
|
|
#
|
|
# 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.
|
|
|
|
|
|
from vmware_nsx.shell.admin.plugins.common import constants
|
|
from vmware_nsx.shell.admin.plugins.common import formatters
|
|
|
|
import vmware_nsx.shell.admin.plugins.common.utils as admin_utils
|
|
from vmware_nsx.shell.admin.plugins.nsxv.resources import utils
|
|
import vmware_nsx.shell.resources as shell
|
|
|
|
from neutron_lib.callbacks import registry
|
|
from neutron_lib import exceptions
|
|
|
|
from vmware_nsx.db import nsxv_db
|
|
from vmware_nsx.extensions import (
|
|
vnicindex as ext_vnic_idx)
|
|
|
|
from oslo_log import log as logging
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
nsxv = utils.get_nsxv_client()
|
|
|
|
|
|
def get_spoofguard_policies():
|
|
nsxv_c = utils.get_nsxv_client()
|
|
return nsxv_c.get_spoofguard_policies()[1].get("policies")
|
|
|
|
|
|
def get_spoofguard_policy_data(policy_id):
|
|
nsxv_c = utils.get_nsxv_client()
|
|
return nsxv_c.get_spoofguard_policy_data(policy_id)[1].get(
|
|
'spoofguardList', [])
|
|
|
|
|
|
@admin_utils.output_header
|
|
def nsx_list_spoofguard_policies(resource, event, trigger, **kwargs):
|
|
"""List spoofguard policies from NSXv backend"""
|
|
policies = get_spoofguard_policies()
|
|
LOG.info(formatters.output_formatter(constants.SPOOFGUARD_POLICY, policies,
|
|
['policyId', 'name']))
|
|
|
|
|
|
def get_spoofguard_policy_network_mappings():
|
|
spgapi = utils.NeutronDbClient()
|
|
return nsxv_db.get_nsxv_spoofguard_policy_network_mappings(
|
|
spgapi.context)
|
|
|
|
|
|
@admin_utils.output_header
|
|
def neutron_list_spoofguard_policy_mappings(resource, event, trigger,
|
|
**kwargs):
|
|
mappings = get_spoofguard_policy_network_mappings()
|
|
LOG.info(formatters.output_formatter(constants.SPOOFGUARD_POLICY, mappings,
|
|
['network_id', 'policy_id']))
|
|
|
|
|
|
def get_missing_spoofguard_policy_mappings(reverse=None):
|
|
nsxv_spoofguard_policies = set()
|
|
for spg in get_spoofguard_policies():
|
|
nsxv_spoofguard_policies.add(spg.get('policyId'))
|
|
|
|
neutron_spoofguard_policy_mappings = set()
|
|
for binding in get_spoofguard_policy_network_mappings():
|
|
neutron_spoofguard_policy_mappings.add(binding.policy_id)
|
|
|
|
if reverse:
|
|
return nsxv_spoofguard_policies - neutron_spoofguard_policy_mappings
|
|
return neutron_spoofguard_policy_mappings - nsxv_spoofguard_policies
|
|
|
|
|
|
@admin_utils.output_header
|
|
def nsx_list_missing_spoofguard_policies(resource, event, trigger,
|
|
**kwargs):
|
|
"""List missing spoofguard policies on NSXv.
|
|
|
|
Spoofguard policies that have a binding in Neutron Db but there is
|
|
no policy on NSXv backend to back it.
|
|
"""
|
|
props = kwargs.get('property')
|
|
reverse = bool(props and props[0] == 'reverse')
|
|
if reverse:
|
|
LOG.info("Spoofguard policies on NSXv but not present in "
|
|
"Neutron Db")
|
|
else:
|
|
LOG.info("Spoofguard policies in Neutron Db but not present "
|
|
"on NSXv")
|
|
missing_policies = get_missing_spoofguard_policy_mappings(reverse)
|
|
if not missing_policies:
|
|
LOG.info("\nNo missing spoofguard policies found."
|
|
"\nNeutron DB and NSXv backend are in sync\n")
|
|
else:
|
|
LOG.info(missing_policies)
|
|
missing_policies = [{'policy_id': pid} for pid in missing_policies]
|
|
LOG.info(formatters.output_formatter(
|
|
constants.SPOOFGUARD_POLICY, missing_policies, ['policy_id']))
|
|
|
|
|
|
def get_port_vnic_id(plugin, port):
|
|
vnic_idx = port.get(ext_vnic_idx.VNIC_INDEX)
|
|
device_id = port.get('device_id')
|
|
return plugin._get_port_vnic_id(vnic_idx, device_id)
|
|
|
|
|
|
def nsx_list_mismatch_addresses_for_net(context, plugin, network_id,
|
|
policy_id):
|
|
policy_data = get_spoofguard_policy_data(policy_id)
|
|
missing = []
|
|
# Get all neutron compute ports on this network
|
|
port_filters = {'network_id': [network_id]}
|
|
neutron_ports = plugin.get_ports(context, filters=port_filters)
|
|
comp_ports = [port for port in neutron_ports
|
|
if port.get('device_owner', '').startswith('compute:')]
|
|
|
|
for port in comp_ports:
|
|
if not port['port_security_enabled']:
|
|
# This port is not in spoofguard
|
|
continue
|
|
error_data = None
|
|
port_ips = []
|
|
for pair in port.get('allowed_address_pairs'):
|
|
port_ips.append(pair['ip_address'])
|
|
for fixed in port.get('fixed_ips'):
|
|
port_ips.append(fixed['ip_address'])
|
|
if not port_ips:
|
|
continue
|
|
port_ips.sort()
|
|
mac_addr = port['mac_address']
|
|
vnic_id = get_port_vnic_id(plugin, port)
|
|
|
|
# look for this port in the spoofguard data
|
|
found_port = False
|
|
for spd in policy_data:
|
|
if spd['id'] == vnic_id:
|
|
found_port = True
|
|
actual_ips = spd.get('publishedIpAddress',
|
|
{}).get('ipAddresses', [])
|
|
actual_ips.sort()
|
|
if actual_ips != port_ips:
|
|
error_data = ('Different IPs (%s/%s)' % (
|
|
len(actual_ips), len(port_ips)))
|
|
elif spd.get('publishedMacAddress') != mac_addr:
|
|
error_data = ('Different MAC address (%s/%s)' % (
|
|
spd.get('publishedMacAddress'), mac_addr))
|
|
continue
|
|
|
|
if not found_port:
|
|
error_data = 'Port missing from SG policy'
|
|
|
|
if error_data:
|
|
missing.append({'network': network_id,
|
|
'policy': policy_id,
|
|
'port': port['id'],
|
|
'data': error_data})
|
|
return missing
|
|
|
|
|
|
@admin_utils.output_header
|
|
def nsx_list_mismatch_addresses(resource, event, trigger, **kwargs):
|
|
"""List missing spoofguard policies approved addresses on NSXv.
|
|
|
|
Address pairs defined on neutron compute ports that are missing from the
|
|
NSX-V spoofguard policy of a specific/all networks.
|
|
"""
|
|
network_id = None
|
|
if kwargs.get('property'):
|
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
|
network_id = properties.get('network')
|
|
|
|
spgapi = utils.NeutronDbClient()
|
|
|
|
if network_id:
|
|
policy_id = nsxv_db.get_spoofguard_policy_id(
|
|
spgapi.context.session, network_id)
|
|
if not policy_id:
|
|
LOG.error("Could not find spoofguard policy for neutron network "
|
|
"%s", network_id)
|
|
return
|
|
with utils.NsxVPluginWrapper() as plugin:
|
|
missing_data = nsx_list_mismatch_addresses_for_net(
|
|
spgapi.context, plugin, network_id, policy_id)
|
|
else:
|
|
with utils.NsxVPluginWrapper() as plugin:
|
|
missing_data = []
|
|
# Go over all the networks with spoofguard policies
|
|
mappings = get_spoofguard_policy_network_mappings()
|
|
for entry in mappings:
|
|
missing_data.extend(nsx_list_mismatch_addresses_for_net(
|
|
spgapi.context, plugin, entry['network_id'],
|
|
entry['policy_id']))
|
|
|
|
if missing_data:
|
|
LOG.info(formatters.output_formatter(
|
|
constants.SPOOFGUARD_POLICY, missing_data,
|
|
['network', 'policy', 'port', 'data']))
|
|
else:
|
|
LOG.info("No mismatches found.")
|
|
|
|
|
|
@admin_utils.output_header
|
|
def nsx_fix_mismatch_addresses(resource, event, trigger, **kwargs):
|
|
"""Fix missing spoofguard policies approved addresses for a port."""
|
|
|
|
port_id = None
|
|
if kwargs.get('property'):
|
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
|
port_id = properties.get('port')
|
|
if not port_id:
|
|
usage_msg = ("Need to specify the id of the neutron port. "
|
|
"Add --property port=<port_id>")
|
|
LOG.error(usage_msg)
|
|
return
|
|
|
|
spgapi = utils.NeutronDbClient()
|
|
with utils.NsxVPluginWrapper() as plugin:
|
|
try:
|
|
port = plugin.get_port(spgapi.context, port_id)
|
|
except exceptions.PortNotFound:
|
|
LOG.error("Could not find neutron port %s", port_id)
|
|
return
|
|
vnic_id = get_port_vnic_id(plugin, port)
|
|
plugin._update_vnic_assigned_addresses(
|
|
spgapi.context.session, port, vnic_id)
|
|
LOG.info("Done.")
|
|
|
|
|
|
def nsx_clean_spoofguard_policy(resource, event, trigger, **kwargs):
|
|
"""Delete spoofguard policy"""
|
|
errmsg = ("Need to specify policy-id. Add --property "
|
|
"policy-id=<policy-id>")
|
|
if not kwargs.get('property'):
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
|
policy_id = properties.get('policy-id')
|
|
if not policy_id:
|
|
LOG.error("%s", errmsg)
|
|
return
|
|
try:
|
|
h, c = nsxv.get_spoofguard_policy(policy_id)
|
|
except exceptions.NeutronException as e:
|
|
LOG.error("Unable to retrieve policy %(p)s: %(e)s",
|
|
{'p': policy_id, 'e': str(e)})
|
|
else:
|
|
if not c.get('spoofguardList'):
|
|
LOG.error("Policy %s does not exist", policy_id)
|
|
return
|
|
confirm = admin_utils.query_yes_no(
|
|
"Do you want to delete spoofguard-policy: %s" % policy_id,
|
|
default="no")
|
|
if not confirm:
|
|
LOG.info("spoofguard-policy deletion aborted by user")
|
|
return
|
|
try:
|
|
nsxv.delete_spoofguard_policy(policy_id)
|
|
except Exception as e:
|
|
LOG.error("%s", str(e))
|
|
LOG.info('spoofguard-policy successfully deleted.')
|
|
|
|
|
|
registry.subscribe(neutron_list_spoofguard_policy_mappings,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.LIST.value)
|
|
registry.subscribe(nsx_list_spoofguard_policies,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.LIST.value)
|
|
registry.subscribe(nsx_list_missing_spoofguard_policies,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.LIST.value)
|
|
registry.subscribe(nsx_list_mismatch_addresses,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.LIST_MISMATCHES.value)
|
|
registry.subscribe(nsx_fix_mismatch_addresses,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.FIX_MISMATCH.value)
|
|
registry.subscribe(nsx_clean_spoofguard_policy,
|
|
constants.SPOOFGUARD_POLICY,
|
|
shell.Operations.CLEAN.value)
|