Test : Multiple scenarios for verification of Proxy ARP.
Change-Id: I58fd0d23d4ceaf9481f0651cee8a13d2d0236d8f
diff --git a/src/test/cli/onosclidriver.py b/src/test/cli/onosclidriver.py
index 252fc73..2556892 100644
--- a/src/test/cli/onosclidriver.py
+++ b/src/test/cli/onosclidriver.py
@@ -1,12 +1,12 @@
-#
+#
# Copyright 2016-present Ciena Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -4589,6 +4589,28 @@
main.cleanup()
main.exit()
+ def host_remove( self, hostid ):
+ try:
+ cmdStr = "host-remove" + " " + hostid
+ handle = self.sendline( cmdStr )
+ assert "Command not found:" not in handle, handle
+ return handle
+ except AssertionError:
+ main.log.exception( "" )
+ return None
+ except TypeError:
+ main.log.exception( self.name + ": Object not as expected" )
+ return None
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanup()
+ main.exit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanup()
+ main.exit()
+
if __name__ == '__main__':
onos_cli = OnosCliDriver(connect = False)
name = 'onos_cli'
@@ -4607,4 +4629,4 @@
flows_json = onos_cli.flows(state = "ADDED")
print('Flows %s' %flows_json)
onos_cli.disconnect()
-
+
diff --git a/src/test/proxyarp/__init__.py b/src/test/proxyarp/__init__.py
new file mode 100644
index 0000000..c38f621
--- /dev/null
+++ b/src/test/proxyarp/__init__.py
@@ -0,0 +1,26 @@
+#
+# Copyright 2016-present Ciena Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os,sys
+##add the python path to lookup the utils
+working_dir = os.path.dirname(os.path.realpath(sys.argv[-1]))
+utils_dir = os.path.join(working_dir, '../utils')
+fsm_dir = os.path.join(working_dir, '../fsm')
+cli_dir = os.path.join(working_dir, '../cli')
+subscriber_dir = os.path.join(working_dir, '../subscriber')
+__path__.append(utils_dir)
+__path__.append(fsm_dir)
+__path__.append(cli_dir)
+__path__.append(subscriber_dir)
diff --git a/src/test/proxyarp/proxyarpTest.py b/src/test/proxyarp/proxyarpTest.py
new file mode 100644
index 0000000..a9083b9
--- /dev/null
+++ b/src/test/proxyarp/proxyarpTest.py
@@ -0,0 +1,439 @@
+
+# Copyright 2016-present Ciena Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import unittest
+from nose.tools import *
+from scapy.all import *
+from OnosCtrl import OnosCtrl
+from OltConfig import OltConfig
+from OnosFlowCtrl import OnosFlowCtrl, get_mac
+from onosclidriver import OnosCliDriver
+from CordContainer import Container, Onos, Quagga
+from CordTestServer import cord_test_onos_restart, cord_test_quagga_restart
+from portmaps import g_subscriber_port_map
+import threading
+from threading import current_thread
+import time
+import os
+import json
+log.setLevel('INFO')
+
+
+class proxyarp_exchange(unittest.TestCase):
+
+ apps = ('org.onosproject.vrouter','org.onosproject.proxyarp')
+ device_id = 'of:' + get_mac('ovsbr0')
+ device_dict = { "devices" : {
+ "{}".format(device_id) : {
+ "basic" : {
+ "driver" : "softrouter"
+ }
+ }
+ },
+ }
+ test_path = os.path.dirname(os.path.realpath(__file__))
+ onos_config_path = os.path.join(test_path, '..', 'setup/onos-config')
+ GATEWAY = '192.168.10.50'
+ INGRESS_PORT = 1
+ EGRESS_PORT = 2
+ MAX_PORTS = 100
+ hosts_list = [ ('192.168.10.1', '00:00:00:00:00:01'), ('192.168.11.1', '00:00:00:00:02:01'), ]
+
+ @classmethod
+ def setUpClass(cls):
+ cls.olt = OltConfig()
+ cls.port_map = cls.olt.olt_port_map()
+ if not cls.port_map:
+ cls.port_map = g_subscriber_port_map
+ time.sleep(3)
+
+ @classmethod
+ def tearDownClass(cls):
+ '''Deactivate the vrouter apps'''
+ #cls.vrouter_host_unload()
+
+ def cliEnter(self):
+ retries = 0
+ while retries < 3:
+ self.cli = OnosCliDriver(connect = True)
+ if self.cli.handle:
+ break
+ else:
+ retries += 1
+ time.sleep(2)
+ def cliExit(self):
+ self.cli.disconnect()
+
+ @classmethod
+ def proxyarp_host_unload(cls):
+ index = 1
+ for host,_ in cls.hosts_list:
+ iface = cls.port_map[index]
+ index += 1
+ config_cmds = ('ifconfig {} 0'.format(iface), )
+ for cmd in config_cmds:
+ log.info('host unload command %s' % cmd)
+ os.system(cmd)
+
+ @classmethod
+ def interface_config_load(cls, interface_cfg = None):
+ if type(interface_cfg) is tuple:
+ res = []
+ for v in interface_cfg:
+ if type(v) == list:
+ pass
+ else:
+ res += v.items()
+ config = dict(res)
+ else:
+ config = interface_cfg
+ cfg = json.dumps(config)
+ with open('{}/network-cfg.json'.format(cls.onos_config_path), 'w') as f:
+ f.write(cfg)
+ return cord_test_onos_restart()
+
+ @classmethod
+ def host_config_load(cls, host_config = None):
+ for host in host_config:
+ status, code = OnosCtrl.host_config(host)
+ if status is False:
+ log.info('JSON request returned status %d' %code)
+ assert_equal(status, True)
+
+ @classmethod
+ def generate_interface_config(cls, hosts = 1):
+ num = 0
+ start_host = ( 192 << 24) | ( 168 << 16) | (10 << 8) | 0
+ end_host = ( 200 << 24 ) | (168 << 16) | (10 << 8) | 0
+ ports_dict = { 'ports' : {} }
+ interface_list = []
+ hosts_list = []
+ for n in xrange(start_host, end_host, 256):
+ port_map = ports_dict['ports']
+ port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
+ device_port_key = '{0}/{1}'.format(cls.device_id, port)
+ try:
+ interfaces = port_map[device_port_key]['interfaces']
+ except:
+ port_map[device_port_key] = { 'interfaces' : [] }
+ interfaces = port_map[device_port_key]['interfaces']
+ ip = n + 1
+ host_ip = n + 2
+ ips = '%d.%d.%d.%d/24'%( (ip >> 24) & 0xff, ( (ip >> 16) & 0xff ), ( (ip >> 8 ) & 0xff ), ip & 0xff)
+ host = '%d.%d.%d.%d' % ( (host_ip >> 24) & 0xff, ( ( host_ip >> 16) & 0xff ), ( (host_ip >> 8 ) & 0xff ), host_ip & 0xff )
+ mac = RandMAC()._fix()
+ hosts_list.append((host, mac))
+ if num < cls.MAX_PORTS - 1:
+ interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : mac }
+ interfaces.append(interface_dict)
+ interface_list.append(interface_dict['name'])
+ else:
+ interfaces[0]['ips'].append(ips)
+ num += 1
+ if num == hosts:
+ break
+ cls.hosts_list = hosts_list
+ return (cls.device_dict, ports_dict, hosts_list)
+
+ @classmethod
+ def generate_host_config(cls):
+ num = 0
+ hosts_dict = {}
+ for host, mac in cls.hosts_list:
+ port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
+ hosts_dict[host] = {'mac':mac, 'vlan':'none', 'ipAddresses':[host], 'location':{ 'elementId' : '{}'.format(cls.device_id), 'port': port}}
+ num += 1
+ return hosts_dict.values()
+
+ @classmethod
+ def proxyarp_activate(cls, deactivate = False):
+ app = 'org.onosproject.proxyarp'
+ onos_ctrl = OnosCtrl(app)
+ if deactivate is True:
+ onos_ctrl.deactivate()
+ else:
+ onos_ctrl.activate()
+ time.sleep(3)
+
+ @classmethod
+ def proxyarp_config(cls, hosts = 1):
+ proxyarp_configs = cls.generate_interface_config(hosts = hosts)
+ cls.interface_config_load(interface_cfg = proxyarp_configs)
+ hostcfg = cls.generate_host_config()
+ cls.host_config_load(host_config = hostcfg)
+ return proxyarp_configs
+
+ def proxyarp_arpreply_verify(self, ingress, hostip, hostmac, PositiveTest=True):
+ log.info('verifying arp reply for host ip %s host mac %s on interface %s'%(hostip ,hostmac ,self.port_map[ingress]))
+ self.success = False
+ def recv_task():
+ def recv_cb(pkt):
+ log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
+ self.success = True if PositiveTest == True else False
+ sniff(count=1, timeout=2, lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
+ prn = recv_cb, iface = self.port_map[ingress])
+ t = threading.Thread(target = recv_task)
+ t.start()
+ pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst=hostip))
+ log.info('sending arp request for dest ip %s on interface %s' %
+ (hostip, self.port_map[ingress]))
+ sendp( pkt, count = 10, iface = self.port_map[ingress])
+ t.join()
+ if PositiveTest:
+ assert_equal(self.success, True)
+ else:
+ assert_equal(self.success, False)
+
+ def __proxyarp_hosts_verify(self, hosts = 1,PositiveTest = True):
+ _,_,hosts_config = self.proxyarp_config(hosts = hosts)
+ log.info('\nhosts_config %s and its type %s'%(hosts_config,type(hosts_config)))
+ self.cliEnter()
+ connected_hosts = json.loads(self.cli.hosts(jsonFormat = True))
+ log.info('Discovered hosts: %s' %connected_hosts)
+ #We read from cli if we expect less number of routes to avoid cli timeouts
+ if hosts <= 10000:
+ assert_equal(len(connected_hosts), hosts)
+ ingress = hosts+1
+ for hostip, hostmac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = PositiveTest)
+ time.sleep(1)
+ self.cliExit()
+ return True
+
+ def test_proxyarp_with_1_host(self, hosts=1):
+ res = self.__proxyarp_hosts_verify(hosts = hosts)
+ assert_equal(res, True)
+ #cls.proxyarp_host_unload()
+ def test_proxyarp_with_10_hosts(self, hosts=10):
+ res = self.__proxyarp_hosts_verify(hosts = hosts)
+ assert_equal(res, True)
+ def test_proxyarp_with_50_hosts(self, hosts=50):
+ res = self.__proxyarp_hosts_verify(hosts = hosts)
+ assert_equal(res, True)
+ def test_proxyarp_app_with_disabling_and_re_enabling(self,hosts = 3):
+ ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
+ ingress = hosts+1
+ for hostip, hostmac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
+ time.sleep(1)
+ log.info('Deactivating proxyarp app and expecting not to get arp reply from ONOS')
+ self.proxyarp_activate(deactivate = True)
+ for hostip, hostmac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = False)
+ time.sleep(1)
+ log.info('activating proxyarp app and expecting to get arp reply from ONOS')
+ self.proxyarp_activate(deactivate = False)
+ for hostip, hostmac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
+ time.sleep(1)
+
+ def test_proxyarp_nonexisting_host(self,hosts = 1):
+ _,_,hosts_config = self.proxyarp_config(hosts = hosts)
+ ingress = hosts + 2
+ for host, mac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,host,mac,PositiveTest = True)
+ new_host = hosts_config[-1][0].split('.')
+ new_host[2] = str(int(new_host[2])+1)
+ new_host = '.'.join(new_host)
+ new_mac = RandMAC()._fix()
+ log.info('verifying arp reply for host ip %s on interface %s'%(new_host,self.port_map[ingress]))
+ res=srp1(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst=new_host),timeout=2,iface=self.port_map[ingress])
+ assert_equal(res, None)
+ log.info('arp reply not seen for host ip %s on interface %s as expected'%(new_host,self.port_map[ingress]))
+ hosts = hosts + 1
+ _,_,hosts_config = self.proxyarp_config(hosts = hosts)
+ for host in hosts_config:
+ if host[0] == new_host:
+ new_mac = host[1]
+ self.proxyarp_arpreply_verify(ingress,new_host,new_mac,PositiveTest = True)
+
+ def test_proxyarp_removing_host(self,hosts = 3):
+ ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
+ ingress = hosts+1
+ for hostip, hostmac in hosts_config:
+ self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
+ time.sleep(1)
+ host_mac = hosts_config[0][1]
+ log.info('removing host entry %s' % host_mac)
+ self.cliEnter()
+ hostentries = json.loads(self.cli.hosts(jsonFormat = True))
+ for host in hostentries:
+ res = host_mac.upper() in host.values()
+ if res:
+ break
+ assert_equal(res, True)
+ hostid = host_mac+'/'+'None'
+ delete_host = self.cli.host_remove(hostid)
+ hostentries = json.loads(self.cli.hosts(jsonFormat = True))
+ for host in hostentries:
+ res = host_mac.upper() in host.values()
+ if res:
+ break
+ assert_equal(res, False)
+ self.proxyarp_arpreply_verify(ingress,hosts_config[0][0],host_mac,PositiveTest = False)
+ time.sleep(1)
+ self.cliExit()
+
+ def test_proxyarp_concurrent_requests_with_multiple_host_and_different_interfaces(self,hosts = 10):
+ ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
+ self.success = True
+ ingress = hosts+1
+ ports = range(ingress,ingress+10)
+ hostmac = []
+ hostip = []
+ for ip,mac in hosts_config:
+ hostmac.append(mac)
+ hostip.append(ip)
+ success_dir = {}
+ def verify_proxyarp(*r):
+ ingress,hostmac,hostip = r[0],r[1],r[2]
+ def mac_recv_task():
+ def recv_cb(pkt):
+ log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
+ success_dir[current_thread().name] = True
+ sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
+ prn = recv_cb, iface = self.port_map[ingress])
+ t = threading.Thread(target = mac_recv_task)
+ t.start()
+ pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
+ log.info('sending arp request for dest ip %s on interface %s' %
+ (hostip,self.port_map[ingress]))
+ sendp(pkt, count = 10,iface = self.port_map[ingress])
+ t.join()
+ t = []
+ for i in range(10):
+ t.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
+ for i in range(10):
+ t[i].start()
+ for i in range(10):
+ t[i].join()
+ if len(success_dir) != 10:
+ self.success = False
+ assert_equal(self.success, True)
+
+ def test_proxyarp_disabling_enabling_app_initiating_concurrent_requests(self,hosts = 10):
+ '''Test sending arp requests to multiple host ips at once from different interfaces by disabling and re-enabling proxyarp app'''
+ ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
+ self.success = True
+ ingress = hosts+1
+ ports = range(ingress,ingress+10)
+ hostmac = []
+ hostip = []
+ for ip,mac in hosts_config:
+ hostmac.append(mac)
+ hostip.append(ip)
+ success_dir = {}
+ def verify_proxyarp(*r):
+ ingress,hostmac,hostip = r[0],r[1],r[2]
+ def mac_recv_task():
+ def recv_cb(pkt):
+ log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
+ success_dir[current_thread().name] = True
+ sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
+ prn = recv_cb, iface = self.port_map[ingress])
+ t = threading.Thread(target = mac_recv_task)
+ t.start()
+ pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
+ log.info('sending arp request for dest ip %s on interface %s' %
+ (hostip,self.port_map[ingress]))
+ sendp(pkt, count = 10,iface = self.port_map[ingress])
+ t.join()
+ t1 = []
+ #starting multi threading before proxyarp disable
+ for i in range(10):
+ t1.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
+ for i in range(10):
+ t1[i].start()
+ for i in range(10):
+ t1[i].join()
+ if len(success_dir) != 10:
+ self.success = False
+ assert_equal(self.success, True)
+ self.proxyarp_activate(deactivate = True)
+ #starting multi threading after proxyarp disable
+ t2 = []
+ self.success = False
+ for i in range(10):
+ t2.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
+ for i in range(10):
+ t2[i].start()
+ for i in range(10):
+ t2[i].join()
+ if len(success_dir) != 10:
+ self.success = True
+ assert_equal(self.success, False)
+ self.proxyarp_activate(deactivate = False)
+ #starting multi threading after proxyarp re-enable
+ self.success = True
+ t3 = []
+ for i in range(10):
+ t3.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
+ for i in range(10):
+ t3[i].start()
+ for i in range(10):
+ t3[i].join()
+ if len(success_dir) != 20:
+ self.success = False
+ assert_equal(self.success, True)
+
+ def test_proxyarp_with_existing_and_non_existing_hostIPs_initiating_concurrent_requests(self,hosts = 5):
+ ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
+ self.success = True
+ ingress = hosts+1
+ ports = range(ingress,ingress+10)
+ hostmac = []
+ hostip = []
+ for ip,mac in hosts_config:
+ hostmac.append(mac)
+ hostip.append(ip)
+ #adding 5 non-existing host IPs to hostip list
+ for i in range(1,6):
+ ip = hostip[-1].split('.')
+ ip[3] = str(int(ip[3])+int(i))
+ ip = '.'.join(ip)
+ hostip.append(ip)
+ hostmac.append(RandMAC()._fix())
+ success_dir = {}
+ replied_hosts = []
+ def verify_proxyarp(*r):
+ ingress,hostmac,hostip = r[0],r[1],r[2]
+ def mac_recv_task():
+ def recv_cb(pkt):
+ log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
+ success_dir[current_thread().name] = True
+ replied_hosts.append(hostip)
+ sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].psrc == hostip,
+ prn = recv_cb, iface = self.port_map[ingress])
+ t = threading.Thread(target = mac_recv_task)
+ t.start()
+ pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
+ log.info('sending arp request for dest ip %s on interface %s' %
+ (hostip,self.port_map[ingress]))
+ sendp(pkt, count = 10,iface = self.port_map[ingress])
+ t.join()
+ t = []
+ for i in range(10):
+ t.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
+ for i in range(10):
+ t[i].start()
+ for i in range(10):
+ t[i].join()
+ if len(success_dir) != 5 and len(replied_hosts) != 5:
+ self.success = False
+ assert_equal(self.success, True)
+ for i in range(5):
+ if hostip[i] not in replied_hosts:
+ self.success = False
+ assert_equal(self.success, True)
diff --git a/src/test/subscriberMultiTable/subscriberMultiTableTest.py b/src/test/subscriberMultiTable/subscriberMultiTableTest.py
index 7cc9eed..a6eec2a 100644
--- a/src/test/subscriberMultiTable/subscriberMultiTableTest.py
+++ b/src/test/subscriberMultiTable/subscriberMultiTableTest.py
@@ -505,7 +505,7 @@
return self.test_status
def test_subscriber_join_recv(self):
- """Test subscriber join and receive"""
+ """Test subscriber join and receive for channel surfing"""
self.num_subscribers = 5
self.num_channels = 1
test_status = self.subscriber_join_verify(num_subscribers = self.num_subscribers,
@@ -527,7 +527,7 @@
assert_equal(test_status, True)
def test_subscriber_join_next(self):
- """Test subscriber join next for channels"""
+ """Test subscriber join next for channel surfing"""
self.num_subscribers = 5
self.num_channels = 10
test_status = self.subscriber_join_verify(num_subscribers = self.num_subscribers,
diff --git a/src/test/utils/OnosCtrl.py b/src/test/utils/OnosCtrl.py
index 92437cb..e323112 100644
--- a/src/test/utils/OnosCtrl.py
+++ b/src/test/utils/OnosCtrl.py
@@ -24,6 +24,7 @@
cfg_url = 'http://%s:8181/onos/v1/network/configuration/' %(controller)
maven_repo = 'http://central.maven.org/maven2/org/onosproject'
applications_url = 'http://%s:8181/onos/v1/applications' %(controller)
+ host_cfg_url = 'http://%s:8181/onos/v1/hosts/' %(controller)
def __init__(self, app, controller = None):
self.app = app
@@ -118,3 +119,11 @@
app_url = '{}/{}'.format(url, app_name)
resp = requests.delete(app_url, auth = cls.auth)
return resp.ok, resp.status_code
+
+ @classmethod
+ def host_config(cls, config):
+ if config:
+ json_data = json.dumps(config)
+ resp = requests.post(cls.host_cfg_url, auth = cls.auth, data = json_data)
+ return resp.ok, resp.status_code
+ return False, 400