def test_create_dns_zone_with_grid_secondaries(self): dns_view_name = 'dns-view-name' fqdn = 'host.global.com' primary_dns_members = [objects.AnyMember(name='member_primary', _struct='memberserver')] secondary_dns_members = [objects.AnyMember(name='member_secondary', _struct='memberserver')] zone_format = 'IPV4' connector = mock.Mock() connector.get_object.return_value = None ibom = om.InfobloxObjectManager(connector) zone = ibom.create_dns_zone(dns_view_name, fqdn, primary_dns_members, secondary_dns_members, zone_format=zone_format) matcher = PayloadMatcher({'view': dns_view_name, 'fqdn': fqdn}) connector.get_object.assert_called_once_with('zone_auth', matcher, return_fields=mock.ANY) payload = {'view': dns_view_name, 'fqdn': fqdn, 'zone_format': zone_format, 'grid_primary': [{'name': primary_dns_members[0].name, '_struct': 'memberserver'}], 'grid_secondaries': [{'name': member.name, '_struct': 'memberserver'} for member in secondary_dns_members] } connector.create_object.assert_called_once_with('zone_auth', payload, mock.ANY) self.assertIsInstance(zone, objects.DNSZone)
def test_get_dns_members_with_dhcp_support(self): user_id = 'test user' tenant_id = '90fbad5a098a4b7cb98826128d5b40b3' # prepare network network_name = 'Test Network' network = self.plugin_stub.create_network(tenant_id, network_name) # prepare subnet subnet_name = 'Test Subnet' subnet_cidr = '11.11.1.0/24' subnet = self.plugin_stub.create_subnet(tenant_id, subnet_name, network['id'], subnet_cidr) self.grid_config.dhcp_support = True ib_cxt = self._get_ib_context(user_id, network, subnet) test_authority_member = utils.json_to_obj( 'AuthorityMember', {'member_id': 'member-id', 'member_type': 'GM', 'member_ip': '11.11.1.11', 'member_ipv6': None, 'member_name': 'gm', 'member_status': 'ON', 'member_wapi': '11.11.1.11'}) ib_cxt.mapping.authority_member = test_authority_member test_dhcp_member_1 = utils.json_to_obj( 'DhcpMember', {'member_id': 'member-id', 'member_type': 'REGULAR', 'member_ip': '11.11.1.12', 'member_ipv6': None, 'member_name': 'm1', 'member_status': 'ON', 'member_wapi': '11.11.1.12'}) test_dhcp_member_2 = utils.json_to_obj( 'DhcpMember', {'member_id': 'member-id', 'member_type': 'CPM', 'member_ip': '11.11.1.13', 'member_ipv6': None, 'member_name': 'm2', 'member_status': 'ON', 'member_wapi': '11.11.1.13'}) ib_cxt.mapping.dhcp_members = [test_dhcp_member_1, test_dhcp_member_2] ib_cxt.mapping.dns_members = [test_dhcp_member_1, test_dhcp_member_2] grid_primaries, grid_secondaries = ib_cxt.get_dns_members() expected_primaries = [ ib_objects.AnyMember(_struct='memberserver', name=test_authority_member.member_name)] expected_secondaries = [ ib_objects.AnyMember(_struct='memberserver', name=test_dhcp_member_1.member_name), ib_objects.AnyMember(_struct='memberserver', name=test_dhcp_member_2.member_name)] self.assertEqual(expected_primaries, grid_primaries) self.assertEqual(expected_secondaries, grid_secondaries)
def get_dns_members(self): """Gets the primary and secondary DNS members that serve DNS. DNS has primary DNS member(s) and secondary DNS member(s). A primary DNS member serves both WAPI and DNS protocol so a GM or CP member can be served as primary. A REGULAR member is used as the primary then only DNS protocol is served. A secondary DNS member serves only DNS protocol. For a host record, a primary DNS member must be the same as DHCP member because both DHCP and DNS record writes require that they are under the same parent which is the network view. Secondary DNS member can be any members as long as they are not listed as a primary DNS member since any member can serve DNS protocols. DHCP and DNS member assignments are performed by reserve_service_members already. Here we just need to pick the first member from mapping dns members as the primary and the rest as the secondary if multiple dns members are assigned. If only one dns member is assigned, then no secondary dns server. """ if self.mapping.authority_member is None: raise exc.InfobloxAuthorityMemberNotReserved( network_view=self.mapping.network_view) if self.grid_config.dhcp_support and not self.mapping.dns_members: raise exc.InfobloxDNSMemberNotReserved( network_view=self.mapping.network_view, cidr=self.subnet.get('cidr')) secondary_members = None # authority member needs to be the grid primary always for host record member_name = self.mapping.authority_member.member_name primary_members = [ ib_objects.AnyMember(_struct='memberserver', name=member_name) ] if self.grid_config.dhcp_support: grid_secondaries = [ m for m in self.mapping.dns_members if m.member_name != member_name ] if grid_secondaries: secondary_members = [] for m in grid_secondaries: secondary_members.append( ib_objects.AnyMember(_struct='memberserver', name=m.member_name)) return primary_members, secondary_members
def test_create_dns_zone_creates_zone_auth_object(self): dns_view_name = 'dns-view-name' fqdn = 'host.global.com' member = objects.AnyMember(name='member_name', ip='192.168.1.2', _struct='memberserver') zone_format = 'IPV4' connector = mock.Mock() connector.get_object.return_value = None ibom = om.InfobloxObjectManager(connector) ibom.create_dns_zone(dns_view_name, fqdn, [member], zone_format=zone_format) matcher = PayloadMatcher({'view': dns_view_name, 'fqdn': fqdn}) connector.get_object.assert_called_once_with('zone_auth', matcher, return_fields=mock.ANY) matcher = PayloadMatcher({'view': dns_view_name, 'fqdn': fqdn, 'zone_format': zone_format, 'name': member.name}) connector.create_object.assert_called_once_with('zone_auth', matcher, mock.ANY)
def test_member_is_assigned_as_list_on_network_create(self): net_view = 'net-view-name' cidr = '192.168.1.0/24' nameservers = [] members = [ objects.AnyMember(name='just-a-single-member-ip', ip='192.168.1.25', _struct='dhcpmember') ] gateway_ip = '192.168.1.1' dhcp_trel_ip = '8.8.8.8' extattrs = None expected_payload = { 'members': [{'ipv4addr': '192.168.1.25', '_struct': 'dhcpmember', 'name': 'just-a-single-member-ip'}], 'network_view': net_view, 'network': cidr, 'options': [{'name': 'routers', 'value': gateway_ip}, {'name': 'dhcp-server-identifier', 'value': dhcp_trel_ip, 'num': 54}]} connector = mock.Mock() ibom = om.InfobloxObjectManager(connector) ibom.create_network(net_view, cidr, nameservers, members, gateway_ip, dhcp_trel_ip, extattrs) assert not connector.get_object.called connector.create_object.assert_called_once_with('network', expected_payload, mock.ANY)
def test_get_dhcp_member_ips_from_ib_network(self): connector = mock.Mock() test_ib_network = ib_objects.NetworkV4(connector, network_view='test-view', cidr='12.12.1.0/24') test_ib_network.members = [ ib_objects.AnyMember(_struct='dhcpmember', name='nios-7.2.0-member3.com', ipv4addr='192.168.1.10')] member_ips = utils.get_dhcp_member_ips(test_ib_network) self.assertEqual("192.168.1.10", member_ips[0])
def _test_reserve_service_members_with_ib_network_without_dhcp_member( self, dns_support): user_id = 'test user' tenant_id = '90fbad5a098a4b7cb98826128d5b40b3' # prepare network network_name = 'Test Network' network = self.plugin_stub.create_network(tenant_id, network_name) # prepare subnet subnet_name = 'Test Subnet' subnet_cidr = '11.11.1.0/24' subnet = self.plugin_stub.create_subnet(tenant_id, subnet_name, network['id'], subnet_cidr) self.grid_config.dhcp_support = True self.grid_config.dns_support = dns_support ib_cxt = ib_context.InfobloxContext(self.ctx, user_id, network, subnet, self.grid_config, self.plugin) ib_cxt._register_services = mock.Mock() # ib network with dhcp member and gateway ips assigned connector = mock.Mock() test_ib_network = ib_objects.NetworkV4(connector, network_view='test-view', cidr='12.12.1.0/24') test_ib_network.members = [ ib_objects.AnyMember( _struct='dhcpmember', name=ib_cxt.mapping.authority_member.member_name) ] test_gateway_ip = '12.12.1.1' test_ib_network.options = [ ib_objects.DhcpOption(name='routers', value=test_gateway_ip) ] ib_cxt.reserve_service_members(test_ib_network) expected_dns_members = ([ib_cxt.mapping.authority_member] if dns_support else []) # authority member is CPM, so dhcp/dns member should be the same as # authority member self.assertEqual([ib_cxt.mapping.authority_member], ib_cxt.mapping.dhcp_members) self.assertEqual(expected_dns_members, ib_cxt.mapping.dns_members) actual_opt_router = [ opt for opt in test_ib_network.options if opt.name == 'routers' ] self.assertEqual(subnet['gateway_ip'] + ',' + test_gateway_ip, actual_opt_router[0].value)
def _test_reserve_service_members_with_ib_network_with_dhcp_member( self, test_dhcp_member, dns_support, expected_dns_members): user_id = 'test user' tenant_id = '90fbad5a098a4b7cb98826128d5b40b3' # prepare network network_name = 'Test Network' network = self.plugin_stub.create_network(tenant_id, network_name) # prepare subnet subnet_name = 'Test Subnet' subnet_cidr = '11.11.1.0/24' subnet = self.plugin_stub.create_subnet(tenant_id, subnet_name, network['id'], subnet_cidr) self.grid_config.dhcp_support = True self.grid_config.dns_support = dns_support ib_cxt = ib_context.InfobloxContext(self.ctx, user_id, network, subnet, self.grid_config, self.plugin) ib_cxt._register_services = mock.Mock() ib_cxt._get_dhcp_members = mock.Mock(return_value=[test_dhcp_member]) ib_cxt._get_dns_members = mock.Mock(return_value=[test_dhcp_member]) # ib network with dhcp member assigned connector = mock.Mock() test_ib_network = ib_objects.NetworkV4(connector, network_view='test-view', cidr='12.12.1.0/24') test_ib_network.members = [ ib_objects.AnyMember(_struct='dhcpmember', name=test_dhcp_member.member_name, ipv4addr=test_dhcp_member.member_ip) ] test_ib_network.options = [ ib_objects.DhcpOption(name='domain-name-servers', value=test_dhcp_member.member_ip) ] ib_cxt.reserve_service_members(test_ib_network) self.assertEqual([test_dhcp_member], ib_cxt.mapping.dhcp_members) self.assertEqual(expected_dns_members, ib_cxt.mapping.dns_members) actual_opt_router = [ opt for opt in test_ib_network.options if opt.name == 'routers' ] self.assertEqual(subnet['gateway_ip'], actual_opt_router[0].value)
def _update_service_member_mapping(self): if not self.ib_network: return if not self.grid_config.dhcp_support: return session = self.context.session # dhcp members dhcp_members = self._get_dhcp_members(self.ib_network) if not dhcp_members: return ib_dhcp_members = [] for m in dhcp_members: dhcp_ip = m.member_dhcp_ip or m.member_ip ib_dhcp_members.append( ib_objects.AnyMember(_struct='dhcpmember', name=m.member_name, ipv4addr=dhcp_ip)) # get dns members from ib network if member exists. if not, get them # from service members dns_members = self._get_dns_members(self.ib_network) if not dns_members: dns_members = [] dns_service_members = dbi.get_service_members( session, network_view_id=self.mapping.network_view_id, service=const.SERVICE_TYPE_DNS) for sm in dns_service_members: member = utils.find_one_in_list('member_id', sm.member_id, self.discovered_grid_members) if member: dns_members.append(member) nameservers = self._get_nameservers(dns_members) self.mapping.dhcp_members = dhcp_members self.mapping.dns_members = dns_members self.mapping.ib_dhcp_members = ib_dhcp_members self.mapping.ib_nameservers = nameservers
def test_get_dns_members_without_dhcp_support(self): user_id = 'test user' tenant_id = '90fbad5a098a4b7cb98826128d5b40b3' # prepare network network_name = 'Test Network' network = self.plugin_stub.create_network(tenant_id, network_name) # prepare subnet subnet_name = 'Test Subnet' subnet_cidr = '11.11.1.0/24' subnet = self.plugin_stub.create_subnet(tenant_id, subnet_name, network['id'], subnet_cidr) self.grid_config.dhcp_support = False ib_cxt = ib_context.InfobloxContext(self.ctx, user_id, network, subnet, self.grid_config, self.plugin) test_authority_member = utils.json_to_obj( 'AuthorityMember', { 'member_id': 'member-id', 'member_type': 'GM', 'member_ip': '11.11.1.11', 'member_ipv6': None, 'member_name': 'm1', 'member_status': 'ON', 'member_wapi': '11.11.1.11' }) ib_cxt.mapping.authority_member = test_authority_member grid_primaries, grid_secondaries = ib_cxt.get_dns_members() expected_grid_primaries = [ ib_objects.AnyMember(_struct='memberserver', name=test_authority_member.member_name) ] self.assertEqual(expected_grid_primaries[0].name, grid_primaries[0].name) self.assertEqual(None, grid_secondaries)
def reserve_service_members(self, ib_network=None): """Reserve DHCP and DNS service members. For the predefined network, dhcp member(s) may be assigned. If assigned, then we need to get them from ib_network.members. For dns member(s), ib_network.options may contain them. If no dhcp member is assigned, then we will pick an available member. If no dns member is assigned, the dhcp member will serve dns as well. If network is not predefined, we need to assign service members. If the authority member is CPM, dhcp/dns members are the same as the authority member. If the authority member is GM, we need to pick an available dhcp member. For simplicity, we will use the dhcp member to serve dns as well. More detailed reason for such dns member assignment logic is explained below. For a host record, a primary dns member must be the same as dhcp member because both dhcp and dns record must be created under the same parent which is the network view. To simplify dns member assignment logic, we will always pick the dns member to be the same as dhcp member. Only exception to this would be the predefined networks that are created from NIOS side. """ if self.grid_config.dhcp_support is False: return if self.mapping.authority_member is None: raise exc.InfobloxAuthorityMemberNotReserved( network_view=self.mapping.network_view) dhcp_members = [] dns_members = [] nameservers = [] if ib_network is None: # service member assignment for a new network dhcp_member = self._reserve_dhcp_member() dhcp_members = [dhcp_member] if self.grid_config.dns_support: dns_members = dhcp_members nameservers = self._get_nameservers(dhcp_members) else: # service member assignment for the predefined network # - first set dhcp servers option dhcp_members = self._get_dhcp_members(ib_network) if not dhcp_members: dhcp_member = self._reserve_dhcp_member() dhcp_ip = dhcp_member.member_dhcp_ip or dhcp_member.member_ip dhcp_members = [dhcp_member] # assign dhcp member ib_network.members = [ ib_objects.AnyMember(_struct='dhcpmember', name=dhcp_member.member_name, ipv4addr=dhcp_ip) ] if self.grid_config.dns_support: # - then set dns servers option dns_members = self._get_dns_members(ib_network) if not dns_members: # for CPM as authority member, only one dhcp member can be # assigned and dns member needs to be the same as dhcp # member for host record. # for GM as authority member, multiple dhcp members can be # assigned but the first dhcp member will serve as the grid # primary and the rest will serve as the grid secondaries. dns_members = dhcp_members nameservers = self._get_nameservers(dns_members) else: nameservers = self._get_nameservers(dhcp_members) nameservers_option_val = ','.join(nameservers) opt_dns = [ opt for opt in ib_network.options if opt.name == 'domain-name-servers' ] if not opt_dns: ib_network.options.append( ib_objects.DhcpOption(name='domain-name-servers', value=nameservers_option_val)) else: opt_dns[0].value = nameservers_option_val # - lastly set routers option if self.subnet['ip_version'] == 4: gateway_ip_str = str(self.subnet.get('gateway_ip')) opt_routers = [ opt for opt in ib_network.options if opt.name == 'routers' ] if not opt_routers: ib_network.options.append( ib_objects.DhcpOption(name='routers', value=gateway_ip_str)) else: router_ips = opt_routers[0].value.split(',') router_ips_all = ( [gateway_ip_str] + [ip for ip in router_ips if ip != gateway_ip_str]) opt_routers[0].value = ','.join(router_ips_all) ib_dhcp_members = [] for m in dhcp_members: dhcp_ip = m.member_dhcp_ip or m.member_ip ib_dhcp_members.append( ib_objects.AnyMember(_struct='dhcpmember', name=m.member_name, ipv4addr=dhcp_ip)) self.mapping.dhcp_members = dhcp_members self.mapping.dns_members = dns_members self.mapping.ib_dhcp_members = ib_dhcp_members self.mapping.ib_nameservers = nameservers self._register_services()