diff --git a/vmware_nsx/plugins/nsx_v/vshield/vcns.py b/vmware_nsx/plugins/nsx_v/vshield/vcns.py index ac821225d5..5e80a49c03 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/vcns.py +++ b/vmware_nsx/plugins/nsx_v/vshield/vcns.py @@ -507,11 +507,14 @@ class Vcns(object): return self.do_request(HTTP_PUT, uri, et.tostring(sg), format='xml', decode=False, encode=False) + def list_security_groups(self): + uri = '%s/scope/globalroot-0' % SECURITYGROUP_PREFIX + return self.do_request(HTTP_GET, uri, format='xml', decode=False) + def get_security_group_id(self, sg_name): """Returns NSXv security group id which match the given name.""" - uri = '%s/scope/globalroot-0' % SECURITYGROUP_PREFIX - h, c = self.do_request(HTTP_GET, uri, format='xml', decode=False) - root = et.fromstring(c) + h, secgroups = self.list_security_groups() + root = et.fromstring(secgroups) for sg in root.iter('securitygroup'): if sg.find('name').text == sg_name: return sg.find('objectId').text @@ -565,14 +568,14 @@ class Vcns(object): return self.do_request(HTTP_GET, section_uri, format='xml', decode=False) + def get_dfw_config(self): + uri = FIREWALL_PREFIX + return self.do_request(HTTP_GET, uri, decode=False, format='xml') + def get_section_id(self, section_name): """Retrieve the id of a section from nsx.""" - uri = FIREWALL_PREFIX - h, section_list = self.do_request(HTTP_GET, uri, decode=False, - format='xml') - - root = et.fromstring(section_list) - + h, firewall_config = self.get_dfw_config() + root = et.fromstring(firewall_config) for sec in root.iter('section'): if sec.attrib['name'] == section_name: return sec.attrib['id'] diff --git a/vmware_nsx/shell/admin/plugins/common/constants.py b/vmware_nsx/shell/admin/plugins/common/constants.py index 095e5b1887..ecac95652f 100644 --- a/vmware_nsx/shell/admin/plugins/common/constants.py +++ b/vmware_nsx/shell/admin/plugins/common/constants.py @@ -21,8 +21,8 @@ NSXV3_PLUGIN = 'vmware_nsx.plugin.NsxV3Plugin' NSXV_PLUGIN = 'vmware_nsx.plugin.NsxVPlugin' # NSXV3 Resource Constants -FIREWALL_SECTIONS = 'Firewall Sections' -FIREWALL_NSX_GROUPS = 'Firewall NS Groups' +FIREWALL_SECTIONS = 'firewall-sections' +FIREWALL_NSX_GROUPS = 'nsx-security-groups' SECURITY_GROUPS = 'security-groups' # NSXV Resource Constants diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/securitygroups.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/securitygroups.py new file mode 100644 index 0000000000..5e57e66adf --- /dev/null +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/securitygroups.py @@ -0,0 +1,179 @@ +# Copyright 2016 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. + + +import logging +import xml.etree.ElementTree as et + +from neutron.callbacks import registry +from neutron import context +from neutron.db import securitygroups_db + +from vmware_nsx.db import nsx_models +from vmware_nsx.db import nsxv_models +from vmware_nsx.shell.admin.plugins.common import constants +from vmware_nsx.shell.admin.plugins.common import formatters +from vmware_nsx.shell.admin.plugins.common import utils as admin_utils +from vmware_nsx.shell.admin.plugins.nsxv.resources import utils +from vmware_nsx.shell import nsxadmin + + +LOG = logging.getLogger(__name__) + + +class NeutronSecurityGroupDB(utils.NeutronDbClient): + def __init__(self): + super(NeutronSecurityGroupDB, self) + # FIXME(roeyc): context is already defined in NeutrondDbClient + self.context = context.get_admin_context() + + def get_security_groups_mappings(self): + q = self.context.session.query( + securitygroups_db.SecurityGroup.name, + securitygroups_db.SecurityGroup.id, + nsxv_models.NsxvSecurityGroupSectionMapping.ip_section_id, + nsx_models.NeutronNsxSecurityGroupMapping.nsx_id).join( + nsxv_models.NsxvSecurityGroupSectionMapping, + nsx_models.NeutronNsxSecurityGroupMapping).all() + sg_mappings = [{'name': mapp.name, + 'id': mapp.id, + 'section-id': mapp.ip_section_id.split('/')[-1], + 'nsx-securitygroup-id': mapp.nsx_id} + for mapp in q] + return sg_mappings + + def get_security_groups(self): + return super(NeutronSecurityGroupDB, + self).get_security_groups(self.context) + + +class NsxFirewallAPI(object): + def __init__(self): + self.vcns = utils.get_nsxv_client() + + def list_security_groups(self): + h, secgroups = self.vcns.list_security_groups() + root = et.fromstring(secgroups) + secgroups = [] + for sg in root.iter('securitygroup'): + sg_id = sg.find('objectId').text + # This specific security-group is not relevant to the plugin + if sg_id == 'securitygroup-1': + continue + secgroups.append({'name': sg.find('name').text, + 'id': sg_id}) + return secgroups + + def list_fw_sections(self): + h, firewall_config = self.vcns.get_dfw_config() + root = et.fromstring(firewall_config) + sections = [] + for sec in root.iter('section'): + sec_id = sec.attrib['id'] + # Don't show NSX default sections, which are not relevant to OS. + if sec_id in ['1001', '1002', '1003']: + continue + sections.append({'name': sec.attrib['name'], + 'id': sec_id}) + return sections + + +neutron_sg = NeutronSecurityGroupDB() +nsxv_firewall = NsxFirewallAPI() + + +def _log_info(resource, data, attrs=['name', 'id']): + LOG.info(formatters.output_formatter(resource, data, attrs)) + + +def list_handler(resource): + def wrap(func): + registry.subscribe(func, resource, + nsxadmin.Operations.LIST.value) + return func + return wrap + + +def list_mismatches_handler(resource): + def wrap(func): + registry.subscribe(func, resource, + nsxadmin.Operations.LIST_MISMATCHES.value) + return func + return wrap + + +@list_handler(constants.SECURITY_GROUPS) +@admin_utils.output_header +def neutron_list_security_groups_mappings(resource, event, trigger, **kwargs): + sg_mappings = neutron_sg.get_security_groups_mappings() + _log_info(constants.SECURITY_GROUPS, + sg_mappings, + attrs=['name', 'id', 'section-id', 'nsx-securitygroup-id']) + return bool(sg_mappings) + + +@list_handler(constants.FIREWALL_SECTIONS) +@admin_utils.output_header +def nsx_list_dfw_sections(resource, event, trigger, **kwargs): + fw_sections = nsxv_firewall.list_fw_sections() + _log_info(constants.FIREWALL_SECTIONS, fw_sections) + return bool(fw_sections) + + +@list_handler(constants.FIREWALL_NSX_GROUPS) +@admin_utils.output_header +def nsx_list_security_groups(resource, event, trigger, **kwargs): + nsx_secgroups = nsxv_firewall.list_security_groups() + _log_info(constants.FIREWALL_NSX_GROUPS, nsx_secgroups) + return bool(nsx_secgroups) + + +@list_mismatches_handler(constants.FIREWALL_NSX_GROUPS) +@admin_utils.output_header +def list_missing_security_groups(resource, event, trigger, **kwargs): + nsx_secgroups = nsxv_firewall.list_security_groups() + sg_mappings = neutron_sg.get_security_groups_mappings() + missing_nsx_secgroups = [] + for sg_db in sg_mappings: + for nsx_sg in nsx_secgroups: + if nsx_sg['id'] == sg_db['nsx-securitygroup-id']: + break + else: + missing_nsx_secgroups.append({'securitygroup-name': sg_db['name'], + 'securitygroup-id': sg_db['id'], + 'nsx-securitygroup-id': + sg_db['nsx-securitygroup-id']}) + _log_info(constants.FIREWALL_NSX_GROUPS, missing_nsx_secgroups, + attrs=['securitygroup-name', 'securitygroup-id', + 'nsx-securitygroup-id']) + return bool(missing_nsx_secgroups) + + +@list_mismatches_handler(constants.FIREWALL_SECTIONS) +@admin_utils.output_header +def list_missing_firewall_sections(resource, event, trigger, **kwargs): + fw_sections = nsxv_firewall.list_fw_sections() + sg_mappings = neutron_sg.get_security_groups_mappings() + missing_sections = [] + for sg_db in sg_mappings: + for fw_section in fw_sections: + if fw_section['id'] == sg_db['section-id']: + break + else: + missing_sections.append({'securitygroup-name': sg_db['name'], + 'securitygroup-id': sg_db['id'], + 'section-id': sg_db['section-id']}) + _log_info(constants.FIREWALL_SECTIONS, missing_sections, + attrs=['securitygroup-name', 'securitygroup-id', 'section-id']) + return bool(missing_sections) diff --git a/vmware_nsx/shell/nsxadmin.py b/vmware_nsx/shell/nsxadmin.py index 7ef7ee87e7..7f6f430596 100644 --- a/vmware_nsx/shell/nsxadmin.py +++ b/vmware_nsx/shell/nsxadmin.py @@ -100,6 +100,14 @@ nsxv_resources = { Operations.NSX_UPDATE.value]), constants.NETWORKS: Resource(constants.NETWORKS, [Operations.LIST.value]), + constants.SECURITY_GROUPS: Resource(constants.SECURITY_GROUPS, + [Operations.LIST.value]), + constants.FIREWALL_SECTIONS: Resource(constants.FIREWALL_SECTIONS, + [Operations.LIST.value, + Operations.LIST_MISMATCHES.value]), + constants.FIREWALL_NSX_GROUPS: Resource( + constants.FIREWALL_NSX_GROUPS, [Operations.LIST.value, + Operations.LIST_MISMATCHES.value]), } nsxv3_resources_names = map(lambda res: res.name, nsxv3_resources.itervalues())