Skip to content

Commit

Permalink
Merge pull request #34 from osrf/issue_34
Browse files Browse the repository at this point in the history
White list for capability server
  • Loading branch information
wjwwood committed Nov 8, 2013
2 parents 79a7a79 + 2741a78 commit da4d263
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ if(CATKIN_ENABLE_TESTING)
add_rostest(test/rostest/test_launch_manager/test_launch_manager.test)
add_rostest(test/rostest/test_server/test_dependent_capabilities.test)
add_rostest(test/rostest/test_server/test_invalid_specs.test)
add_rostest(test/rostest/test_server/test_package_white_black_lists.test)
add_rostest(test/rostest/test_server/test_ros_services.test)
add_rostest(test/rostest/test_server/test_white_black_lists.test)
add_rostest(test/rostest/test_service_discovery/test_spec_index_from_service.test)
endif()
18 changes: 18 additions & 0 deletions launch/demo.launch
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@
<env name="ROS_PACKAGE_PATH"
value="$(find capabilities)/test/unit/discovery_workspaces/$(arg test_case):$(env ROS_PACKAGE_PATH)" />
<param name="debug" value="true" if="$(arg debug)" />
<!-- Uncomment to whitelist packages -->
<!-- <rosparam param="package_whitelist">
- some_other_package
#- minimal_pkg
</rosparam> -->
<!-- Uncomment to blacklist packages -->
<!-- <rosparam param="package_blacklist">
- minimal_pkg
</rosparam> -->
<!-- Uncomment to whitelist capabilities -->
<!-- <rosparam param="whitelist">
- 'minimal_pkg/Minimal'
- 'minimal_pkg/SpecificMinimal'
</rosparam> -->
<!-- Uncomment to blacklist capabilities -->
<!-- <rosparam param="blacklist">
- 'minimal_pkg/SpecificMinimal'
</rosparam> -->
<!-- Uncomment below to explicitly set the default provider for minimal_pkg/Minimal -->
<!-- <param name="defaults/minimal_pkg/Minimal" value="minimal_pkg/minimal" /> -->
</node>
Expand Down
34 changes: 34 additions & 0 deletions src/capabilities/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ def spec_file_index_from_package_index(package_index):
if tag != 'package' and tag in spec_file_index[package_name]:
spec_file_path = os.path.join(package_path, export.content)
spec_file_index[package_name][tag].append(spec_file_path)
# Prune packages with no specs
if (
not spec_file_index[package_name]['capability_interface']
and not spec_file_index[package_name]['capability_provider']
and not spec_file_index[package_name]['semantic_capability_interface']
):
del spec_file_index[package_name]
return spec_file_index


Expand Down Expand Up @@ -303,6 +310,15 @@ def add_interface(self, interface, file_path, package_name):
'instance': interface
}

def remove_interface(self, interface_name):
"""Removes a capability interface by name
:param interface_name: name of the interface to remove
:type interface_name: str
:raises: :py:exc:`KeyError` if there is no interface by that name
"""
del self.__interfaces[interface_name]

def add_semantic_interface(self, semantic_interface, file_path, package_name):
"""Add a loaded SemanticCapabilityInterface object into the repository
Expand Down Expand Up @@ -338,6 +354,15 @@ def add_semantic_interface(self, semantic_interface, file_path, package_name):
'instance': semantic_interface
}

def remove_semantic_interface(self, semantic_interface_name):
"""Removes a semantic capability interface by name
:param semantic_interface_name: name of the interface to remove
:type semantic_interface_name: str
:raises: :py:exc:`KeyError` if there is no interface by that name
"""
del self.__semantic_interfaces[semantic_interface_name]

def add_provider(self, provider, file_path, package_name):
"""Add a loaded CapabilityProvider object into the repository
Expand Down Expand Up @@ -371,6 +396,15 @@ def add_provider(self, provider, file_path, package_name):
'instance': provider
}

def remove_provider(self, provider_name):
"""Removes a capability provider by name
:param provider_name: name of the interface to remove
:type provider_name: str
:raises: :py:exc:`KeyError` if there is no interface by that name
"""
del self.__providers[provider_name]

