diff options
| -rw-r--r-- | interface-definitions/service_dhcp-server.xml.in | 21 | ||||
| -rw-r--r-- | python/vyos/template.py | 15 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_service_dhcp-server.py | 65 | ||||
| -rwxr-xr-x | src/conf_mode/service_dhcp-server.py | 8 | ||||
| -rwxr-xr-x | src/op_mode/generate_tech-support_archive.py | 2 | 
5 files changed, 104 insertions, 7 deletions
| diff --git a/interface-definitions/service_dhcp-server.xml.in b/interface-definitions/service_dhcp-server.xml.in index 2afa05a8a..cb5f9a804 100644 --- a/interface-definitions/service_dhcp-server.xml.in +++ b/interface-definitions/service_dhcp-server.xml.in @@ -22,6 +22,27 @@              </properties>              <children>                #include <include/source-address-ipv4.xml.i> +              <leafNode name="mode"> +                <properties> +                  <help>Configure high availability mode</help> +                  <completionHelp> +                    <list>active-active active-passive</list> +                  </completionHelp> +                  <valueHelp> +                    <format>active-active</format> +                    <description>Both server attend DHCP requests</description> +                  </valueHelp> +                  <valueHelp> +                    <format>active-passive</format> +                    <description>Only primary server attends DHCP requests</description> +                  </valueHelp> +                  <constraint> +                    <regex>(active-active|active-passive)</regex> +                  </constraint> +                  <constraintErrorMessage>Invalid DHCP high availability mode</constraintErrorMessage> +                </properties> +                <defaultValue>active-active</defaultValue> +              </leafNode>                <leafNode name="remote">                  <properties>                    <help>IPv4 remote address used for connection</help> diff --git a/python/vyos/template.py b/python/vyos/template.py index 3e468eb82..ac77e8a3d 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -823,10 +823,19 @@ def kea_high_availability_json(config):      source_addr = config['source_address']      remote_addr = config['remote'] +    ha_mode = 'hot-standby' if config['mode'] == 'active-passive' else 'load-balancing' +    ha_role = config['status'] + +    if ha_role == 'primary': +        peer1_role = 'primary' +        peer2_role = 'standby' if ha_mode == 'hot-standby' else 'secondary' +    else: +        peer1_role = 'standby' if ha_mode == 'hot-standby' else 'secondary' +        peer2_role = 'primary'      data = {          'this-server-name': os.uname()[1], -        'mode': 'hot-standby', +        'mode': ha_mode,          'heartbeat-delay': 10000,          'max-response-delay': 10000,          'max-ack-delay': 5000, @@ -835,13 +844,13 @@ def kea_high_availability_json(config):          {              'name': os.uname()[1],              'url': f'http://{source_addr}:647/', -            'role': 'standby' if config['status'] == 'secondary' else 'primary', +            'role': peer1_role,              'auto-failover': True          },          {              'name': config['name'],              'url': f'http://{remote_addr}:647/', -            'role': 'primary' if config['status'] == 'secondary' else 'standby', +            'role': peer2_role,              'auto-failover': True          }]      } diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py index abf40cd3b..46c4e25a1 100755 --- a/smoketest/scripts/cli/test_service_dhcp-server.py +++ b/smoketest/scripts/cli/test_service_dhcp-server.py @@ -699,6 +699,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):          self.cli_set(base_path + ['high-availability', 'name', failover_name])          self.cli_set(base_path + ['high-availability', 'remote', failover_remote])          self.cli_set(base_path + ['high-availability', 'status', 'primary']) +        ## No mode defined -> its active-active mode by default          # commit changes          self.cli_commit() @@ -717,7 +718,69 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):          self.verify_config_object(              obj,              ['Dhcp4', 'hooks-libraries', 0, 'parameters', 'high-availability', 0, 'peers'], -            {'name': failover_name, 'url': f'http://{failover_remote}:647/', 'role': 'standby', 'auto-failover': True}) +            {'name': failover_name, 'url': f'http://{failover_remote}:647/', 'role': 'secondary', 'auto-failover': True}) + +        self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', shared_net_name) +        self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', subnet) + +        # Verify options +        self.verify_config_object( +                obj, +                ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'], +                {'name': 'routers', 'data': router}) + +        # Verify pools +        self.verify_config_object( +                obj, +                ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'pools'], +                {'pool': f'{range_0_start} - {range_0_stop}'}) + +        # Check for running process +        self.assertTrue(process_named_running(PROCESS_NAME)) +        self.assertTrue(process_named_running(CTRL_PROCESS_NAME)) + +    def test_dhcp_high_availability_standby(self): +        shared_net_name = 'FAILOVER' +        failover_name = 'VyOS-Failover' + +        range_0_start = inc_ip(subnet, 10) +        range_0_stop  = inc_ip(subnet, 20) + +        pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet] +        self.cli_set(pool + ['subnet-id', '1']) +        # we use the first subnet IP address as default gateway +        self.cli_set(pool + ['option', 'default-router', router]) +        self.cli_set(pool + ['range', '0', 'start', range_0_start]) +        self.cli_set(pool + ['range', '0', 'stop', range_0_stop]) + +        # failover +        failover_local = router +        failover_remote = inc_ip(router, 1) + +        self.cli_set(base_path + ['high-availability', 'source-address', failover_local]) +        self.cli_set(base_path + ['high-availability', 'name', failover_name]) +        self.cli_set(base_path + ['high-availability', 'remote', failover_remote]) +        self.cli_set(base_path + ['high-availability', 'status', 'secondary']) +        self.cli_set(base_path + ['high-availability', 'mode', 'active-passive']) + +        # commit changes +        self.cli_commit() + +        config = read_file(KEA4_CONF) +        obj = loads(config) + +        # Verify failover +        self.verify_config_value(obj, ['Dhcp4', 'control-socket'], 'socket-name', KEA4_CTRL) + +        self.verify_config_object( +            obj, +            ['Dhcp4', 'hooks-libraries', 0, 'parameters', 'high-availability', 0, 'peers'], +            {'name': os.uname()[1], 'url': f'http://{failover_local}:647/', 'role': 'standby', 'auto-failover': True}) + +        self.verify_config_object( +            obj, +            ['Dhcp4', 'hooks-libraries', 0, 'parameters', 'high-availability', 0, 'peers'], +            {'name': failover_name, 'url': f'http://{failover_remote}:647/', 'role': 'primary', 'auto-failover': True})          self.verify_config_value(obj, ['Dhcp4', 'shared-networks'], 'name', shared_net_name)          self.verify_config_value(obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'subnet', subnet) diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py index bf4454fda..f4fb78f57 100755 --- a/src/conf_mode/service_dhcp-server.py +++ b/src/conf_mode/service_dhcp-server.py @@ -143,8 +143,12 @@ def get_config(config=None):                          dhcp['shared_network_name'][network]['subnet'][subnet].update(                                  {'range' : new_range_dict}) -    if dict_search('high_availability.certificate', dhcp): -        dhcp['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) +    if len(dhcp['high_availability']) == 1: +        ## only default value for mode is set, need to remove ha node +        del dhcp['high_availability'] +    else: +        if dict_search('high_availability.certificate', dhcp): +            dhcp['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)      return dhcp diff --git a/src/op_mode/generate_tech-support_archive.py b/src/op_mode/generate_tech-support_archive.py index c490b0137..41b53cd15 100755 --- a/src/op_mode/generate_tech-support_archive.py +++ b/src/op_mode/generate_tech-support_archive.py @@ -120,7 +120,7 @@ if __name__ == '__main__':      # Temporary directory creation      tmp_dir_path = f'{tmp_path}/drops-debug_{time_now}'      tmp_dir: Path = Path(tmp_dir_path) -    tmp_dir.mkdir() +    tmp_dir.mkdir(parents=True)      report_file: Path = Path(f'{tmp_dir_path}/show_tech-support_report.txt')      report_file.touch() | 
