VOL-1060: Test Case: DHCP

Delivery of DHCP Test Case

Add missing Firewall call in Robot
Calling dhclient directly and not via bash
Therefore Lib fix is unnecessary
Logging to file dhcp assignment response
Other minor changes in Robot
Common Retry Timeout and Interval in "Wait Until Keyword Succeeds" moved to variables
Removed DHCP deactivate from Test Case

Change-Id: If9902e2b3606ac14af2c2f8ece34db074b373c50
diff --git a/tests/atests/build/dhcp_json b/tests/atests/build/dhcp_json
new file mode 100755
index 0000000..eb7d232
--- /dev/null
+++ b/tests/atests/build/dhcp_json
@@ -0,0 +1,20 @@
+{  
+  "org.onosproject.dhcp":{
+    "dhcp":{
+      "ip":"10.1.11.50",
+      "mac":"ca:fe:ca:fe:ca:fe",
+      "subnet":"255.255.252.0",
+      "broadcast":"10.1.11.255",
+      "router":"10.1.8.1",
+      "domain":"8.8.8.8",
+      "ttl":"63",
+      "lease":"300",
+      "renew":"150",
+      "rebind":"200",
+      "delay":"2",
+      "timeout":"150",
+      "startip":"10.1.11.51",
+      "endip":"10.1.11.100"
+    }
+  }
+}
diff --git a/tests/atests/common/auto_test.py b/tests/atests/common/auto_test.py
index f4b90ae..b43665a 100755
--- a/tests/atests/common/auto_test.py
+++ b/tests/atests/common/auto_test.py
@@ -26,6 +26,7 @@
 import preprovisioning
 import discovery
 import authentication
+import dhcp
 import logging
 
 DEFAULT_LOG_DIR = '/tmp/voltha_test_results'
@@ -79,4 +80,6 @@
 
     authentication.run_test(ROOT_DIR, VOLTHA_DIR, LOG_DIR)
 
+    dhcp.run_test(ROOT_DIR, VOLTHA_DIR, LOG_DIR)
+
     time.sleep(5)