@property
def names(self):
"""list of all names"""
Expand Down
54 changes: 54 additions & 0 deletions src/capabilities/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,35 @@ def __init__(self, package_paths, screen=None):
self.__capability_instances = {}
self.__launch_manager = LaunchManager(screen=bool(rospy.get_param('~use_screen', screen)))
self.__debug = False
self.__package_whitelist = None
self.__package_blacklist = None
self.__whitelist = None
self.__blacklist = None
self.__default_providers = {}
self.__missing_default_provider_is_an_error = rospy.get_param('~missing_default_provider_is_an_error', False)

def spin(self):
"""Starts the capability server by setting up ROS comms, then spins"""
self.__package_whitelist = rospy.get_param('~package_whitelist', None)
if not isinstance(self.__package_whitelist, (list, tuple, type(None))):
msg = "~package_whitelist must be a list or null, got a '{0}'".format(type(self.__whitelist))
rospy.logerr(msg)
self.__package_whitelist = None
self.__package_blacklist = rospy.get_param('~package_blacklist', None)
if not isinstance(self.__package_blacklist, (list, tuple, type(None))):
msg = "~package_blacklist must be a list or null, got a '{0}'".format(type(self.__whitelist))
rospy.logerr(msg)
self.__package_blacklist = None
self.__whitelist = rospy.get_param('~whitelist', None)
if not isinstance(self.__whitelist, (list, tuple, type(None))):
msg = "~whitelist must be a list or null, got a '{0}'".format(type(self.__whitelist))
rospy.logerr(msg)
self.__whitelist = None
self.__blacklist = rospy.get_param('~blacklist', None)
if not isinstance(self.__blacklist, (list, tuple, type(None))):
msg = "~blacklist must be a list or null, got a '{0}'".format(type(self.__blacklist))
rospy.logerr(msg)
self.__blacklist = None
self.__debug = rospy.get_param('~debug', False)
if self.__debug:
logger = logging.getLogger('rosout')
Expand Down Expand Up @@ -327,11 +351,41 @@ def shutdown(self):
def __load_capabilities(self):
package_index = package_index_from_package_path(self.__package_paths)
self.spec_file_index = spec_file_index_from_package_index(package_index)
# Prune packages by black and white list
for package in self.spec_file_index.keys():
if self.__package_whitelist and package not in self.__package_whitelist:
rospy.loginfo("Package '{0}' not in whitelist, skipping.".format(package))
del self.spec_file_index[package]
if self.__package_blacklist and package in self.__package_blacklist:
rospy.loginfo("Package '{0}' in blacklist, skipping.".format(package))
del self.spec_file_index[package]
# Generate spec_index from spec file index
spec_index, errors = spec_index_from_spec_file_index(self.spec_file_index)
if errors:
rospy.logerr("Errors were encountered loading capabilities:")
for error in errors:
rospy.logerr(" " + str(error.__class__.__name__) + ": " + str(error))
# Prune specific capabilities based on black and white lists
removed_interfaces = []
for specs, remove_func in [
(spec_index.interfaces, spec_index.remove_interface),
(spec_index.semantic_interfaces, spec_index.remove_semantic_interface),
(spec_index.providers, spec_index.remove_provider)
]:
for spec in specs.keys():
if self.__whitelist and spec not in self.__whitelist:
removed_interfaces.append(spec)
remove_func(spec)
rospy.loginfo("Spec '{0}' is not in the whitelist, skipping.".format(spec))
if self.__blacklist and spec in self.__blacklist:
removed_interfaces.append(spec)
remove_func(spec)
rospy.loginfo("Spec '{0}' is in the blacklist, skipping.".format(spec))
# Remove providers which no longer have an interface
for interface in removed_interfaces:
for provider in spec_index.providers.values():
if provider.implements == interface:
spec_index.remove_provider(provider.name)
self.__spec_index = spec_index

def __populate_default_providers(self):
Expand Down
1 change: 0 additions & 1 deletion test/rostest/test_server/test_invalid_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,5 @@ def test_event_handler(self):
rospy.sleep(1) # Allow time for the publish to happen

if __name__ == '__main__':
import rospy
rospy.init_node(TEST_NAME, anonymous=True)
rostest.unitrun('capabilities', TEST_NAME, Test)
33 changes: 33 additions & 0 deletions test/rostest/test_server/test_package_white_black_lists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python

from __future__ import print_function

import unittest

import rostest

import rospy

from rosservice import get_service_class_by_name

TEST_NAME = 'test_white_black_list'


