diff --git a/configutilities/configutilities/configutilities/__init__.py b/configutilities/configutilities/configutilities/__init__.py index bd7610e820..0717792c47 100755 --- a/configutilities/configutilities/configutilities/__init__.py +++ b/configutilities/configutilities/configutilities/__init__.py @@ -29,4 +29,5 @@ from configutilities.common.utils import validate_address # noqa: F401 from configutilities.common.utils import ip_version_to_string # noqa: F401 from configutilities.common.utils import lag_mode_to_str # noqa: F401 from configutilities.common.utils import validate_openstack_password # noqa: F401 +from configutilities.common.utils import validate_nameserver_address_str # noqa: F401 from configutilities.common.utils import extract_openstack_password_rules_from_file # noqa: F401 diff --git a/configutilities/configutilities/configutilities/common/validator.py b/configutilities/configutilities/configutilities/common/validator.py index 2bba43351e..3045459bf0 100644 --- a/configutilities/configutilities/configutilities/common/validator.py +++ b/configutilities/configutilities/configutilities/common/validator.py @@ -23,6 +23,7 @@ from configutilities.common.utils import is_mtu_valid from configutilities.common.utils import get_service from configutilities.common.utils import get_optional from configutilities.common.utils import validate_address_str +from configutilities.common.utils import validate_nameserver_address_str from configutilities.common.exceptions import ConfigFail from configutilities.common.exceptions import ValidateFail @@ -944,8 +945,25 @@ class ConfigValidator(object): raise ConfigFail("SDN Configuration is no longer supported") def validate_dns(self): - if self.conf.has_section('DNS'): - raise ConfigFail("DNS Configuration is no longer supported") + # DNS config is optional + if not self.conf.has_section('DNS'): + return + if self.cgcs_conf is not None: + self.cgcs_conf.add_section('cDNS') + for x in range(0, 3): + if self.conf.has_option('DNS', 'NAMESERVER_' + str(x + 1)): + dns_address_str = self.conf.get('DNS', 'NAMESERVER_' + str( + x + 1)) + try: + dns_address = validate_nameserver_address_str( + dns_address_str) + if self.cgcs_conf is not None: + self.cgcs_conf.set('cDNS', 'NAMESERVER_' + str(x + 1), + str(dns_address)) + except ValidateFail as e: + raise ConfigFail( + "Invalid DNS NAMESERVER value of %s.\nReason: %s" % + (dns_address_str, e)) def validate_ntp(self): if self.conf.has_section('NTP'): diff --git a/controllerconfig/controllerconfig/controllerconfig/configassistant.py b/controllerconfig/controllerconfig/controllerconfig/configassistant.py index 1a224ba90c..b1c1b5db71 100644 --- a/controllerconfig/controllerconfig/controllerconfig/configassistant.py +++ b/controllerconfig/controllerconfig/controllerconfig/configassistant.py @@ -28,6 +28,7 @@ from configutilities import validate_network_str from configutilities import validate_address_str from configutilities import validate_address from configutilities import ip_version_to_string +from configutilities import validate_nameserver_address_str from configutilities import validate_openstack_password from configutilities import DEFAULT_DOMAIN_NAME from netaddr import IPNetwork @@ -463,6 +464,10 @@ class ConfigAssistant(): # SDN config self.enable_sdn = False + + # DNS config + self.nameserver_addresses = ["8.8.8.8", "8.8.4.4", ""] + # HTTPS self.enable_https = False # Network config @@ -2666,6 +2671,64 @@ class ConfigAssistant(): """ Cluster host interface configuration complete""" self.cluster_host_interface_configured = True + def get_dns_servers(self): + """Produce a comma separated list of DNS servers.""" + servers = [str(s) for s in self.nameserver_addresses if s] + return ",".join(servers) + + def input_dns_config(self): + """Allow user to input DNS config and perform validation.""" + + print("\nDomain Name System (DNS):") + print("-------------------------\n") + print(textwrap.fill( + "Configuring DNS servers accessible through the external " + "OAM network allows domain names to be mapped to IP " + "addresses.", 80)) + print(textwrap.fill( + "The configuration of at least one DNS server is mandatory. To " + "skip the configuration of one or more nameservers (1 to 3 are " + "allowed), enter C to continue to the next configuration item.", + 80)) + print('') + + if self.external_oam_subnet.version == 6: + self.nameserver_addresses = ["2001:4860:4860::8888", + "2001:4860:4860::8844", ""] + + for server in range(0, len(self.nameserver_addresses)): + while True: + user_input = raw_input( + "Nameserver " + str(server + 1) + " [" + + str(self.nameserver_addresses[server]) + "]: ") + if user_input.lower() == 'q': + raise UserQuit + elif user_input.lower() == 'c': + if server == 0: + print("At least one DNS server is required.") + continue + for x in range(server, len(self.nameserver_addresses)): + self.nameserver_addresses[x] = "" + return + elif user_input == "": + user_input = self.nameserver_addresses[server] + # Pressing enter with a blank default will continue + if user_input == "": + return + + try: + try: + ip_input = validate_nameserver_address_str( + user_input, self.external_oam_subnet.version) + except ValidateFail as e: + print('{}'.format(e)) + continue + self.nameserver_addresses[server] = ip_input + break + except (AddrFormatError, ValueError): + print("Invalid address - please enter a valid IPv4 " + "address") + def input_authentication_config(self): """Allow user to input authentication config and perform validation. """ @@ -2711,6 +2774,8 @@ class ConfigAssistant(): self.management_interface_configured = True self.external_oam_interface_configured = True self.default_pxeboot_config() + if not self.kubernetes: + self.nameserver_addresses = ["", "", ""] if utils.is_cpe(): self.system_mode = sysinv_constants.SYSTEM_MODE_DUPLEX @@ -2747,6 +2812,8 @@ class ConfigAssistant(): if self.kubernetes: self.input_cluster_host_config() self.input_external_oam_config() + if self.kubernetes: + self.input_dns_config() self.input_authentication_config() def is_valid_management_multicast_subnet(self, ip_subnet): @@ -3079,6 +3146,19 @@ class ConfigAssistant(): self.external_oam_interface_configured = True + # DNS configuration + if self.kubernetes: + if config.has_section('cDNS'): + self.nameserver_addresses = ["", "", ""] + for x in range(0, len(self.nameserver_addresses)): + if config.has_option('cDNS', + 'NAMESERVER_' + str(x + 1)): + cvalue = config.get('cDNS', + 'NAMESERVER_' + str(x + 1)) + if cvalue != "NC" and cvalue != "": + self.nameserver_addresses[x] = \ + IPAddress(cvalue) + # SDN Network configuration if config.has_option('cSDN', 'ENABLE_SDN'): raise ConfigFail("The option ENABLE_SDN is no longer " @@ -3511,6 +3591,18 @@ class ConfigAssistant(): else: print("External OAM address: " + str(self.external_oam_address_0)) + if self.kubernetes: + print("\nDNS Configuration") + print("-----------------") + dns_config = False + for x in range(0, len(self.nameserver_addresses)): + if self.nameserver_addresses[x]: + print("Nameserver " + str(x + 1) + ": " + + str(self.nameserver_addresses[x])) + dns_config = True + if not dns_config: + print("External DNS servers not configured") + if self.region_config: print("\nRegion Configuration") print("--------------------") @@ -3796,6 +3888,17 @@ class ConfigAssistant(): f.write("EXTERNAL_OAM_1_ADDRESS=" + str(self.external_oam_address_1) + "\n") + if self.kubernetes: + # DNS configuration + f.write("\n[cDNS]") + f.write("\n# DNS Configuration\n") + for x in range(0, len(self.nameserver_addresses)): + if self.nameserver_addresses[x]: + f.write("NAMESERVER_" + str(x + 1) + "=" + + str(self.nameserver_addresses[x]) + "\n") + else: + f.write("NAMESERVER_" + str(x + 1) + "=NC" + "\n") + # Network configuration f.write("\n[cNETWORK]") f.write("\n# Data Network Configuration\n") @@ -5188,6 +5291,17 @@ class ConfigAssistant(): "required_patches": "N/A"} client.sysinv.load.create(**patch) + def _populate_dns_config(self, client): + # Retrieve the list of dns servers to get the uuid + dns_list = client.sysinv.idns.list() + dns_record = dns_list[0] + values = { + 'nameservers': self.get_dns_servers(), + 'action': 'apply' + } + patch = sysinv.dict_to_patch(values) + client.sysinv.idns.update(dns_record.uuid, patch) + def populate_initial_config(self): """Populate initial system inventory configuration""" try: @@ -5195,6 +5309,8 @@ class ConfigAssistant(): self._populate_system_config(client) self._populate_load_config(client) self._populate_network_config(client) + if self.kubernetes: + self._populate_dns_config(client) controller = self._populate_controller_config(client) # ceph_mon config requires controller host to be created self._inventory_config_complete_wait(client, controller) diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.kubernetes b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.kubernetes new file mode 100755 index 0000000000..24cb70edd6 --- /dev/null +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.kubernetes @@ -0,0 +1,86 @@ +[cSYSTEM] +# System Configuration +SYSTEM_MODE=duplex +TIMEZONE=UTC + +[cPXEBOOT] +# PXEBoot Network Support Configuration +PXECONTROLLER_FLOATING_HOSTNAME=pxecontroller + +[cMGMT] +# Management Network Configuration +MANAGEMENT_INTERFACE_NAME=eth1 +MANAGEMENT_INTERFACE=eth1 +MANAGEMENT_MTU=1500 +MANAGEMENT_SUBNET=192.168.204.0/24 +LAG_MANAGEMENT_INTERFACE=no +CONTROLLER_FLOATING_ADDRESS=192.168.204.2 +CONTROLLER_0_ADDRESS=192.168.204.3 +CONTROLLER_1_ADDRESS=192.168.204.4 +NFS_MANAGEMENT_ADDRESS_1=192.168.204.5 +NFS_MANAGEMENT_ADDRESS_2=192.168.204.6 +CONTROLLER_FLOATING_HOSTNAME=controller +CONTROLLER_HOSTNAME_PREFIX=controller- +OAMCONTROLLER_FLOATING_HOSTNAME=oamcontroller +DYNAMIC_ADDRESS_ALLOCATION=yes +MANAGEMENT_MULTICAST_SUBNET=239.1.1.0/28 + +[cINFRA] +# Infrastructure Network Configuration +INFRASTRUCTURE_INTERFACE_NAME=NC +INFRASTRUCTURE_INTERFACE=NC +INFRASTRUCTURE_VLAN=NC +INFRASTRUCTURE_MTU=NC +INFRASTRUCTURE_SUBNET=NC +LAG_INFRASTRUCTURE_INTERFACE=no +INFRASTRUCTURE_BOND_MEMBER_0=NC +INFRASTRUCTURE_BOND_MEMBER_1=NC +INFRASTRUCTURE_BOND_POLICY=NC +CONTROLLER_0_INFRASTRUCTURE_ADDRESS=NC +CONTROLLER_1_INFRASTRUCTURE_ADDRESS=NC +NFS_INFRASTRUCTURE_ADDRESS_1=NC +STORAGE_0_INFRASTRUCTURE_ADDRESS=NC +STORAGE_1_INFRASTRUCTURE_ADDRESS=NC +CONTROLLER_INFRASTRUCTURE_HOSTNAME_SUFFIX=NC +INFRASTRUCTURE_START_ADDRESS=NC +INFRASTRUCTURE_END_ADDRESS=NC + +[cCLUSTER] +# Cluster Host Network Configuration +CLUSTER_INTERFACE_NAME=eth1 +CLUSTER_INTERFACE=eth1 +CLUSTER_VLAN=NC +CLUSTER_MTU=1500 +CLUSTER_SUBNET=192.168.206.0/24 +LAG_CLUSTER_INTERFACE=no + +[cEXT_OAM] +# External OAM Network Configuration +EXTERNAL_OAM_INTERFACE_NAME=eth0 +EXTERNAL_OAM_INTERFACE=eth0 +EXTERNAL_OAM_VLAN=NC +EXTERNAL_OAM_MTU=1500 +LAG_EXTERNAL_OAM_INTERFACE=no +EXTERNAL_OAM_SUBNET=10.10.10.0/24 +EXTERNAL_OAM_GATEWAY_ADDRESS=10.10.10.1 +EXTERNAL_OAM_FLOATING_ADDRESS=10.10.10.2 +EXTERNAL_OAM_0_ADDRESS=10.10.10.3 +EXTERNAL_OAM_1_ADDRESS=10.10.10.4 + +[cDNS] +# DNS Configuration +NAMESERVER_1=1.2.3.4 +NAMESERVER_2=5.6.7.8 +NAMESERVER_3=NC + +[cNETWORK] +# Data Network Configuration +VSWITCH_TYPE=ovs-dpdk + +[cSECURITY] +[cREGION] +# Region Configuration +REGION_CONFIG=False + +[cAUTHENTICATION] +ADMIN_PASSWORD=Li69nux* diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.cluster b/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes similarity index 94% rename from controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.cluster rename to controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes index 6117b7d4b4..d14364b7ca 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.cluster +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes @@ -44,6 +44,11 @@ CIDR=10.10.10.0/24 GATEWAY=10.10.10.1 LOGICAL_INTERFACE=LOGICAL_INTERFACE_2 +[DNS] +# DNS Configuration +NAMESERVER_1=1.2.3.4 +NAMESERVER_2=5.6.7.8 + ;[PXEBOOT_NETWORK] ;PXEBOOT_CIDR=192.168.203.0/24 diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_answerfile.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_answerfile.py index e0562d50e7..d87c735caa 100644 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_answerfile.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_answerfile.py @@ -19,13 +19,14 @@ import controllerconfig.common.constants as constants def _test_answerfile(tmpdir, filename, mock_get_net_device_list, mock_get_rootfs_node, - compare_results=True): + compare_results=True, + ca_options={}): """ Test import and generation of answerfile """ mock_get_net_device_list.return_value = \ ['eth0', 'eth1', 'eth2'] mock_get_rootfs_node.return_value = '/dev/sda' - assistant = ca.ConfigAssistant() + assistant = ca.ConfigAssistant(**ca_options) # Create the path to the answerfile answerfile = os.path.join( @@ -93,3 +94,10 @@ def test_answerfile_region_nuage_vrs(tmpdir): """ Test import of answerfile with region values for nuage_vrs""" _test_answerfile(tmpdir, "cgcs_config.region_nuage_vrs") + + +def test_answerfile_kubernetes(tmpdir): + """ Test import of answerfile with kubernetes values """ + + _test_answerfile(tmpdir, "cgcs_config.kubernetes", + ca_options={"kubernetes": True}) diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py index eda2692230..22f2224ddf 100644 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py @@ -42,7 +42,7 @@ def _test_system_config(filename): cr.create_cgcs_config_file(None, system_config, None, None, None, 0, validate_only=True) - # Validate the region config file. + # Validate the system config file. # Using onboard validation since the validator's reference version number # is only set at build-time when validating offboard validate(system_config, DEFAULT_CONFIG, None, False) @@ -508,14 +508,6 @@ def test_system_config_validation(): with pytest.raises(exceptions.ConfigFail): validate(system_config, DEFAULT_CONFIG, None, False) - # Test detection of unsupported DNS NAMESERVER - system_config = cr.parse_system_config(simple_systemfile) - system_config.add_section('DNS') - system_config.set('DNS', 'NAMESERVER_1', '8.8.8.8') - with pytest.raises(exceptions.ConfigFail): - cr.create_cgcs_config_file(None, system_config, None, None, None, 0, - validate_only=True) - # Test detection of unsupported NTP NTP_SERVER system_config = cr.parse_system_config(simple_systemfile) system_config.add_section('NTP') @@ -606,12 +598,13 @@ def test_pxeboot_range(): validate(system_config, DEFAULT_CONFIG, None, False) -def test_cluster_network(): - """ Test import of system_config file for cluster network address """ +def test_kubernetes(): + """ Test import of system_config file for kubernetes """ # Create the path to the system_config file systemfile = os.path.join( - os.getcwd(), "controllerconfig/tests/files/", "system_config.cluster") + os.getcwd(), "controllerconfig/tests/files/", + "system_config.kubernetes") # Test import and generation of answer file _test_system_config(systemfile) @@ -647,3 +640,10 @@ def test_cluster_network(): validate_only=True) with pytest.raises(exceptions.ConfigFail): validate(system_config, DEFAULT_CONFIG, None, False) + + # Test absence of optional DNS configuration + system_config = cr.parse_system_config(systemfile) + system_config.remove_section('DNS') + cr.create_cgcs_config_file(None, system_config, None, None, None, 0, + validate_only=True) + validate(system_config, DEFAULT_CONFIG, None, False) diff --git a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp index b6b6a74b15..f30dbd5da6 100644 --- a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp +++ b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp @@ -58,15 +58,8 @@ class platform::kubernetes::master::init # For initial controller install, configure kubernetes from scratch. $resolv_conf = '/etc/resolv.conf' - # Add a DNS server to allow access to kubernetes repo. This will no longer - # be required once we are using our own internal repo. - file_line { "${resolv_conf} nameserver 8.8.8.8": - path => $resolv_conf, - line => 'nameserver 8.8.8.8', - } - # Configure the master node. - -> file { '/etc/kubernetes/kubeadm.yaml': + file { '/etc/kubernetes/kubeadm.yaml': ensure => file, content => template('platform/kubeadm.yaml.erb'), }