diff --git a/tests/atests/common/dhcp.py b/tests/atests/common/dhcp.py
new file mode 100644
index 0000000..cedd7ee
--- /dev/null
+++ b/tests/atests/common/dhcp.py
@@ -0,0 +1,210 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# 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.
+#
+
+"""
+vOLT-HA DHCP Test Case module
+"""
+
+import os
+import testCaseUtils
+import logging
+import subprocess
+
+
+class DHCP(object):
+    """
+    This class implements voltha DHCP test case
+    """
+
+    CHECK_IP_FILENAME = 'voltha_check_ip.log'
+    DE_ASSIGN_IP_FILENAME = 'voltha_de-assign_ip.log'
+    ASSIGN_DHCP_IP_FILENAME = 'voltha_assign_dhcp_ip.log'
+    CHECK_ASSIGNED_IP_FILENAME = 'voltha_check_assigned_dhcp_ip.log'
+
+    def __init__(self):
+        self.dirs = dict()
+        self.dirs['log'] = None
+        self.dirs['root'] = None
+        self.dirs['voltha'] = None
+
+        self.__rgName = None
+        self.__fields = None
+        self.__deviceId = None
+        self.__portNumber = None
+
+    def h_set_log_dirs(self, root_dir, voltha_dir, log_dir):
+        testCaseUtils.config_dirs(self, log_dir, root_dir, voltha_dir)
+
+    def lookup_rg_pod_name(self):
+        self.__rgName = testCaseUtils.extract_pod_name('rg-').strip()
+
+    def discover_authorized_users(self):
+        testCaseUtils.send_command_to_onos_cli(testCaseUtils.get_dir(self, 'log'),
+                                               'voltha_onos_users.log', 'aaa-users')
+
+    def retrieve_authorized_users_device_id_and_port_number(self):
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'AUTHORIZED', 'voltha_onos_users.log')
+        assert statusLines, 'No Users Authorized'
+        self.__fields = testCaseUtils.parse_fields(statusLines, ',')
+        deviceField = self.__fields[2].strip()
+        deviceStr, equal, deviceId = deviceField.partition('=')
+        self.__deviceId = deviceId
+        portField = self.__fields[4].strip()
+        portNumStr, equal, portNum = portField.partition('=')
+        self.__portNumber = portNum
+
+    def add_subscriber_access(self):
+        testCaseUtils.send_command_to_onos_cli(testCaseUtils.get_dir(self, 'log'),
+                                               'voltha_add_subscriber_access.log', 'volt-add-subscriber-access %s %s'
+                                               % (self.__deviceId, self.__portNumber))
+
+    def should_now_have_two_dhcp_flows(self):
+        testCaseUtils.send_command_to_onos_cli(testCaseUtils.get_dir(self, 'log'),
+                                               'voltha_onos_flows.log', 'flows')
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'IP_PROTO:17', 'voltha_onos_flows.log')
+        assert statusLines, 'No DHCP Detection flows'
+        lines = statusLines.splitlines()
+        for line in lines:
+            self.__fields = testCaseUtils.parse_fields(line, ',')
+            inPortStr = self.__fields[10].strip()
+            selector, delimiter, inPort = inPortStr.partition('=[')
+            assert (inPort == 'IN_PORT:2' or inPort == 'IN_PORT:128'), 'DHCP detection flows not associated with expected ports'
+
+    def add_dhcp_server_configuration_data_in_onos(self):
+        logging.info('Adding DHCP Configuration Data to Onos NetCfg')
+        logging.debug('curl --user karaf:karaf -X POST -H "Content-Type: application/json" '
+                      'http://localhost:30120/onos/v1/network/configuration/apps/ -d @%s/tests/atests/build/dhcp_json'
+                      % testCaseUtils.get_dir(self, 'voltha'))
+        os.system('curl --user karaf:karaf -X POST -H "Content-Type: application/json" '
+                  'http://localhost:30120/onos/v1/network/configuration/apps/ -d @%s/tests/atests/build/dhcp_json'
+                  % testCaseUtils.get_dir(self, 'voltha'))
+
+    def activate_dhcp_server_in_onos(self):
+        logging.info('Activating DHCP server on Onos')
+        testCaseUtils.send_command_to_onos_cli(testCaseUtils.get_dir(self, 'log'),
+                                               'voltha_dhcp_server_activate.log', 'app activate dhcp')
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'Activated', 'voltha_dhcp_server_activate.log')
+        assert statusLines, 'DHCP server failed to be Activated'
+
+    def deactivate_dhcp_server_in_onos(self):
+        logging.info('Deactivating DHCP server on Onos')
+        testCaseUtils.send_command_to_onos_cli(testCaseUtils.get_dir(self, 'log'),
+                                               'voltha_dhcp_server_deactivate.log', 'app deactivate dhcp')
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'Deactivated', 'voltha_dhcp_server_deactivate.log')
+        assert statusLines, 'DHCP server failed to be Deactivated'
+
+    def query_for_default_ip_on_rg(self):
+        logging.info('De-assigning default IP on RG')
+        process_output = open('%s/%s' % (testCaseUtils.get_dir(self, 'log'), self.CHECK_IP_FILENAME), 'w')
+        ifconfigCheck1 = subprocess.Popen(['/usr/bin/kubectl', 'exec', '-n', 'voltha', self.__rgName, '--', 'bash', '-c',
+                                          'ifconfig'],
+                                          stdout=subprocess.PIPE,
+                                          stderr=subprocess.PIPE)
+        ifconfigCheck2 = subprocess.Popen(['grep', '-e', 'eth0', '-A1'], stdin=ifconfigCheck1.stdout,
+                                          stdout=process_output,
+                                          stderr=process_output)
+
+        ifconfigCheck1.wait()
+        ifconfigCheck1.stdout.close()
+        ifconfigCheck2.wait()
+
+        process_output.close()
+
+        testCaseUtils.print_log_file(self, self.CHECK_IP_FILENAME)
+
+    def de_assign_default_ip_on_rg(self):
+
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'inet', self.CHECK_IP_FILENAME)
+        if statusLines:
+            process_output = open('%s/%s' % (testCaseUtils.get_dir(self, 'log'), self.DE_ASSIGN_IP_FILENAME), 'w')
+            os.system('/usr/bin/kubectl exec -n voltha %s -- bash -c "ifconfig eth0 0.0.0.0"' % self.__rgName)
+            ifconfigDeassign1 = subprocess.Popen(['/usr/bin/kubectl', 'exec', '-n', 'voltha', self.__rgName, '--', 'bash', '-c',
+                                                 'ifconfig'],
+                                                 stdout=subprocess.PIPE,
+                                                 stderr=subprocess.PIPE)
+
+            ifconfigDeassign2 = subprocess.Popen(['grep', '-e', 'eth0', '-A1'], stdin=ifconfigDeassign1.stdout,
+                                                 stdout=process_output,
+                                                 stderr=process_output)
+            ifconfigDeassign1.wait()
+            ifconfigDeassign1.stdout.close()
+            ifconfigDeassign2.wait()
+
+            process_output.close()
+
+            statusLines = testCaseUtils.get_fields_from_grep_command(self, 'inet', self.DE_ASSIGN_IP_FILENAME)
+            assert not statusLines, 'IP addr not de-assigned'
+
+        else:
+            logging.info('No default IP addr assigned to eth0')
+
+    def assign_dhcp_ip_addr_to_rg(self):
+        logging.info('Assigning IP addr on RG using DHCP')
+        process_output = open('%s/%s' % (testCaseUtils.get_dir(self, 'log'), self.ASSIGN_DHCP_IP_FILENAME), 'w')
+        dhcpAssignIp1 = subprocess.Popen(['/usr/bin/kubectl', 'exec', '-it', '-n', 'voltha', self.__rgName, '--',
+                                         'dhclient', '-v', 'eth0'],
+                                         stdout=process_output,
+                                         stderr=process_output)
+
+        dhcpAssignIp1.wait()
+        process_output.close()
+
+        testCaseUtils.print_log_file(self, self.ASSIGN_DHCP_IP_FILENAME)
+
+    def should_have_dhcp_assigned_ip(self):
+        process_output = open('%s/%s' % (testCaseUtils.get_dir(self, 'log'), self.CHECK_ASSIGNED_IP_FILENAME), 'w')
+        ifConfigCheck1 = subprocess.Popen(['/usr/bin/kubectl', 'exec', '-n', 'voltha', self.__rgName, '--', 'bash', '-c',
+                                          'ifconfig'],
+                                          stdout=subprocess.PIPE,
+                                          stderr=subprocess.PIPE)
+
+        ifConfigCheck2 = subprocess.Popen(['grep', '-e', 'eth0', '-A1'], stdin=ifConfigCheck1.stdout,
+                                          stdout=process_output,
+                                          stderr=process_output)
+        ifConfigCheck1.wait()
+        ifConfigCheck1.stdout.close()
+        ifConfigCheck2.wait()
+
+        process_output.close()
+
+        testCaseUtils.print_log_file(self, self.CHECK_ASSIGNED_IP_FILENAME)
+
+        statusLines = testCaseUtils.get_fields_from_grep_command(self, 'inet', self.CHECK_ASSIGNED_IP_FILENAME)
+        assert statusLines, 'DHCP IP addr not assigned'
+
+
+def set_firewall_rules():
+    logging.info('Setting Firewall rules for DHCP test')
+    os.system('sudo iptables -P FORWARD ACCEPT')
+
+
+def run_test(root_dir, voltha_dir, log_dir):
+
+    set_firewall_rules()
+    dhcp = DHCP()
+    dhcp.h_set_log_dirs(root_dir, voltha_dir, log_dir)
+    dhcp.lookup_rg_pod_name()
+    dhcp.discover_authorized_users()
+    dhcp.retrieve_authorized_users_device_id_and_port_number()
+    dhcp.add_subscriber_access()
+    dhcp.should_now_have_two_dhcp_flows()
+    dhcp.deactivate_dhcp_server_in_onos()
+    dhcp.add_dhcp_server_configuration_data_in_onos()
+    dhcp.activate_dhcp_server_in_onos()
+    dhcp.query_for_default_ip_on_rg()
+    dhcp.de_assign_default_ip_on_rg()
+    dhcp.assign_dhcp_ip_addr_to_rg()
+    dhcp.should_have_dhcp_assigned_ip()
diff --git a/tests/atests/common/discovery.py b/tests/atests/common/discovery.py
index fb57a22..1c5234a 100755
--- a/tests/atests/common/discovery.py
+++ b/tests/atests/common/discovery.py
@@ -56,7 +56,7 @@
         logging.info('Logical Device Info')
         statusLines = testCaseUtils.get_fields_from_grep_command(self, self.__logicalDeviceType, 'voltha_devices_after_enable.log')
         assert statusLines, 'No Logical Devices listed under devices'
