def test_merge_machine(): s = SDNConnect() old_machine = {'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '0.0.0.0', 'ipv6': '1212::1'} new_machine = {'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '', 'ipv6': ''} s.merge_machine_ip(old_machine, new_machine) assert old_machine['ipv4'] == new_machine['ipv4'] assert new_machine['ipv6'] == new_machine['ipv6']
def __init__(self): self.logger = logger self.faucet_event = [] self.controller = Config().get_config() self.controller['max_concurrent_reinvestigations'] = 10 self.s = SDNConnect() if 'POSEIDON_TRAVIS' in os.environ: self.s.r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True) endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1'} endpoint.mirror() endpoint.known() self.s.endpoints.append(endpoint) endpoint = Endpoint('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1'} endpoint.mirror() endpoint.known() self.s.endpoints.append(endpoint) self.s.store_endpoints() self.s.get_stored_endpoints()
def __init__(self): self.logger = logger self.faucet_event = [] self.controller = Config().get_config() self.controller['max_concurrent_reinvestigations'] = 10 self.s = SDNConnect(self.controller) endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.known() self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.known() self.s.endpoints[endpoint.name] = endpoint self.s.store_endpoints() self.s.get_stored_endpoints()
def test_remove_endpoint(): s = SDNConnect() endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00'} s.endpoints.append(endpoint) s.remove_endpoint(endpoint)
def __init__(self): self.states = [ 'active', 'inactive', 'known', 'unknown', 'mirroring', 'abnormal', 'shutdown', 'reinvestigating', 'queued' ] self.sdnc = SDNConnect() self.sdnc.get_stored_endpoints()
class MockMonitor(Monitor): def __init__(self): self.logger = logger self.fa_rabbit_routing_key = 'FAUCET.Event' self.faucet_event = None self.controller = Config().get_config() self.s = SDNConnect(self.controller) self.s.controller['TYPE'] = 'None' self.s.get_sdn_context() self.s.controller['TYPE'] = 'bcf' self.s.get_sdn_context() self.s.controller['TYPE'] = 'faucet' self.s.get_sdn_context() self.job_queue = queue.Queue() self.m_queue = queue.Queue() endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.p_next_state = 'mirror' endpoint.queue() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo3') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } self.s.endpoints[endpoint.name] = endpoint self.s.store_endpoints() self.s.get_stored_endpoints() self.results = 0 def get_q_item(self, q, timeout=1): if not self.results: self.results += 1 return (True, ('foo', {'data': {}})) return (False, None) def bad_get_q_item(self, q, timeout=1): return (False, ('bar', {'data': {}})) def format_rabbit_message(self, item): return ({'data': {}}, False)
def __init__(self): self.states = [ 'active', 'inactive', 'known', 'unknown', 'mirroring', 'abnormal', 'shutdown', 'reinvestigating', 'queued' ] self.controller = Config().get_config() self.sdnc = SDNConnect(self.controller, first_time=False) self.sdnc.get_stored_endpoints()
class MockMonitor(Monitor): def __init__(self): self.logger = logger self.fa_rabbit_routing_key = 'FAUCET.Event' self.faucet_event = None self.controller = Config().get_config() self.s = SDNConnect(self.controller) self.s.controller['TYPE'] = 'None' self.s.get_sdn_context() self.s.controller['TYPE'] = 'bcf' self.s.get_sdn_context() self.s.controller['TYPE'] = 'faucet' self.s.get_sdn_context() if 'POSEIDON_TRAVIS' in os.environ: self.s.r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True) endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.p_next_state = 'mirror' endpoint.queue() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo3') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } self.s.endpoints[endpoint.name] = endpoint self.s.store_endpoints() self.s.get_stored_endpoints() def get_q_item(self): return (True, ('foo', {'data': {}})) def bad_get_q_item(self): return (False, ('bar', {'data': {}})) def format_rabbit_message(self, item): return ({'data': {}}, False)
def test_endpoint_by_name(): s = SDNConnect() endpoint = s.endpoint_by_name('foo') assert endpoint == None endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1'} s.endpoints[endpoint.name] = endpoint endpoint2 = s.endpoint_by_name('foo') assert endpoint == endpoint2
def test_endpoints_by_mac(): s = SDNConnect() endpoints = s.endpoints_by_mac('00:00:00:00:00:01') assert endpoints == [] endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1'} s.endpoints.append(endpoint) endpoint2 = s.endpoints_by_mac('00:00:00:00:00:00') assert [endpoint] == endpoint2
def test_endpoints_by_ip(): s = SDNConnect() endpoints = s.endpoints_by_ip('10.0.0.1') assert endpoints == [] endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '10.0.0.1', 'ipv6': 'None'} s.endpoints.append(endpoint) endpoint2 = s.endpoints_by_ip('10.0.0.1') assert [endpoint] == endpoint2
def test_endpoint_by_hash(): s = SDNConnect() endpoint = s.endpoint_by_hash('foo') assert endpoint == None endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1'} s.endpoints.append(endpoint) endpoint2 = s.endpoint_by_hash('foo') assert endpoint == endpoint2
def test_find_new_machines(): s = SDNConnect() machines = [{'active': 0, 'source': 'poseidon', 'role': 'unknown', 'state': 'unknown', 'ipv4_os': 'unknown', 'tenant': 'vlan1', 'port': 1, 'segment': 'switch1', 'ipv4': '123.123.123.123', 'mac': '00:00:00:00:00:00', 'id': 'foo1', 'behavior': 1}, {'active': 1, 'source': 'poseidon', 'role': 'unknown', 'state': 'unknown', 'ipv4_os': 'unknown', 'tenant': 'vlan1', 'port': 1, 'segment': 'switch1', 'ipv4': '123.123.123.123', 'mac': '00:00:00:00:00:00', 'id': 'foo2', 'behavior': 1}, {'active': 0, 'source': 'poseidon', 'role': 'unknown', 'state': 'unknown', 'ipv4_os': 'unknown', 'tenant': 'vlan1', 'port': 1, 'segment': 'switch1', 'ipv4': '123.123.123.123', 'mac': '00:00:00:00:00:00', 'id': 'foo3', 'behavior': 1}, {'active': 1, 'source': 'poseidon1', 'role': 'unknown', 'state': 'unknown', 'ipv4_os': 'unknown', 'tenant': 'vlan1', 'port': 2, 'segment': 'switch1', 'ipv4': '2106::1', 'mac': '00:00:00:00:00:00', 'id': 'foo4', 'behavior': 1}, {'active': 1, 'source': 'poseidon', 'role': 'unknown', 'state': 'unknown', 'ipv4_os': 'unknown', 'tenant': 'vlan1', 'port': 1, 'segment': 'switch1', 'ipv4': '::', 'mac': '00:00:00:00:00:00', 'id': 'foo5', 'behavior': 1}] s.find_new_machines(machines)
def test_unmirror_endpoint(): controller = Config().get_config() s = SDNConnect(controller) endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s.endpoints[endpoint.name] = endpoint s.unmirror_endpoint(endpoint)
def test_endpoint_by_name(): controller = Config().get_config() s = SDNConnect(controller) endpoint = s.endpoint_by_name('foo') assert endpoint == None endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s.endpoints[endpoint.name] = endpoint endpoint2 = s.endpoint_by_name('foo') assert endpoint == endpoint2
def test_endpoints_by_mac(): controller = get_test_controller() s = SDNConnect(controller) endpoints = s.endpoints_by_mac('00:00:00:00:00:01') assert endpoints == [] endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s.endpoints[endpoint.name] = endpoint endpoint2 = s.endpoints_by_mac('00:00:00:00:00:00') assert [endpoint] == endpoint2
def __init__(self): self.logger = logger self.fa_rabbit_routing_key = 'FAUCET.Event' self.faucet_event = None self.controller = Config().get_config() self.s = SDNConnect() self.s.controller['TYPE'] = 'None' self.s.get_sdn_context() self.s.controller['TYPE'] = 'bcf' self.s.get_sdn_context() self.s.controller['TYPE'] = 'faucet' self.s.get_sdn_context() if 'POSEIDON_TRAVIS' in os.environ: self.s.r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True) endpoint = Endpoint('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints.append(endpoint) endpoint = Endpoint('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.p_next_state = 'mirror' endpoint.queue() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints.append(endpoint) endpoint = Endpoint('foo3') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } self.s.endpoints.append(endpoint) self.s.store_endpoints() self.s.get_stored_endpoints()
def test_Actions_nosdn(): """ Tests Actions with no SDN controller """ endpoint = Endpoint('foo') endpoint.endpoint_data = { 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s = SDNConnect() s.sdnc = None a = Actions(endpoint, s.sdnc) a.mirror_endpoint() a.unmirror_endpoint() a.shutdown_endpoint()
def __init__(self): self.fa_rabbit_routing_key = 'foo' self.logger = logger self.controller = Config().get_config() self.s = SDNConnect(self.controller) self.faucet_event = [] self.s.sdnc = MockParser()
def test_endpoints_by_ip(): controller = Config().get_config() s = SDNConnect(controller) endpoints = s.endpoints_by_ip('10.0.0.1') assert endpoints == [] endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '10.0.0.1', 'ipv6': 'None' } s.endpoints[endpoint.name] = endpoint endpoint2 = s.endpoints_by_ip('10.0.0.1') assert [endpoint] == endpoint2
def __init__(self): self.logger = logger self.fa_rabbit_routing_key = 'FAUCET.Event' self.faucet_event = None self.controller = Config().get_config() self.s = SDNConnect(self.controller) self.s.controller['TYPE'] = 'None' self.s.get_sdn_context() self.s.controller['TYPE'] = 'bcf' self.s.get_sdn_context() self.s.controller['TYPE'] = 'faucet' self.s.get_sdn_context() self.job_queue = queue.Queue() self.m_queue = queue.Queue() endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.mirror() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo2') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } endpoint.p_next_state = 'mirror' endpoint.queue() endpoint.p_prev_states.append((endpoint.state, int(time.time()))) self.s.endpoints[endpoint.name] = endpoint endpoint = endpoint_factory('foo3') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } self.s.endpoints[endpoint.name] = endpoint self.s.store_endpoints() self.s.get_stored_endpoints() self.results = 0
def test_Actions_nosdn(): """ Tests Actions with no SDN controller """ endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } controller = Config().get_config() s = SDNConnect(controller) s.sdnc = None a = Actions(endpoint, s.sdnc) a.mirror_endpoint() a.unmirror_endpoint() a.coprocess_endpoint() a.uncoprocess_endpoint() a.shutdown_endpoint()
def test_Actions(): """ Tests Actions """ endpoint = Endpoint('foo') endpoint.endpoint_data = {'mac': '00:00:00:00:00:00'} s = SDNConnect() a = Actions(endpoint, s.sdnc) a.mirror_endpoint() a.unmirror_endpoint() a.shutdown_endpoint()
def test_parse_metadata(): controller = Config().get_config() s = SDNConnect(controller) mac_info = { b'poseidon_hash': 'myhash', } ml_info = { b'labels': b'["foo", "bar"]', b'confidences': b'[1.0, 2.0]', 'myhash': b'{"pcap_labels": "mylabels", "decisions": {"behavior": "definitely"}}', } assert s.parse_metadata(mac_info, ml_info) == { 'behavior': 'None', 'confidences': [1.0, 2.0], 'labels': ['foo', 'bar'], 'pcap_labels': 'mylabels', 'behavior': 'definitely' }
def test_update_history(): endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '0.0.0.0', 'ipv6': '1212::1' } endpoint.metadata = { 'mac_addresses': { '00:00:00:00:00:00': { '1551805502': { 'labels': ['developer workstation'], 'behavior': 'normal' } } }, 'ipv4_addresses': { '0.0.0.0': { 'os': 'windows' } }, 'ipv6_addresses': { '1212::1': { 'os': 'windows' } } } controller = Config().get_config() s = SDNConnect(controller) s.endpoints[endpoint.name] = endpoint metadata = {123: {'behavior': 'normal'}} s.update_history(endpoint, {'00:00:00:00:00:00': metadata}, {'0.0.0.0': metadata}, {'1212::1': metadata})
def test_Actions(): """ Tests Actions """ endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } controller = Config().get_config() s = SDNConnect(controller) a = Actions(endpoint, s.sdnc) a.mirror_endpoint() a.unmirror_endpoint() a.shutdown_endpoint()
def test_clear_filters(): controller = get_test_controller() s = SDNConnect(controller) endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s.endpoints[endpoint.name] = endpoint s.clear_filters() controller = get_test_controller() s = SDNConnect(controller) endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1' } s.endpoints[endpoint.name] = endpoint s.clear_filters()
class Commands: def __init__(self): self.states = [ 'active', 'inactive', 'known', 'unknown', 'mirroring', 'abnormal', 'shutdown', 'reinvestigating', 'queued' ] self.sdnc = SDNConnect() self.sdnc.get_stored_endpoints() def _get_endpoints(self, args, idx): ''' get endpoints that match ''' eps = [] device = args.rsplit(' ', 1)[idx] name_endpoint = self.sdnc.endpoint_by_name(device) if name_endpoint: eps.append(name_endpoint) return eps hash_endpoint = self.sdnc.endpoint_by_hash(device) if hash_endpoint: eps.append(hash_endpoint) return eps ip_endpoints = self.sdnc.endpoints_by_ip(device) if len(ip_endpoints) > 0: return ip_endpoints mac_endpoints = self.sdnc.endpoints_by_mac(device) if len(mac_endpoints) > 0: return mac_endpoints return eps def what_is(self, args): ''' what is a specific thing ''' endpoints = [] eps = self._get_endpoints(args, -1) for endpoint in eps: if endpoint: endpoints.append(endpoint) return endpoints def history_of(self, args): ''' history of a specific thing ''' endpoints = [] eps = self._get_endpoints(args, -1) for endpoint in eps: if endpoint: endpoints.append(endpoint) return endpoints def where_is(self, args): ''' where topologically is a specific thing ''' endpoints = [] eps = self._get_endpoints(args, -1) for endpoint in eps: if endpoint: endpoints.append(endpoint) return endpoints def remove_inactives(self, args): ''' remove all inactive devices ''' endpoints = [] endpoint_names = [] for endpoint in self.sdnc.endpoints: if endpoint.state == 'inactive': endpoints.append(endpoint) endpoint_names.append(endpoint.name) self.sdnc.publish_action('poseidon.action.remove.inactives', json.dumps(endpoint_names)) return endpoints def remove_ignored(self, args): ''' remove all ignored devices ''' endpoints = [] endpoint_names = [] for endpoint in self.sdnc.endpoints: if endpoint.ignore == True: endpoints.append(endpoint) endpoint_names.append(endpoint.name) self.sdnc.publish_action('poseidon.action.remove.ignored', json.dumps(endpoint_names)) return endpoints def ignore(self, args): ''' ignore a specific thing ''' eps = [] device = args.rsplit(' ', 1)[0] if device == 'inactive': for endpoint in self.sdnc.endpoints: if endpoint.state == 'inactive': eps.append(endpoint) else: eps.append(self.sdnc.endpoint_by_name(device)) eps.append(self.sdnc.endpoint_by_hash(device)) eps += self.sdnc.endpoints_by_ip(device) eps += self.sdnc.endpoints_by_mac(device) endpoints = [] endpoint_names = [] for endpoint in eps: if endpoint: endpoints.append(endpoint) endpoint_names.append(endpoint.name) self.sdnc.publish_action('poseidon.action.ignore', json.dumps(endpoint_names)) return endpoints def clear_ignored(self, args): ''' stop ignoring a specific thing ''' eps = [] device = args.rsplit(' ', 1)[0] if device == 'ignored': for endpoint in self.sdnc.endpoints: if endpoint.ignore: eps.append(endpoint) else: eps.append(self.sdnc.endpoint_by_name(device)) eps.append(self.sdnc.endpoint_by_hash(device)) eps += self.sdnc.endpoints_by_ip(device) eps += self.sdnc.endpoints_by_mac(device) endpoints = [] endpoint_names = [] for endpoint in eps: if endpoint: endpoints.append(endpoint) endpoint_names.append(endpoint.name) self.sdnc.publish_action('poseidon.action.clear.ignored', json.dumps(endpoint_names)) return endpoints def remove(self, args): ''' remove and forget about a specific thing until it's seen again ''' endpoints = [] endpoint_names = [] eps = self._get_endpoints(args, 0) for endpoint in eps: if endpoint: endpoints.append(endpoint) endpoint_names.append(endpoint.name) self.sdnc.publish_action('poseidon.action.remove', json.dumps(endpoint_names)) return endpoints def show_devices(self, arg): ''' show all devices that are of a specific filter. i.e. windows, developer workstation, abnormal, mirroring, etc. ''' return self.sdnc.show_endpoints(arg) def change_devices(self, args): ''' change state of a specific thing ''' eps = [] endpoints = [] endpoint_names = [] device = args.split(' ', 1)[0] state = args.rsplit(' ', 1)[-1] eps.append(self.sdnc.endpoint_by_name(device)) eps.append(self.sdnc.endpoint_by_hash(device)) eps += self.sdnc.endpoints_by_ip(device) eps += self.sdnc.endpoints_by_mac(device) for endpoint in eps: if endpoint: endpoints.append(endpoint) endpoint_names.append((endpoint.name, state)) self.sdnc.publish_action('poseidon.action.change', json.dumps(endpoint_names)) return endpoints
def test_check_endpoints(): controller = Config().get_config() s = SDNConnect(controller) s.sdnc = None s.check_endpoints()
def test_show_endpoints(): endpoint = endpoint_factory('foo') endpoint.endpoint_data = { 'tenant': 'foo', 'mac': '00:00:00:00:00:00', 'segment': 'foo', 'port': '1', 'ipv4': '0.0.0.0', 'ipv6': '1212::1' } endpoint.metadata = { 'mac_addresses': { '00:00:00:00:00:00': { '1551805502': { 'labels': ['developer workstation'], 'behavior': 'normal' } } }, 'ipv4_addresses': { '0.0.0.0': { 'os': 'windows' } }, 'ipv6_addresses': { '1212::1': { 'os': 'windows' } } } controller = Config().get_config() s = SDNConnect(controller) s.endpoints[endpoint.name] = endpoint s.show_endpoints('all') s.show_endpoints('state active') s.show_endpoints('state ignored') s.show_endpoints('state unknown') s.show_endpoints('os windows') s.show_endpoints('role developer-workstation') s.show_endpoints('behavior normal')