diff --git a/src/config/common/tests/test_utils.py b/src/config/common/tests/test_utils.py index 9eac0797cd8..be68e385b38 100644 --- a/src/config/common/tests/test_utils.py +++ b/src/config/common/tests/test_utils.py @@ -88,6 +88,10 @@ def get_keyspace_properties(self, ks_name): def create_column_family(self, *args, **kwargs): pass + def drop_keyspace(self, ks_name): + if name in self._keyspaces: + self._keyspaces.remove(name) + class CassandraCFs(object): _all_cfs = {} @@ -102,7 +106,12 @@ def get_cf(cls, name): # end get_cf @classmethod - def reset(cls): + def reset(cls, cf_list=None): + if cf_list: + for name in cf_list: + if name in cls._all_cfs: + del cls._all_cfs[name] + return cls._all_cfs = {} # end CassandraCFs diff --git a/src/discovery/disc_server.py b/src/discovery/disc_server.py index 85e9268df9e..0cacd56acd2 100644 --- a/src/discovery/disc_server.py +++ b/src/discovery/disc_server.py @@ -650,21 +650,17 @@ def match_subscriber(self, dsa_rule, sub): return True, match_len return False, 0 - def match_publishers(self, dsa_rule, pubs): + def match_publishers(self, rule_list, pubs): result = [] - rule_pub = dsa_rule['publisher'] for pub in pubs: - # include publisher if rule not relevant - if rule_pub['ep_type'] != pub['ep_type']: - result.append(pub) - continue - match, mlen = self.match_dsa_rule_ep(rule_pub, pub) - if match: - result.append(pub) + for dsa_rule in rule_list: + ok, pfxlen = self.match_dsa_rule_ep(dsa_rule['publisher'], pub) + if ok: + result.append(pub) return result - def apply_dsa_config(self, pubs, sub): + def apply_dsa_config(self, service_type, pubs, sub): if len(pubs) == 0: return pubs @@ -674,23 +670,31 @@ def apply_dsa_config(self, pubs, sub): # self.syslog('dsa: rules %s' % dsa_rules) lpm = -1 - matched_sub_rule = None + matched_rules = None for rule in dsa_rules: + # ignore rule if publisher not relevant + if rule['publisher']['ep_type'] != service_type: + continue + + # ignore rule if subscriber doesn't match matched, matched_len = self.match_subscriber(rule, sub) if not matched: continue self.syslog('dsa: matched sub %s' % sub) + # collect matched rules if matched_len > lpm: lpm = matched_len - matched_sub_rule = rule + matched_rules = [rule] + elif matched_len == lpm: + matched_rules.append(rule) # end for # return original list if there is no sub match - if not matched_sub_rule: + if not matched_rules: return pubs - matched_pubs = self.match_publishers(matched_sub_rule, pubs) + matched_pubs = self.match_publishers(matched_rules, pubs) self.syslog('dsa: matched pubs %s' % matched_pubs) return matched_pubs @@ -767,7 +771,7 @@ def api_subscribe(self): # send short ttl if no publishers pubs = self._db_conn.lookup_service(service_type) or [] pubs_active = [item for item in pubs if not self.service_expired(item)] - pubs_active = self.apply_dsa_config(pubs_active, cl_entry) + pubs_active = self.apply_dsa_config(service_type, pubs_active, cl_entry) pubs_active = self.service_list(service_type, pubs_active) plist = dict((entry['service_id'],entry) for entry in pubs_active) plist_all = dict((entry['service_id'],entry) for entry in pubs) diff --git a/src/discovery/tests/test_case.py b/src/discovery/tests/test_case.py index 6a740657075..51a0c999de9 100644 --- a/src/discovery/tests/test_case.py +++ b/src/discovery/tests/test_case.py @@ -67,7 +67,7 @@ def setUp(self, extra_disc_server_config_knobs = None, def tearDown(self): - test_utils.CassandraCFs.reset() + test_utils.CassandraCFs.reset(cf_list=['discovery']) test_common.kill_disc_server(self._disc_server_greenlet) super(DsTestCase, self).tearDown() diff --git a/src/discovery/tests/test_dsa.py b/src/discovery/tests/test_dsa.py index c96ff5b3058..801dbcea80d 100644 --- a/src/discovery/tests/test_dsa.py +++ b/src/discovery/tests/test_dsa.py @@ -68,6 +68,113 @@ def info_callback(info): class TestDsa(test_case.DsTestCase): + def test_bug_1548771(self): + dsa = DiscoveryServiceAssignment() + rule_entry = build_dsa_rule_entry('77.77.3.0/24,xmpp-server 77.77.0.0/16,contrail-vrouter-agent:0') + rule_uuid = uuid.uuid4() + dsa_rule1 = DsaRule(name = str(rule_uuid), parent_obj = dsa, dsa_rule_entry = rule_entry) + dsa_rule1.set_uuid(str(rule_uuid)) + self._vnc_lib.dsa_rule_create(dsa_rule1) + + rule_entry = build_dsa_rule_entry('77.77.3.0/24,dns-server 77.77.3.11/32,contrail-vrouter-agent:0') + rule_uuid = uuid.uuid4() + dsa_rule2 = DsaRule(name = str(rule_uuid), parent_obj = dsa, dsa_rule_entry = rule_entry) + dsa_rule2.set_uuid(str(rule_uuid)) + self._vnc_lib.dsa_rule_create(dsa_rule2) + + puburl = '/publish' + suburl = "/subscribe" + + # publish 3 control nodes and dns servers + for service_type in ['xmpp-server', 'dns-server']: + for ipaddr in ["77.77.1.10", "77.77.2.10", "77.77.3.10"]: + payload = { + service_type: { "ip-addr" : ipaddr, "port" : "1111" }, + 'service-type' : '%s' % service_type, + 'service-id' : '%s-%s' % (service_type, ipaddr), + 'remote-addr': ipaddr, + } + (code, msg) = self._http_post(puburl, json.dumps(payload)) + self.assertEqual(code, 200) + + # Verify all services are published. + (code, msg) = self._http_get('/services.json') + self.assertEqual(code, 200) + response = json.loads(msg) + self.assertEqual(len(response['services']), 6) + + # verify all agents see only 1 xmpp-server (rule #1) + service_type = 'xmpp-server' + expectedpub_set = set(["xmpp-server-77.77.3.10"]) + for ipaddr in ["77.77.1.11", "77.77.2.11", "77.77.3.11"]: + payload = { + 'service' : '%s' % service_type, + 'client' : '%s-%s' % (service_type, ipaddr), + 'instances' : 2, + 'client-type' : 'contrail-vrouter-agent:0', + 'remote-addr' : ipaddr, + } + (code, msg) = self._http_post(suburl, json.dumps(payload)) + self.assertEqual(code, 200) + response = json.loads(msg) + self.assertEqual(len(response[service_type]), 1) + receivedpub_set = set([svc['@publisher-id'] for svc in response[service_type]]) + self.assertEqual(expectedpub_set == receivedpub_set, True) + + self._vnc_lib.dsa_rule_delete(id = dsa_rule1.get_uuid()) + self._vnc_lib.dsa_rule_delete(id = dsa_rule2.get_uuid()) + + def test_bug_1540777(self): + dsa = DiscoveryServiceAssignment() + + rule_entry = build_dsa_rule_entry('77.77.3.10/32,pulkit-pub 77.77.3.11/32,pulkit-sub') + rule_uuid = uuid.uuid4() + dsa_rule1 = DsaRule(name = str(rule_uuid), parent_obj = dsa, dsa_rule_entry = rule_entry) + dsa_rule1.set_uuid(str(rule_uuid)) + self._vnc_lib.dsa_rule_create(dsa_rule1) + + rule_entry = build_dsa_rule_entry('77.77.2.10/32,pulkit-pub 77.77.3.11/32,pulkit-sub') + rule_uuid = uuid.uuid4() + dsa_rule2 = DsaRule(name = str(rule_uuid), parent_obj = dsa, dsa_rule_entry = rule_entry) + dsa_rule2.set_uuid(str(rule_uuid)) + self._vnc_lib.dsa_rule_create(dsa_rule2) + + puburl = '/publish' + suburl = "/subscribe" + service_type = 'pulkit-pub' + + # publish 3 control nodes - 2 subject to rules above + for ipaddr in ["77.77.1.10", "77.77.2.10", "77.77.3.10"]: + payload = { + service_type: { "ip-addr" : ipaddr, "port" : "1111" }, + 'service-type' : '%s' % service_type, + 'service-id' : 'pulkit-pub-%s' % ipaddr, + 'remote-addr': ipaddr, + } + (code, msg) = self._http_post(puburl, json.dumps(payload)) + self.assertEqual(code, 200) + + payload = { + 'service' : '%s' % service_type, + 'client' : 'discovery-ut', + 'instances' : 3, + 'client-type' : 'pulkit-sub', + 'remote-addr' : '77.77.3.11', + } + + # should see 2 publishers due to two rules + (code, msg) = self._http_post(suburl, json.dumps(payload)) + self.assertEqual(code, 200) + response = json.loads(msg) + self.assertEqual(len(response[service_type]), 2) + + expectedpub_set = set(["pulkit-pub-77.77.2.10", "pulkit-pub-77.77.3.10"]) + receivedpub_set = set([svc['@publisher-id'] for svc in response[service_type]]) + self.assertEqual(expectedpub_set == receivedpub_set, True) + + self._vnc_lib.dsa_rule_delete(id = dsa_rule1.get_uuid()) + self._vnc_lib.dsa_rule_delete(id = dsa_rule2.get_uuid()) + def test_dsa_config(self): # Assign DC1 control nodes to DC1 agents rule_entry = build_dsa_rule_entry('1.1.1.0/24,Control-Node 1.1.1.0/24,Vrouter-Agent') @@ -167,11 +274,9 @@ def test_dsa_config(self): for svc in response[service_type]: self.assertEqual("DC2-CN" in svc['@publisher-id'], True) - """ - Subscribe to IfmapServer from DC1, DC2 and DC3. There are no - assignment rules applicable to IfmapServer. Thus clients from - all DC should be able to subscribe to singtleton IfmapServer - """ + # Subscribe to IfmapServer from DC1, DC2 and DC3. There are no + # assignment rules applicable to IfmapServer. Thus clients from + # all DC should be able to subscribe to singtleton IfmapServer service_type = 'IfmapServer' payload = { service_type: { "ip-addr" : "4.4.4.4", "port" : "4444" }, @@ -195,10 +300,8 @@ def test_dsa_config(self): response = json.loads(msg) self.assertEqual(len(response[service_type]), 1) - """ - Delete service assignment rule. - Subs from any DC should see all DC1+DC2 services - """ + # Delete service assignment rule. + # Subs from any DC should see all DC1+DC2 services self._vnc_lib.dsa_rule_delete(id = dsa_rule1.uuid) self._vnc_lib.dsa_rule_delete(id = dsa_rule2.uuid)