-        self.__fields = testCaseUtils.parse_fields(statusLines)
+        self.__fields = testCaseUtils.parse_fields(statusLines, '|')
         self.__logicalDeviceId = self.__fields[4].strip()
         testCaseUtils.send_command_to_voltha_cli(testCaseUtils.get_dir(self, 'log'),
                                                  'voltha_logical_device.log', 'logical_device ' + self.__logicalDeviceId,
@@ -70,7 +70,7 @@
     def logical_device_ports_should_exist(self):
         statusLines = testCaseUtils.get_fields_from_grep_command(self, self.__oltDeviceId, 'voltha_logical_device_ports.log')
         assert statusLines, 'No Olt device listed under logical device ports'
-        self.__fields = testCaseUtils.parse_fields(statusLines)
+        self.__fields = testCaseUtils.parse_fields(statusLines, '|')
         portType = self.__fields[1].strip()
         assert portType == 'nni', 'Port type for %s does not match expected nni' % self.__oltDeviceId
         for onuDeviceId in self.__onuDeviceIds:
@@ -78,7 +78,7 @@
             assert statusLines, 'No Onu device %s listed under logical device ports' % onuDeviceId
             lines = statusLines.splitlines()
             for line in lines:
-                self.__fields = testCaseUtils.parse_fields(line)
+                self.__fields = testCaseUtils.parse_fields(line, '|')
                 portType = self.__fields[1].strip()
                 assert portType == 'uni-128', 'Port type for %s does not match expected uni-128' % onuDeviceId
 
@@ -94,7 +94,7 @@
         logging.info('Olt Discovery')
         statusLines = testCaseUtils.get_fields_from_grep_command(self, self.__oltType, 'voltha_devices_after_enable.log')
         assert statusLines, 'No Olt listed under devices'
-        self.__fields = testCaseUtils.parse_fields(statusLines)
+        self.__fields = testCaseUtils.parse_fields(statusLines, '|')
         self.__oltDeviceId = self.__fields[1].strip()
         testCaseUtils.send_command_to_voltha_cli(testCaseUtils.get_dir(self, 'log'),
                                                  'voltha_olt_device.log', 'device ' + self.__oltDeviceId, 'voltha_olt_ports.log',
@@ -108,7 +108,7 @@
         assert statusLines, 'No Onu listed under devices'
         lines = statusLines.splitlines()
         for line in lines:
-            self.__fields = testCaseUtils.parse_fields(line)
+            self.__fields = testCaseUtils.parse_fields(line, '|')
             onuDeviceId = self.__fields[1].strip()
             self.__onuDeviceIds.append(onuDeviceId)
             testCaseUtils.send_command_to_voltha_cli(testCaseUtils.get_dir(self, 'log'),
@@ -124,7 +124,7 @@
         assert statusLines, 'No Olt device listed under ports'
         lines = statusLines.splitlines()
         for line in lines:
-            self.__fields = testCaseUtils.parse_fields(line)
+            self.__fields = testCaseUtils.parse_fields(line, '|')
             assert (self.check_states(self.__oltDeviceId) is True), 'States of %s does match expected ' % self.__oltDeviceId
             portType = self.__fields[3].strip()
             assert (portType == 'ETHERNET_NNI' or portType == 'PON_OLT'),\
@@ -145,7 +145,7 @@
             assert statusLines, 'No Onu device listed under ports'
             lines = statusLines.splitlines()
             for line in lines:
-                self.__fields = testCaseUtils.parse_fields(line)
+                self.__fields = testCaseUtils.parse_fields(line, '|')
                 assert (self.check_states(onuDeviceId) is True), 'States of %s does match expected ' % onuDeviceId
                 portType = self.__fields[3].strip()
                 assert (portType == 'ETHERNET_UNI' or portType == 'PON_ONU'),\
diff --git a/tests/atests/common/preprovisioning.py b/tests/atests/common/preprovisioning.py
index affa991..a7f8a7f 100755
--- a/tests/atests/common/preprovisioning.py
+++ b/tests/atests/common/preprovisioning.py
@@ -71,7 +71,7 @@
     def check_olt_fields_before_enabling(self):
         statusLines = testCaseUtils.get_fields_from_grep_command(self, self.__oltType, 'voltha_devices_before_enable.log')
         assert statusLines, 'No Olt listed under devices'
-        self.__fields = testCaseUtils.parse_fields(statusLines)
+        self.__fields = testCaseUtils.parse_fields(statusLines, '|')
         self.__oltDeviceId = self.__fields[1].strip()
         logging.debug("OLT device id = %s" % self.__oltDeviceId)
         adminState = self.__fields[3].strip()
@@ -95,7 +95,7 @@
     def check_olt_fields_after_enabling(self):
         statusLines = testCaseUtils.get_fields_from_grep_command(self, self.__oltType, 'voltha_devices_after_enable.log')
         assert statusLines, 'No Olt listed under devices'
-        self.__fields = testCaseUtils.parse_fields(statusLines)
+        self.__fields = testCaseUtils.parse_fields(statusLines, '|')
         assert self.check_states(self.__oltType), 'States of %s does match expected' % self.__oltType
         hostPort = self.__fields[11].strip()
         assert hostPort, 'hostPort field is empty'
@@ -110,7 +110,7 @@
         lenLines = len(lines)
         assert lenLines == 1, 'Fixed single onu does not match, ONU Count was %d' % lenLines
         for line in lines:
-            self.__fields = testCaseUtils.parse_fields(line)
+            self.__fields = testCaseUtils.parse_fields(line, '|')
             assert (self.check_states(self.__onuType) is True), 'States of %s does match expected' % self.__onuType
         
     def enable(self):
diff --git a/tests/atests/common/testCaseUtils.py b/tests/atests/common/testCaseUtils.py
index e51199d..ff13db6 100755
--- a/tests/atests/common/testCaseUtils.py
+++ b/tests/atests/common/testCaseUtils.py
@@ -77,14 +77,14 @@
     child.close()
 
 
-def send_command_to_onos_cli(log_dir, cmd, log_file):
+def send_command_to_onos_cli(log_dir, log_file, cmd):
     output = open(log_dir + '/' + log_file, 'w')
     child = pexpect.spawn('ssh -p 30115 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no karaf@localhost')
     child.expect('[pP]assword:')
     child.sendline('karaf')
-    child.expect('(\\x1b\[\d*;?\d+m){1,2}onos>(\\x1b\[\d*;?\d+m){1,2}')
+    child.expect('(\\x1b\[\d*;?\d+m){1,2}onos> (\\x1b\[\d*;?\d+m){1,2}')
     child.sendline(cmd)
-    child.expect('(\\x1b\[\d*;?\d+m){1,2}onos>(\\x1b\[\d*;?\d+m){1,2}')
+    child.expect('(\\x1b\[\d*;?\d+m){1,2}onos> (\\x1b\[\d*;?\d+m){1,2}')
 
     output.write(child.before)
     
@@ -99,8 +99,8 @@
     return statusLines
     
 
-def parse_fields(status_line):
-    statusList = status_line.split("|")
+def parse_fields(status_line, delimiter):
+    statusList = status_line.split(delimiter)
     return statusList
 
 
diff --git a/tests/atests/robot/voltha_automated_test_suite.robot b/tests/atests/robot/voltha_automated_test_suite.robot
index 9add442..efa6639 100755
--- a/tests/atests/robot/voltha_automated_test_suite.robot
+++ b/tests/atests/robot/voltha_automated_test_suite.robot
@@ -20,24 +20,28 @@
 Library           ../common/preprovisioning.py
 Library           ../common/discovery.py
 Library           ../common/authentication.py
+Library           ../common/dhcp.py
 Library           volthaMngr.VolthaMngr
 Library           preprovisioning.Preprovisioning
 Library           discovery.Discovery
 Library           authentication.Authentication
+Library           dhcp.DHCP
 
 Suite Setup        Start Voltha      
 Suite Teardown     Stop Voltha
 
 *** Variables ***
-${LOG_DIR}        /tmp/voltha_test_results
-${ROOT_DIR}       ${EMPTY}
-${VOLTHA_DIR}     ${EMPTY}
-${ONOS_SSH_PORT}  8101
-${OLT_IP_ADDR}    olt.voltha.svc
-${OLT_PORT_ID}    50060
-${LOGICAL_TYPE}   olt.voltha.svc
-${OLT_TYPE}       ponsim_olt
-${ONU_TYPE}       ponsim_onu
+${LOG_DIR}              /tmp/voltha_test_results
+${ROOT_DIR}             ${EMPTY}
+${VOLTHA_DIR}           ${EMPTY}
+${ONOS_SSH_PORT}        8101
+${OLT_IP_ADDR}          olt.voltha.svc
+${OLT_PORT_ID}          50060
+${LOGICAL_TYPE}         olt.voltha.svc
+${OLT_TYPE}             ponsim_olt
+${ONU_TYPE}             ponsim_onu
+${RETRY_TIMEOUT_60}     60s
+${RETRY_INTERVAL_2}     2s
 
 *** Test Cases ***
 Olt Pre Provisioning
@@ -49,11 +53,11 @@
     P Set Log Dirs      ${LOG_DIR}
     P Configure         ${OLT_IP_ADDR}    ${OLT_PORT_ID}    ${OLT_TYPE}    ${ONU_TYPE}
     Preprovision Olt
-    Wait Until Keyword Succeeds    60s    2s    Query Devices Before Enabling
+    Wait Until Keyword Succeeds    ${RETRY_TIMEOUT_60}    ${RETRY_INTERVAL_2}    Query Devices Before Enabling
     Status Should Be Success After Preprovision Command
     Check Olt Fields Before Enabling
     Enable
-    Wait Until Keyword Succeeds    60s    2s    Query Devices After Enabling
+    Wait Until Keyword Succeeds    ${RETRY_TIMEOUT_60}    ${RETRY_INTERVAL_2}    Query Devices After Enabling
     Status Should Be Success After Enable Command
     Check Olt Fields After Enabling
     Check Onu Fields After Enabling
@@ -61,7 +65,8 @@
 Olt Onu Discovery
     [Documentation]     Olt Onu Discovery
     ...                 This test covers both Onu Discovery and yet to be developped Olt Discovery
-    ...                 It aims to verify the integrity of all port fields under each discrete device.
+    ...                 It aims to verify the integrity of all port fields under each discrete device, including
+    ...                 Logical Device.
     ...                 It also insures that the peers fields contains device Id entries for the corresponding 
     ...                 Olt or Onu device. Functionality to support multiple ONU accomodated
     ...                 The extent of the flow validation is limited to checking whether number of Flows is > 0
@@ -94,6 +99,28 @@
     Verify Authentication Should Have Disconnected
     Verify Authentication Should Have Terminated    
 
+Dhcp IP Address Assignment on RG
+    [Documentation]     DHCP assigned IP Address
+    ...                 A DHCP server is configured and Activated on Onos. We need to change
+    ...                 the Firewall rules so as to allow packets to flow between RG and OLT/ONU
+    ...                 We also must add a second DHCP flow rule in onos in the direction from NNI
+    ...                 by calling 'add subscriber access' on onos. We then deassign the default
+    ...                 IP address granted to RG upon instantiating the RG pod. Finally we invoke
+    ...                 'dhclient' on RG to request a DHCP IP address.
+    H Set Log Dirs      ${ROOT_DIR}     ${VOLTHA_DIR}    ${LOG_DIR}
+    Lookup Rg Pod Name
+    Set Firewall Rules
+    Discover Authorized Users
+    Retrieve Authorized Users Device Id And Port Number
+    Add Subscriber Access
+    Should Now Have Two Dhcp Flows
+    Add Dhcp Server Configuration Data In Onos
+    Activate Dhcp Server In Onos
+    Wait Until Keyword Succeeds  ${RETRY_TIMEOUT_60}    ${RETRY_INTERVAL_2}    Query For Default Ip On Rg
+    De Assign Default Ip On Rg
+    Wait Until Keyword Succeeds  ${RETRY_TIMEOUT_60}    ${RETRY_INTERVAL_2}    Assign Dhcp Ip Addr To Rg
+    Wait Until Keyword Succeeds  ${RETRY_TIMEOUT_60}    ${RETRY_INTERVAL_2}    Should Have Dhcp Assigned Ip
+
 *** Keywords ***
 Start Voltha
     [Documentation]     Start Voltha infrastructure to run test(s). This includes starting all