def call_service(service_name, *args, **kwargs):
rospy.wait_for_service(service_name)
service_type = get_service_class_by_name(service_name)
proxy = rospy.ServiceProxy(service_name, service_type)
return proxy(*args, **kwargs)


class Test(unittest.TestCase):
def test_introspection_services(self):
# get interafaces
resp = call_service('/capability_server/get_interfaces')
assert 'minimal_pkg/Minimal' not in resp.interfaces, resp
assert 'navigation_capability/Navigation' in resp.interfaces, resp
assert 'differential_mobile_base_capability/DifferentialMobileBase' not in resp.interfaces, resp

if __name__ == '__main__':
rospy.init_node(TEST_NAME, anonymous=True)
rostest.unitrun('capabilities', TEST_NAME, Test)
16 changes: 16 additions & 0 deletions test/rostest/test_server/test_package_white_black_lists.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<launch>
<node pkg="capabilities" name="capability_server" type="capability_server" output="screen" required="true"
launch-prefix="coverage run --append ">
<param name="debug" value="true"/>
<env name="ROS_PACKAGE_PATH"
value="$(find capabilities)/test/unit/discovery_workspaces/minimal:$(find capabilities)/test/rostest/test_server/dependent_capabilities:$(env ROS_PACKAGE_PATH)" />
<rosparam param="package_whitelist">
- navigation_capability
- differential_mobile_base_capability
</rosparam>
<rosparam param="package_blacklist">
- differential_mobile_base_capability
</rosparam>
</node>
<test test-name="white_black_lists_tests" pkg="capabilities" type="test_white_black_lists.py"/>
</launch>
12 changes: 12 additions & 0 deletions test/rostest/test_server/test_ros_services.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
<param name="debug" value="true"/>
<env name="ROS_PACKAGE_PATH"
value="$(find capabilities)/test/unit/discovery_workspaces/minimal:$(find capabilities)/test/rostest/test_server/no_provider:$(env ROS_PACKAGE_PATH)" />
<rosparam param="package_whitelist">
'invalid'
</rosparam>
<rosparam param="package_blacklist">
'invalid'
</rosparam>
<rosparam param="whitelist">
'invalid'
</rosparam>
<rosparam param="blacklist">
'invalid'
</rosparam>
</node>
<test test-name="ros_services" pkg="capabilities" type="test_ros_services.py"/>
</launch>
33 changes: 33 additions & 0 deletions test/rostest/test_server/test_white_black_lists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python

from __future__ import print_function

import unittest

import rostest

import rospy

from rosservice import get_service_class_by_name

TEST_NAME = 'test_white_black_list'


def call_service(service_name, *args, **kwargs):
rospy.wait_for_service(service_name)
service_type = get_service_class_by_name(service_name)
proxy = rospy.ServiceProxy(service_name, service_type)
return proxy(*args, **kwargs)


class Test(unittest.TestCase):
def test_introspection_services(self):
# get interafaces
resp = call_service('/capability_server/get_interfaces')
assert 'minimal_pkg/Minimal' not in resp.interfaces, resp
assert 'navigation_capability/Navigation' in resp.interfaces, resp
assert 'differential_mobile_base_capability/DifferentialMobileBase' not in resp.interfaces, resp

if __name__ == '__main__':
rospy.init_node(TEST_NAME, anonymous=True)
rostest.unitrun('capabilities', TEST_NAME, Test)
17 changes: 17 additions & 0 deletions test/rostest/test_server/test_white_black_lists.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<launch>
<node pkg="capabilities" name="capability_server" type="capability_server" output="screen" required="true"
launch-prefix="coverage run --append ">
<param name="debug" value="true"/>
<env name="ROS_PACKAGE_PATH"
value="$(find capabilities)/test/unit/discovery_workspaces/minimal:$(find capabilities)/test/rostest/test_server/dependent_capabilities:$(env ROS_PACKAGE_PATH)" />
<rosparam param="whitelist">
- navigation_capability/Navigation
- differential_mobile_base_capability/DifferentialMobileBase
- differential_mobile_base_capability/faux_differential_mobile_base
</rosparam>
<rosparam param="blacklist">
- differential_mobile_base_capability/DifferentialMobileBase
</rosparam>
</node>
<test test-name="white_black_lists_tests" pkg="capabilities" type="test_white_black_lists.py"/>
</launch>

0 comments on commit da4d263

Please sign in to comment.