diff --git a/configutilities/configutilities/configutilities/__init__.py b/configutilities/configutilities/configutilities/__init__.py index 0717792c47..a694fc1a6c 100755 --- a/configutilities/configutilities/configutilities/__init__.py +++ b/configutilities/configutilities/configutilities/__init__.py @@ -26,6 +26,8 @@ from configutilities.common.utils import is_mtu_valid # noqa: F401 from configutilities.common.utils import validate_network_str # noqa: F401 from configutilities.common.utils import validate_address_str # noqa: F401 from configutilities.common.utils import validate_address # noqa: F401 +from configutilities.common.utils import is_valid_url # noqa: F401 +from configutilities.common.utils import is_valid_domain_or_ip # 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 diff --git a/configutilities/configutilities/configutilities/common/utils.py b/configutilities/configutilities/configutilities/common/utils.py index 12540c431d..77d1c38314 100644 --- a/configutilities/configutilities/configutilities/common/utils.py +++ b/configutilities/configutilities/configutilities/common/utils.py @@ -11,6 +11,8 @@ import six from netaddr import IPNetwork from netaddr import IPAddress from netaddr import AddrFormatError +from netaddr import valid_ipv4 +from netaddr import valid_ipv6 from configutilities.common.exceptions import ValidateFail @@ -131,6 +133,65 @@ def is_valid_by_path(filename): return "/dev/disk/by-path" in filename and "-part" not in filename +def is_valid_url(url_str): + # Django URL validation patterns + r = re.compile( + r'^(?:http|ftp)s?://' # http:// or https:// + r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain... + r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' + r'localhost|' # localhost... + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip + r'(?::\d+)?' # optional port + r'(?:/?|[/?]\S+)$', re.IGNORECASE) + + url = r.match(url_str) + if url: + return True + else: + return False + + +def is_valid_domain(url_str): + r = re.compile( + r'^(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain... + r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' + r'[A-Za-z0-9-_]*)' # localhost, hostname + r'(?::\d+)?' # optional port + r'(?:/?|[/?]\S+)$', re.IGNORECASE) + + url = r.match(url_str) + if url: + return True + else: + return False + + +def is_valid_ipv4(address): + """Verify that address represents a valid IPv4 address.""" + try: + return valid_ipv4(address) + except Exception: + return False + + +def is_valid_ipv6(address): + try: + return valid_ipv6(address) + except Exception: + return False + + +def is_valid_domain_or_ip(url_str): + if is_valid_domain(url_str): + return True + elif is_valid_ipv4(url_str): + return True + elif is_valid_ipv6(url_str): + return True + else: + return False + + def validate_address_str(ip_address_str, network): """Determine whether an address is valid.""" try: diff --git a/configutilities/configutilities/configutilities/common/validator.py b/configutilities/configutilities/configutilities/common/validator.py index 3045459bf0..6fcf4a0718 100644 --- a/configutilities/configutilities/configutilities/common/validator.py +++ b/configutilities/configutilities/configutilities/common/validator.py @@ -24,6 +24,8 @@ 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.utils import is_valid_url +from configutilities.common.utils import is_valid_domain_or_ip from configutilities.common.exceptions import ConfigFail from configutilities.common.exceptions import ValidateFail @@ -965,6 +967,48 @@ class ConfigValidator(object): "Invalid DNS NAMESERVER value of %s.\nReason: %s" % (dns_address_str, e)) + def validate_docker_proxy(self): + if not self.conf.has_section('DOCKER_PROXY'): + return + if self.cgcs_conf is not None: + self.cgcs_conf.add_section('cDOCKER_PROXY') + # check http_proxy + if self.conf.has_option('DOCKER_PROXY', 'DOCKER_HTTP_PROXY'): + docker_http_proxy_str = self.conf.get( + 'DOCKER_PROXY', 'DOCKER_HTTP_PROXY') + if is_valid_url(docker_http_proxy_str): + if self.cgcs_conf is not None: + self.cgcs_conf.set('cDOCKER_PROXY', 'DOCKER_HTTP_PROXY', + docker_http_proxy_str) + else: + raise ConfigFail( + "Invalid DOCKER_HTTP_PROXY value of %s." % + docker_http_proxy_str) + # check https_proxy + if self.conf.has_option('DOCKER_PROXY', 'DOCKER_HTTPS_PROXY'): + docker_https_proxy_str = self.conf.get( + 'DOCKER_PROXY', 'DOCKER_HTTPS_PROXY') + if is_valid_url(docker_https_proxy_str): + if self.cgcs_conf is not None: + self.cgcs_conf.set('cDOCKER_PROXY', 'DOCKER_HTTPS_PROXY', + docker_https_proxy_str) + else: + raise ConfigFail( + "Invalid DOCKER_HTTPS_PROXY value of %s." % + docker_https_proxy_str) + # check no_proxy + if self.conf.has_option('DOCKER_PROXY', 'DOCKER_NO_PROXY'): + docker_no_proxy_list_str = self.conf.get( + 'DOCKER_PROXY', 'DOCKER_NO_PROXY').split(',') + for no_proxy_str in docker_no_proxy_list_str: + if not is_valid_domain_or_ip(no_proxy_str): + raise ConfigFail( + "Invalid DOCKER_NO_PROXY value of %s." % + no_proxy_str) + if self.cgcs_conf is not None: + self.cgcs_conf.set('cDOCKER_PROXY', 'DOCKER_NO_PROXY', + docker_no_proxy_list_str) + def validate_ntp(self): if self.conf.has_section('NTP'): raise ConfigFail("NTP Configuration is no longer supported") @@ -1421,6 +1465,8 @@ def validate(system_config, config_type=REGION_CONFIG, cgcs_config=None, # Neutron configuration - leave blank to use defaults # DNS configuration validator.validate_dns() + # Docker Proxy configuration + validator.validate_docker_proxy() # NTP configuration validator.validate_ntp() # Network configuration diff --git a/controllerconfig/controllerconfig/controllerconfig/configassistant.py b/controllerconfig/controllerconfig/controllerconfig/configassistant.py index b1c1b5db71..72b202ccc7 100644 --- a/controllerconfig/controllerconfig/controllerconfig/configassistant.py +++ b/controllerconfig/controllerconfig/controllerconfig/configassistant.py @@ -29,6 +29,8 @@ 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 is_valid_url +from configutilities import is_valid_domain_or_ip from configutilities import validate_openstack_password from configutilities import DEFAULT_DOMAIN_NAME from netaddr import IPNetwork @@ -462,6 +464,12 @@ class ConfigAssistant(): self.cluster_pod_subnet = IPNetwork("172.16.0.0/16") self.cluster_service_subnet = IPNetwork("10.96.0.0/12") + # Docker Proxy config + self.enable_docker_proxy = False + self.docker_http_proxy = "" + self.docker_https_proxy = "" + self.docker_no_proxy = "" + # SDN config self.enable_sdn = False @@ -2729,6 +2737,118 @@ class ConfigAssistant(): print("Invalid address - please enter a valid IPv4 " "address") + def input_docker_proxy_config(self): + """Allow user to input docker proxy config.""" + + print("\nDocker Proxy:") + print("-------------------------\n") + print(textwrap.fill( + "Docker proxy is needed if host OAM network is behind a proxy.", + 80)) + print('') + while True: + user_input = input( + "Configure docker proxy [y/N]: ") + if user_input.lower() == 'q': + raise UserQuit + elif user_input.lower() == 'y': + while True: + user_input = input( + "HTTP proxy (http://example.proxy:port): ") + if user_input.lower() == 'q': + raise UserQuit + if user_input: + if is_valid_url(user_input): + self.docker_http_proxy = user_input + break + else: + print("Please input a valid url") + continue + else: + self.docker_http_proxy = "" + break + + while True: + user_input = input( + "HTTPS proxy (https://example.proxy:port): ") + if user_input.lower() == 'q': + raise UserQuit + if user_input: + if is_valid_url(user_input): + self.docker_https_proxy = user_input + break + else: + print("Please input a valid url") + continue + else: + self.docker_https_proxy = "" + break + + if not self.docker_http_proxy and not self.docker_https_proxy: + print("At least one proxy required") + continue + else: + self.enable_docker_proxy = True + + while True: + # TODO: Current Docker version 18.03.1-ce utilizes go-lang + # net library for proxy setting. The go-lang net lib + # doesn't support CIDR notation until this commit: + # + # https://github.com/golang/net/commit/ + # c21de06aaf072cea07f3a65d6970e5c7d8b6cd6d + # + # After docker upgrades to a version that CIDR notation + # supported pre_set_no_proxy will be simplified to subnets + if self.system_mode == \ + sysinv_constants.SYSTEM_MODE_SIMPLEX: + pre_set_no_proxy = "localhost,127.0.0.1," + \ + str(self.controller_floating_address) + "," + \ + str(self.controller_address_0) + "," + \ + str(self.controller_address_1) + "," + \ + str(self.external_oam_address_0) + else: + pre_set_no_proxy = "localhost,127.0.0.1," + \ + str(self.controller_floating_address) + "," + \ + str(self.controller_address_0) + "," + \ + str(self.controller_address_1) + "," + \ + str(self.external_oam_floating_address) + "," + \ + str(self.external_oam_address_0) + "," + \ + str(self.external_oam_address_1) + + user_input = input( + "Additional NO proxy besides '" + + pre_set_no_proxy + + "'\n(Comma-separated addresses, " + + "wildcard/subnet not allowed)\n:") + if user_input.lower() == 'q': + raise UserQuit + if user_input: + input_addr_list = user_input.split(",") + valid_address = True + for input_addr in input_addr_list: + if not is_valid_domain_or_ip(input_addr): + print("Input address '%s' is invalid" % + input_addr) + valid_address = False + break + if valid_address: + self.docker_no_proxy = pre_set_no_proxy + \ + "," + user_input + break + else: + continue + else: + self.docker_no_proxy = pre_set_no_proxy + break + break + elif user_input.lower() in ('n', ''): + self.enable_docker_proxy = False + break + else: + print("Invalid choice") + continue + def input_authentication_config(self): """Allow user to input authentication config and perform validation. """ @@ -2814,6 +2934,8 @@ class ConfigAssistant(): self.input_external_oam_config() if self.kubernetes: self.input_dns_config() + # Docker proxy is only used in kubernetes config + self.input_docker_proxy_config() self.input_authentication_config() def is_valid_management_multicast_subnet(self, ip_subnet): @@ -3159,6 +3281,22 @@ class ConfigAssistant(): self.nameserver_addresses[x] = \ IPAddress(cvalue) + # Docker Proxy Configuration + if config.has_section('cDOCKER_PROXY'): + self.enable_docker_proxy = True + if config.has_option('cDOCKER_PROXY', + 'DOCKER_HTTP_PROXY'): + self.docker_http_proxy = config.get( + 'cDOCKER_PROXY', 'DOCKER_HTTP_PROXY') + if config.has_option('cDOCKER_PROXY', + 'DOCKER_HTTPS_PROXY'): + self.docker_https_proxy = config.get( + 'cDOCKER_PROXY', 'DOCKER_HTTPS_PROXY') + if config.has_option('cDOCKER_PROXY', + 'DOCKER_NO_PROXY'): + self.docker_no_proxy = config.get( + 'cDOCKER_PROXY', 'DOCKER_NO_PROXY') + # SDN Network configuration if config.has_option('cSDN', 'ENABLE_SDN'): raise ConfigFail("The option ENABLE_SDN is no longer " @@ -3602,6 +3740,15 @@ class ConfigAssistant(): dns_config = True if not dns_config: print("External DNS servers not configured") + if self.enable_docker_proxy: + print("\nDocker Proxy Configuraton") + print("----------------------") + if self.docker_http_proxy: + print("Docker HTTP proxy: " + self.docker_http_proxy) + if self.docker_https_proxy: + print("Docker HTTPS proxy: " + self.docker_https_proxy) + if self.docker_no_proxy: + print("Docker NO proxy: " + self.docker_no_proxy) if self.region_config: print("\nRegion Configuration") @@ -3899,6 +4046,23 @@ class ConfigAssistant(): else: f.write("NAMESERVER_" + str(x + 1) + "=NC" + "\n") + # Docker proxy configuration + if self.enable_docker_proxy: + f.write("\n[cDOCKER_PROXY]") + f.write("\n# Docker Proxy Configuration\n") + if self.docker_http_proxy: + f.write( + "DOCKER_HTTP_PROXY=" + + str(self.docker_http_proxy) + "\n") + if self.docker_https_proxy: + f.write( + "DOCKER_HTTPS_PROXY=" + + str(self.docker_https_proxy) + "\n") + if self.docker_no_proxy: + f.write( + "DOCKER_NO_PROXY=" + + str(self.docker_no_proxy) + "\n") + # Network configuration f.write("\n[cNETWORK]") f.write("\n# Data Network Configuration\n") @@ -5302,6 +5466,24 @@ class ConfigAssistant(): patch = sysinv.dict_to_patch(values) client.sysinv.idns.update(dns_record.uuid, patch) + def _populate_docker_config(self, client): + parameter = {} + if self.docker_http_proxy: + parameter['http_proxy'] = self.docker_http_proxy + if self.docker_https_proxy: + parameter['https_proxy'] = self.docker_https_proxy + if self.docker_no_proxy: + parameter['no_proxy'] = self.docker_no_proxy + + if parameter: + client.sysinv.service_parameter.create( + sysinv_constants.SERVICE_TYPE_DOCKER, + sysinv_constants.SERVICE_PARAM_SECTION_DOCKER_PROXY, + None, + None, + parameter + ) + def populate_initial_config(self): """Populate initial system inventory configuration""" try: @@ -5311,6 +5493,8 @@ class ConfigAssistant(): self._populate_network_config(client) if self.kubernetes: self._populate_dns_config(client) + if self.enable_docker_proxy: + self._populate_docker_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 index 24cb70edd6..7df235ba86 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.kubernetes +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.kubernetes @@ -73,6 +73,12 @@ NAMESERVER_1=1.2.3.4 NAMESERVER_2=5.6.7.8 NAMESERVER_3=NC +[cDOCKER_PROXY] +# Docker Proxy Configuration +DOCKER_HTTP_PROXY=http://proxy.com:123 +DOCKER_HTTPS_PROXY=https://proxy.com:123 +DOCKER_NO_PROXY=localhost,127.0.0.1,192.168.204.2 + [cNETWORK] # Data Network Configuration VSWITCH_TYPE=ovs-dpdk diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes b/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes index d14364b7ca..7ff90974ac 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/system_config.kubernetes @@ -49,6 +49,12 @@ LOGICAL_INTERFACE=LOGICAL_INTERFACE_2 NAMESERVER_1=1.2.3.4 NAMESERVER_2=5.6.7.8 +[DOCKER_PROXY] +# Docker Proxy Configuration +DOCKER_HTTP_PROXY=http://proxy.com:123 +DOCKER_HTTPS_PROXY=https://proxy.com:123 +DOCKER_NO_PROXY=localhost,127.0.0.1,192.168.204.2 + ;[PXEBOOT_NETWORK] ;PXEBOOT_CIDR=192.168.203.0/24 diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py index 22f2224ddf..a8438eb8ee 100644 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py @@ -647,3 +647,10 @@ def test_kubernetes(): cr.create_cgcs_config_file(None, system_config, None, None, None, 0, validate_only=True) validate(system_config, DEFAULT_CONFIG, None, False) + + # Test absence of optional docker proxy configuration + system_config = cr.parse_system_config(systemfile) + system_config.remove_section('DOCKER_PROXY') + 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/docker.pp b/puppet-manifests/src/modules/platform/manifests/docker.pp index ababce3d56..23beb2e884 100644 --- a/puppet-manifests/src/modules/platform/manifests/docker.pp +++ b/puppet-manifests/src/modules/platform/manifests/docker.pp @@ -1,5 +1,8 @@ class platform::docker::params ( - $package_name = 'docker-ce', + $package_name = 'docker-ce', + $http_proxy = undef, + $https_proxy = undef, + $no_proxy = undef, ) { } class platform::docker::config @@ -9,6 +12,22 @@ class platform::docker::config if $::platform::kubernetes::params::enabled { + if $http_proxy or $https_proxy { + file { '/etc/systemd/system/docker.service.d': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0755', + } + -> file { '/etc/systemd/system/docker.service.d/http-proxy.conf': + ensure => present, + owner => 'root', + group => 'root', + mode => '0644', + content => template('platform/dockerproxy.conf.erb'), + } + } + Class['::platform::filesystem::docker'] ~> Class[$name] service { 'docker': diff --git a/puppet-manifests/src/modules/platform/templates/dockerproxy.conf.erb b/puppet-manifests/src/modules/platform/templates/dockerproxy.conf.erb new file mode 100644 index 0000000000..a1739ef249 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/dockerproxy.conf.erb @@ -0,0 +1,8 @@ +[Service] +<%- if @http_proxy -%> +Environment="HTTP_PROXY=<%= @http_proxy %>" +<%- end -%> +<%- if @https_proxy -%> +Environment="HTTPS_PROXY=<%= @https_proxy %>" +<%- end -%> +Environment="NO_PROXY=<%= @no_proxy %>" diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 87e072f82f..00d740c5c9 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -874,6 +874,7 @@ SERVICE_TYPE_PANKO = 'panko' SERVICE_TYPE_AODH = 'aodh' SERVICE_TYPE_GLANCE = 'glance' SERVICE_TYPE_BARBICAN = 'barbican' +SERVICE_TYPE_DOCKER = 'docker' SERVICE_PARAM_SECTION_MURANO_RABBITMQ = 'rabbitmq' SERVICE_PARAM_SECTION_MURANO_ENGINE = 'engine' @@ -1064,6 +1065,13 @@ SERVICE_PARAM_AODH_DATABASE_ALARM_HISTORY_TIME_TO_LIVE_DEFAULT = PM_TTL_DEFAULT SERVICE_PARAM_SECTION_SWIFT_CONFIG = 'config' SERVICE_PARAM_NAME_SWIFT_SERVICE_ENABLED = 'service_enabled' SERVICE_PARAM_NAME_SWIFT_FS_SIZE_MB = 'fs_size_mb' + +# docker parameters +SERVICE_PARAM_SECTION_DOCKER_PROXY = 'proxy' +SERVICE_PARAM_NAME_DOCKER_HTTP_PROXY = 'http_proxy' +SERVICE_PARAM_NAME_DOCKER_HTTPS_PROXY = 'https_proxy' +SERVICE_PARAM_NAME_DOCKER_NO_PROXY = 'no_proxy' + # default filesystem size to 25 MB SERVICE_PARAM_SWIFT_FS_SIZE_MB_DEFAULT = 25 diff --git a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py index ff440ce666..caae7fd536 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py @@ -648,6 +648,25 @@ def _validate_swift_enabled(name, value): "Swift API is already supported by Ceph Object Gateway.")) +def _validate_docker_proxy_address(name, value): + """Check if proxy value is valid""" + if not cutils.is_url(value): + raise wsme.exc.ClientSideError(_( + "Parameter '%s' must be a valid address." % name)) + + +def _validate_docker_no_proxy_address(name, value): + """Check if no proxy value is valid""" + values = value.split(',') + for item in values: + # will extend to more cases if CIDR notation is supported + if not cutils.is_valid_domain(item): + if not cutils.is_valid_ip(item): + raise wsme.exc.ClientSideError(_( + "Parameter '%s' includes an invalid address '%s'." % + (name, item))) + + # LDAP Identity Service Parameters (mandatory) SERVICE_PARAM_IDENTITY_LDAP_URL = 'url' @@ -1476,6 +1495,27 @@ SWIFT_CONFIG_PARAMETER_DATA_FORMAT = { constants.SERVICE_PARAM_NAME_SWIFT_SERVICE_ENABLED: SERVICE_PARAMETER_DATA_FORMAT_BOOLEAN, } +DOCKER_PROXY_PARAMETER_OPTIONAL = [ + constants.SERVICE_PARAM_NAME_DOCKER_HTTP_PROXY, + constants.SERVICE_PARAM_NAME_DOCKER_HTTPS_PROXY, + constants.SERVICE_PARAM_NAME_DOCKER_NO_PROXY, +] + +DOCKER_PROXY_PARAMETER_VALIDATOR = { + constants.SERVICE_PARAM_NAME_DOCKER_HTTP_PROXY: _validate_docker_proxy_address, + constants.SERVICE_PARAM_NAME_DOCKER_HTTPS_PROXY: _validate_docker_proxy_address, + constants.SERVICE_PARAM_NAME_DOCKER_NO_PROXY: _validate_docker_no_proxy_address, +} + +DOCKER_PROXY_PARAMETER_RESOURCE = { + constants.SERVICE_PARAM_NAME_DOCKER_HTTP_PROXY: + 'platform::docker::params::http_proxy', + constants.SERVICE_PARAM_NAME_DOCKER_HTTPS_PROXY: + 'platform::docker::params::https_proxy', + constants.SERVICE_PARAM_NAME_DOCKER_NO_PROXY: + 'platform::docker::params::no_proxy', +} + # Service Parameter Schema SERVICE_PARAM_MANDATORY = 'mandatory' SERVICE_PARAM_OPTIONAL = 'optional' @@ -1652,6 +1692,13 @@ SERVICE_PARAMETER_SCHEMA = { SERVICE_PARAM_DATA_FORMAT: SWIFT_CONFIG_PARAMETER_DATA_FORMAT, }, }, + constants.SERVICE_TYPE_DOCKER: { + constants.SERVICE_PARAM_SECTION_DOCKER_PROXY: { + SERVICE_PARAM_OPTIONAL: DOCKER_PROXY_PARAMETER_OPTIONAL, + SERVICE_PARAM_VALIDATOR: DOCKER_PROXY_PARAMETER_VALIDATOR, + SERVICE_PARAM_RESOURCE: DOCKER_PROXY_PARAMETER_RESOURCE, + }, + }, } SERVICE_PARAMETER_MAX_LENGTH = 255 diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index bd5cb5b7c9..cf6873ae1b 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -1797,6 +1797,21 @@ def is_url(url_str): return False +def is_valid_domain(url_str): + r = re.compile( + r'^(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain... + r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' + r'[A-Za-z0-9-_]*)' # localhost, hostname + r'(?::\d+)?' # optional port + r'(?:/?|[/?]\S+)$', re.IGNORECASE) + + url = r.match(url_str) + if url: + return True + else: + return False + + def verify_checksum(path): """ Find and validate the checksum file in a given directory. """ rc = True