def test_context_manager(context): ifname = context.new_ifname address = '00:11:22:36:47:58' spec = {'ifname': ifname, 'kind': 'dummy'} ifobj = context.ndb.interfaces.create(**spec) with ifobj: pass assert interface_exists(context.netns, ifname=ifname, state='down') with ifobj: ifobj['state'] = 'up' ifobj['address'] = address assert interface_exists(context.netns, ifname=ifname, address=address, state='up') with ifobj: ifobj.remove() assert not interface_exists(context.netns, ifname=ifname)
def test_create(context): ifname = context.new_ifname iface = (context.ndb.interfaces.create(ifname=ifname, kind='dummy').commit()) assert interface_exists(context.netns, ifname=ifname) iface.rollback() assert not interface_exists(context.netns, ifname=ifname)
def _test_tunnel_endpoints(context, state): ifname = context.new_ifname ipaddr_local1 = context.new_ipaddr ipaddr_local2 = context.new_ipaddr ipaddr_remote = context.new_ipaddr kind = context.kind (context.ndb.interfaces.create( **{ 'ifname': ifname, 'state': state, 'kind': kind, f'{kind}_local': ipaddr_local1, f'{kind}_remote': ipaddr_remote, }).commit()) def match(ifname, ipaddr): return (lambda x: x.get_nested('IFLA_LINKINFO', 'IFLA_INFO_KIND') == kind and x.get_attr('IFLA_IFNAME') == ifname and x.get_nested( 'IFLA_LINKINFO', 'IFLA_INFO_DATA', 'IFLA_%s_LOCAL' % kind.upper(), ) == ipaddr) assert interface_exists(context.netns, match(ifname, ipaddr_local1)) (context.ndb.interfaces[ifname].set(f'{kind}_local', ipaddr_local2).commit()) assert interface_exists(context.netns, match(ifname, ipaddr_local2))
def test_set(context): ifname = context.new_ifname (context .ndb .interfaces .create(ifname=ifname, kind='dummy', address='00:11:22:33:44:55') .commit()) assert interface_exists(context.netns, ifname=ifname, address='00:11:22:33:44:55') (context .ndb .interfaces[ifname] .set('address', '00:11:22:aa:aa:aa') .commit()) assert not interface_exists(context.netns, ifname=ifname, address='00:11:22:33:44:55') assert interface_exists(context.netns, ifname=ifname, address='00:11:22:aa:aa:aa') (context .ndb .interfaces[ifname] .rollback()) assert not interface_exists(context.netns, ifname=ifname, address='00:11:22:aa:aa:aa') assert interface_exists(context.netns, ifname=ifname, address='00:11:22:33:44:55')
def test_simple_deps(context): ifname = context.new_ifname ipaddr = context.new_ipaddr router = context.new_ipaddr dst = str(context.ipnets[1].network) # # simple dummy interface with one address and # one dependent route # (context.ndb.interfaces.create(ifname=ifname, kind='dummy').set( 'state', 'up').add_ip(address=ipaddr, prefixlen=24).commit()) (context.ndb.routes.create(dst=dst, dst_len=24, gateway=router).commit()) # check everything is in place assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ipaddr) assert route_exists(context.netns, gateway=router, dst=dst, dst_len=24) # remove the interface iface = context.ndb.interfaces[ifname].remove().commit() # check there is no interface, no route assert not interface_exists(context.netns, ifname=ifname) assert not address_exists(context.netns, ifname=ifname, address=ipaddr) assert not route_exists(context.netns, gateway=router, dst=dst, dst_len=24) # revert the changes using the implicit last_save iface.rollback() assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ipaddr) assert route_exists(context.netns, gateway=router, dst=dst, dst_len=24)
def test_source_localhost_restart(context): ''' The database must be operational after a complete restart of any source. ''' require_user('root') ifname1 = context.new_ifname ifname2 = context.new_ifname ndb = context.ndb # # check that there are existing interfaces # loaded into the DB assert len(list(ndb.interfaces.dump())) # # create a dummy interface to prove the # source working (ndb .interfaces .create(ifname=ifname1, kind='dummy', state='up') .commit()) # # an external check assert interface_exists(ifname=ifname1, state='up') # # internal checks assert ifname1 in ndb.interfaces assert ndb.interfaces[ifname1]['state'] == 'up' # # now restart the source # the reason should be visible in the log ndb.sources['localhost'].restart(reason='test') # # the interface must be in the DB (after the # source restart) assert ifname1 in ndb.interfaces # # create another one (ndb .interfaces .create(ifname=ifname2, kind='dummy', state='down') .commit()) # # check the interface both externally and internally assert interface_exists(ifname=ifname2, state='down') assert ifname2 in ndb.interfaces assert ndb.interfaces[ifname2]['state'] == 'down' # # cleanup ndb.interfaces[ifname1].remove().commit() ndb.interfaces[ifname2].remove().commit() # # check assert not interface_exists(ifname=ifname1) assert not interface_exists(ifname=ifname2)
def test_bridge(context): bridge = context.new_ifname brport = context.new_ifname spec_br = {'ifname': bridge, 'kind': 'bridge'} spec_pt = {'ifname': brport, 'kind': 'dummy'} (context.ndb.interfaces.create(**spec_br).commit()) (context.ndb.interfaces.create(**spec_pt).set( 'master', context.ndb.interfaces[spec_br]['index']).commit()) assert interface_exists(context.netns, ifname=bridge) assert interface_exists(context.netns, ifname=brport, master=context.ndb.interfaces[spec_br]['index'])
def test_scopes(context): ipaddr = context.new_ipaddr ifname = context.new_ifname table = context.table dst = '172.24.200.142' (context.ndb.interfaces.create(ifname=ifname, kind='dummy', state='up').add_ip(address=ipaddr, prefixlen=24).commit()) spec = { 'dst': dst, 'oif': context.ndb.interfaces[ifname]['index'], 'dst_len': 32, 'scope': 253 } if table: spec['table'] = table (context.ndb.routes.create(**spec).commit()) assert interface_exists(context.netns, ifname=ifname) assert route_exists(context.netns, **spec) (context.ndb.routes[spec].remove().commit()) assert not route_exists(context.netns, **spec)
def test_basic(context): ifaddr = context.new_ipaddr router = context.new_ipaddr ifname = context.new_ifname ipnet = str(context.ipnets[1].network) table = context.table (context .ndb .interfaces .create(ifname=ifname, kind='dummy', state='up') .ipaddr .create(address=ifaddr, prefixlen=24) .commit()) spec = {'dst_len': 24, 'dst': ipnet, 'gateway': router} if table: spec['table'] = table (context .ndb .routes .create(**spec) .commit()) assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ifaddr) assert route_exists(context.netns, dst=ipnet, table=table or 254)
def test_dummy(context): ifname = context.new_ifname spec = {'ifname': ifname, 'kind': 'dummy', 'address': '00:11:22:33:44:55'} context.ndb.interfaces.create(**spec).commit() assert interface_exists(context.netns, ifname=ifname, address='00:11:22:33:44:55')
def test_cm_interface_change_assign(context): ''' :: with interface as i: i['state'] = 'up' ''' ifname = test_cm_interface_create(context) with context.ndb.interfaces[ifname] as i: i['state'] = 'up' assert interface_exists(context.netns, ifname=ifname, state='up')
def test_cm_interface_change_set_kwarg(context): ''' :: with interface as i: i.set(state='up') ''' ifname = test_cm_interface_create(context) with context.ndb.interfaces[ifname] as i: i.set(state='up') assert interface_exists(context.netns, ifname=ifname, state='up')
def test_del_ip_fail(context): ifname = context.new_ifname ipaddr = '%s/24' % context.new_ipaddr ipaddr_fail = '%s/24' % context.new_ipaddr (context.ndb.interfaces.create(ifname=ifname, kind='dummy', state='up').add_ip(ipaddr).commit()) assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ipaddr) try: (context.ndb.interfaces[ifname].del_ip(ipaddr_fail).commit()) raise Exception('shall not pass') except KeyError: pass assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ipaddr)
def test_cm_interface_create(context): ''' Create an interface using context manager syntax ''' ifname = context.new_ifname with context.ndb.interfaces.create(ifname=ifname, kind='dummy', state='down'): pass assert interface_exists(context.netns, ifname=ifname, state='down') return ifname
def test_vxlan(context): host = context.new_ifname vxlan = context.new_ifname spec_host = {'ifname': host, 'kind': 'dummy'} spec_vxlan = {'ifname': vxlan, 'kind': 'vxlan'} (context.ndb.interfaces.create(**spec_host).commit()) (context.ndb.interfaces.create(**spec_vxlan).set( 'vxlan_link', context.ndb.interfaces[spec_host]['index']).set( 'vxlan_id', 101).set('vxlan_group', '239.1.1.1').set('vxlan_ttl', 16).commit()) assert interface_exists(context.netns, ifname=vxlan)
def test_veth_simple(context): ifname = context.new_ifname peername = context.new_ifname spec = {'ifname': ifname, 'peer': peername, 'kind': 'veth'} context.ndb.interfaces.create(**spec).commit() spec_ifl = {'ifname': ifname} spec_pl = {'ifname': peername} iflink = context.ndb.interfaces[spec_ifl]['link'] plink = context.ndb.interfaces[spec_pl]['link'] assert iflink == context.ndb.interfaces[spec_pl]['index'] assert plink == context.ndb.interfaces[spec_ifl]['index'] assert interface_exists(context.netns, ifname=ifname) assert interface_exists(context.netns, ifname=peername) context.ndb.interfaces[spec_ifl].remove().commit() assert not interface_exists(context.netns, ifname=ifname) assert not interface_exists(context.netns, ifname=peername)
def test_basic_address(context): ifaddr = context.new_ipaddr ifname = context.new_ifname spec_if = {'ifname': ifname, 'kind': 'dummy', 'state': 'up'} i = (context.ndb.interfaces.create(**spec_if)) i.commit() spec_ad = {'index': i['index'], 'address': ifaddr, 'prefixlen': 24} a = (context.ndb.addresses.create(**spec_ad)) a.commit() assert interface_exists(context.netns, ifname=ifname) assert address_exists(context.netns, ifname=ifname, address=ifaddr)
def test_localhost_implicit(context): ifname = context.new_ifname ipaddr = context.new_ipaddr nsname = context.new_nsname context.ndb.sources.add(netns=nsname) context.ndb.localhost = nsname (context.ndb.interfaces.create(ifname=ifname, kind='dummy').add_ip(address=ipaddr, prefixlen=24).commit()) assert interface_exists(nsname, ifname=ifname) assert address_exists(nsname, ifname=ifname, address=ipaddr)
def test_multiple_interfaces(context): ifname1 = context.new_ifname ifname2 = context.new_ifname ipaddr1 = context.new_ipaddr ipaddr2 = context.new_ipaddr (context.ndb.begin().push( context.ndb.interfaces.create(ifname=ifname1, kind='dummy').set( state='up').set(address='00:11:22:aa:aa:aa').add_ip( address=ipaddr1, prefixlen=24), context.ndb.interfaces.create(ifname=ifname2, kind='dummy').set( state='up').set(address='00:11:22:bb:bb:bb').add_ip( address=ipaddr2, prefixlen=24)).commit()) assert interface_exists(context.netns, ifname=ifname1, address='00:11:22:aa:aa:aa') assert interface_exists(context.netns, ifname=ifname2, address='00:11:22:bb:bb:bb') assert address_exists(context.netns, ifname=ifname1, address=ipaddr1) assert address_exists(context.netns, ifname=ifname2, address=ipaddr2)
def test_vlan_deps(context): if_host = context.new_ifname if_vlan = context.new_ifname ifaddr1 = context.new_ipaddr ifaddr2 = context.new_ipaddr router = context.new_ipaddr dst = str(context.ipnets[1].network) (context .ndb .interfaces .create(ifname=if_host, kind='dummy', state='up') .commit()) (context .ndb .interfaces .create(ifname=if_vlan, kind='vlan', state='up', vlan_id=1001, link=if_host) .add_ip(address=ifaddr1, prefixlen=24) .add_ip(address=ifaddr2, prefixlen=24) .commit()) (context .ndb .routes .create(dst=dst, dst_len=24, gateway=router) .commit()) # check everything is in place assert interface_exists(context.netns, ifname=if_host) assert interface_exists(context.netns, ifname=if_vlan) assert address_exists(context.netns, ifname=if_vlan, address=ifaddr1) assert address_exists(context.netns, ifname=if_vlan, address=ifaddr2) assert route_exists(context.netns, dst=dst, gateway=router) # remove the interface iface = context.ndb.interfaces[if_host].remove().commit() # check there is no interface, no route assert not interface_exists(context.netns, ifname=if_host) assert not interface_exists(context.netns, ifname=if_vlan) assert not address_exists(context.netns, ifname=if_vlan, address=ifaddr1) assert not address_exists(context.netns, ifname=if_vlan, address=ifaddr2) assert not route_exists(context.netns, dst=dst, gateway=router) # revert the changes using the implicit last_save iface.rollback() assert interface_exists(context.netns, ifname=if_host) assert interface_exists(context.netns, ifname=if_vlan) assert address_exists(context.netns, ifname=if_vlan, address=ifaddr1) assert address_exists(context.netns, ifname=if_vlan, address=ifaddr2) assert route_exists(context.netns, dst=dst, gateway=router)
def test_veth_spec(context): ifname = context.new_ifname peername = context.new_ifname nsname = context.new_nsname context.ndb.sources.add(netns=nsname) spec = { 'ifname': ifname, 'kind': 'veth', 'peer': { 'ifname': peername, 'address': '00:11:22:33:44:55', 'net_ns_fd': nsname } } (context.ndb.interfaces.create(**spec).commit()) (context.ndb.interfaces.wait(target=nsname, ifname=peername)) iflink = context.ndb.interfaces[{'ifname': ifname}]['link'] plink = context.ndb.interfaces[{ 'target': nsname, 'ifname': peername }]['link'] assert iflink == (context.ndb.interfaces[{ 'target': nsname, 'ifname': peername }]['index']) assert plink == (context.ndb.interfaces[{'ifname': ifname}]['index']) assert interface_exists(context.netns, ifname=ifname) assert interface_exists(nsname, ifname=peername) assert not interface_exists(nsname, ifname=ifname) assert not interface_exists(context.netns, ifname=peername) (context.ndb.interfaces[{'ifname': ifname}].remove().commit()) assert not interface_exists(context.netns, ifname=ifname) assert not interface_exists(nsname, ifname=ifname) assert not interface_exists(context.netns, ifname=peername) assert not interface_exists(nsname, ifname=peername) context.ndb.sources.remove(nsname)
def test_fail(context): ifname = context.new_ifname kind = context.new_ifname spec = {'ifname': ifname, 'kind': kind} ifobj = context.ndb.interfaces.create(**spec) save = dict(ifobj) try: ifobj.commit() except NetlinkError as e: assert e.code == 95 # Operation not supported assert save == dict(ifobj) assert ifobj.state == 'invalid' assert not interface_exists(context.netns, ifname=ifname)
def test_bridge_deps(context): if_br0 = context.new_ifname if_br0p0 = context.new_ifname if_br0p1 = context.new_ifname ifaddr1 = context.new_ipaddr ifaddr2 = context.new_ipaddr router = context.new_ipaddr dst = str(context.ipnets[1].network) with context.ndb.interfaces as i: i.create(ifname=if_br0p0, kind='dummy', state='up').commit() i.create(ifname=if_br0p1, kind='dummy', state='up').commit() (i.create(ifname=if_br0, kind='bridge', state='up') .add_port(if_br0p0) .add_port(if_br0p1) .add_ip(address=ifaddr1, prefixlen=24) .add_ip(address=ifaddr2, prefixlen=24) .commit()) (context .ndb .routes .create(dst=dst, dst_len=24, gateway=router) .commit()) assert interface_exists(context.netns, ifname=if_br0) assert interface_exists(context.netns, ifname=if_br0p0) assert interface_exists(context.netns, ifname=if_br0p1) assert address_exists(context.netns, ifname=if_br0, address=ifaddr1) assert address_exists(context.netns, ifname=if_br0, address=ifaddr2) assert route_exists(context.netns, gateway=router, dst=dst, dst_len=24) # remove the interface iface = context.ndb.interfaces[if_br0].remove().commit() assert not interface_exists(context.netns, ifname=if_br0) assert not address_exists(context.netns, ifname=if_br0, address=ifaddr1) assert not address_exists(context.netns, ifname=if_br0, address=ifaddr2) assert not route_exists(context.netns, gateway=router, dst=dst, dst_len=24) # revert the changes using the implicit last_save iface.rollback() assert interface_exists(context.netns, ifname=if_br0) assert interface_exists(context.netns, ifname=if_br0p0) assert interface_exists(context.netns, ifname=if_br0p1) assert address_exists(context.netns, ifname=if_br0, address=ifaddr1) assert address_exists(context.netns, ifname=if_br0, address=ifaddr2) assert route_exists(context.netns, gateway=router, dst=dst, dst_len=24)
def test_source_netns_restart(context): ''' Netns sources should be operational after restart as well ''' require_user('root') nsname = context.new_nsname # # simple `context.new_ifname` returns ifname only for the main # netns, if we want to register the name in a netns, we should # use `context.register(netns=...)` ifname = context.register(netns=nsname) ndb = context.ndb # # add a netns source, the netns will be created automatically ndb.sources.add(netns=nsname) # # check the interfaces from the netns are loaded into the DB assert len(list(ndb.interfaces.dump().filter(target=nsname))) # # restart the DB ndb.sources[nsname].restart(reason='test') # # check the netns interfaces again assert len(list(ndb.interfaces.dump().filter(target=nsname))) # # create an interface in the netns ( ndb.interfaces.create( target=nsname, ifname=ifname, kind='dummy', state='up' ).commit() ) # # check the interface assert interface_exists(nsname, ifname=ifname) assert ( ndb.interfaces[{'target': nsname, 'ifname': ifname}]['state'] == 'up' )
def test_move(context): ifname = context.new_ifname ifaddr = context.new_ipaddr nsname = context.new_nsname context.ndb.sources.add(netns=nsname) # create the interface (context.ndb.interfaces.create(ifname=ifname, kind='dummy').commit()) # move it to a netns (context.ndb.interfaces[ifname].set('net_ns_fd', nsname).commit()) # setup the interface only when it is moved (context.ndb.interfaces.wait(target=nsname, ifname=ifname).set( 'state', 'up').set('address', '00:11:22:33:44:55').add_ip('%s/24' % ifaddr).commit()) assert interface_exists(nsname, ifname=ifname, state='up', address='00:11:22:33:44:55')
def test_vrf(context): vrf = context.new_ifname spec = {'ifname': vrf, 'kind': 'vrf'} (context.ndb.interfaces.create(**spec).set('vrf_table', 42).commit()) assert interface_exists(context.netns, ifname=vrf)
def test_view_cache(context): ''' NDB stores all the info in an SQL database, and instantiates python objects only upon request, since it isn't cheap. References to the created objects are stored in the object cache until expired. This test checks is the cache works as expected. Initially there should be no references in the cache, check if the references are properly cached and expired in time. ''' require_user('root') ifname1 = context.new_ifname ifname2 = context.new_ifname ndb = context.ndb # # the cache is empty from the beginning assert len(list(ndb.interfaces.cache)) == 0 # # create test interfaces ndb.interfaces.create(ifname=ifname1, kind='dummy').commit() ndb.interfaces.create(ifname=ifname2, kind='dummy').commit() assert interface_exists(ifname=ifname1) assert interface_exists(ifname=ifname2) # # the interface object must not be cached, as they # weren't referenced yet assert len(list(ndb.interfaces.cache)) == 0 # # setup the cache expiration time ce = config.cache_expire # save the old value config.cache_expire = 1 # set the new one # # access the interfaces via __getitem__() -- this must # create objects and cache the references assert ndb.interfaces[ifname1] is not None assert ndb.interfaces[ifname2] is not None # # both references must be in the cache now assert len(list(ndb.interfaces.cache)) == 2 # # expire the cache time.sleep(1) # # access the second interface to trigger the # cache invalidation assert ndb.interfaces[ifname2] is not None # # ifname1 must be out of the cache now as not # accessed within the timeout # # only ifname2 must remain assert len(list(ndb.interfaces.cache)) == 1 assert list(ndb.interfaces.cache.items())[0][1]['ifname'] == ifname2 # # restore the environment config.cache_expire = ce ndb.interfaces[ifname1].remove().commit() ndb.interfaces[ifname2].remove().commit() # # check that the interfaces are cleaned up from the system assert not interface_exists(ifname=ifname1) assert not interface_exists(ifname=ifname2)