예제 #1
0
    def check(self, args):
        """Validate that all fields have valid values through sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        responses = self.responses

        errors = []
        if not responses.get(BOOTSTRAP_SKIP_BUILD_KEY):
            errors.extend(self.check_apt_repos(responses))

        if errors:
            log.error("Errors: %s", errors)
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #2
0
    def check(self, args):
        """Validate that all fields have valid values through sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        responses = self.responses

        errors = []
        if not responses.get(BOOTSTRAP_SKIP_BUILD_KEY):
            errors.extend(self.check_apt_repos(responses))

        if errors:
            log.error("Errors: %s", errors)
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #3
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname != "blank":
                responses[fieldname] = self.edits[index].get_edit_text()

        password = responses["FUEL_ACCESS/password"]

        # Validate each field
        errors = []
        warnings = []

        # Passwords must match
        if password != responses["CONFIRM_PASSWORD"] and \
                password != self.defaults['FUEL_ACCESS/password']['value']:
            errors.append("Passwords do not match.")

        # Password must not be empty
        if len(password) == 0:
            errors.append("Password must not be empty.")

        # Password needs to be in ASCII character set
        try:
            if password.decode('ascii'):
                pass
        except UnicodeDecodeError:
            errors.append("Password contains non-ASCII characters.")

        # Passwords should be at least 8 symbols
        if len(password) < 8:
            warnings.append("8 symbols")

        # Passwords should contain at least one digit
        if re.search(r"\d", password) is None:
            warnings.append("one digit")

        if re.search(r"[A-Z]", password) is None:
            warnings.append("one uppercase letter")

        if re.search(r"[a-z]", password) is None:
            warnings.append("one lowercase letter")

        if re.search(r"[!#$%&'()*+,-./[\\\]^_`{|}~" + r'"]', password) is None:
            warnings.append("one special character")

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False

        if len(warnings) > 0:
            self.parent.footer.set_text("Warning: Password should have "
                                        "at least %s." % (warnings[0]))
        else:
            self.parent.footer.set_text("No errors found.")

        # Remove confirm from responses so it isn't saved
        del responses["CONFIRM_PASSWORD"]
        return responses
예제 #4
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        # Get field information
        responses = dict()
        self.parent.footer.set_text("Checking data...")
        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank" or fieldname == "ifname":
                pass
            elif fieldname == "bootproto":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    responses["bootproto"] = "none"
                else:
                    responses["bootproto"] = "dhcp"
            elif fieldname == "onboot":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    responses["onboot"] = "yes"
                else:
                    responses["onboot"] = "no"
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # Check for the duplicate IP provided
        for k, v in six.iteritems(self.netsettings):
            if (k != self.activeiface and responses["ipaddr"] != ''
                    and responses["ipaddr"] == v.get('addr')):
                errors.append("The same IP address {0} is assigned for "
                              "interfaces '{1}' and '{2}'.".format(
                                  responses["ipaddr"], k, self.activeiface))
                break

        if responses["onboot"] == "no":
            numactiveifaces = 0
            for iface in self.netsettings:
                if self.netsettings[iface]['addr'] != "":
                    numactiveifaces += 1
            if numactiveifaces < 2 and \
                    self.netsettings[self.activeiface]['addr'] != "":
                # Block user because puppet l23network fails if all interfaces
                # are disabled.
                errors.append("Cannot disable all interfaces.")
        elif responses["bootproto"] == "dhcp":
            self.parent.footer.set_text("Scanning for DHCP servers. "
                                        "Please wait...")
            self.parent.refreshScreen()
            try:
                dhcptimeout = 5
                dhcp_server_data = network.search_external_dhcp(
                    self.activeiface, dhcptimeout)
            except network.NetworkException:
                self.log.warning("dhcp_checker failed to check on %s"
                                 % self.activeiface)
                dhcp_server_data = []

            if len(dhcp_server_data) < 1:
                errors.append("No DHCP servers found. Cannot enable DHCP")

        # Check ipaddr, netmask, gateway only if static
        elif responses["bootproto"] == "none":
            try:
                if netaddr.valid_ipv4(responses["ipaddr"]):
                    if not netaddr.IPAddress(responses["ipaddr"]):
                        raise BadIPException("Not a valid IP address")
                else:
                    raise BadIPException("Not a valid IP address")
            except (BadIPException, Exception):
                errors.append("Not a valid IP address: %s" %
                              responses["ipaddr"])
            try:
                if netaddr.valid_ipv4(responses["netmask"]):
                    netmask = netaddr.IPAddress(responses["netmask"])
                    if netmask.is_netmask is False:
                        raise BadIPException("Not a valid IP address")
                else:
                    raise BadIPException("Not a valid IP address")
            except (BadIPException, Exception):
                errors.append("Not a valid netmask: %s" % responses["netmask"])
            try:
                if len(responses["gateway"]) > 0:
                    # Check if gateway is valid
                    if netaddr.valid_ipv4(responses["gateway"]) is False:
                        raise BadIPException("Gateway IP address is not valid")
                    # Check if gateway is in same subnet
                    if network.inSameSubnet(responses["ipaddr"],
                                            responses["gateway"],
                                            responses["netmask"]) is False:
                        raise BadIPException("Gateway IP is not in same "
                                             "subnet as IP address")
            except (BadIPException, Exception) as e:
                errors.append(e)
            self.parent.footer.set_text("Scanning for duplicate IP address..")
            if len(responses["ipaddr"]) > 0:
                if self.netsettings[self.activeiface]['link'].upper() != "UP":
                    try:
                        network.upIface(self.activeiface)
                    except NetworkException as e:
                        errors.append("Cannot activate {0} to check for "
                                      "duplicate IP.".format(self.activeiface))

                # Bind arping to requested IP if it's already assigned
                assigned_ips = [v.get('addr') for v in
                                self.netsettings.itervalues()]
                arping_bind = responses["ipaddr"] in assigned_ips

                if network.duplicateIPExists(responses["ipaddr"],
                                             self.activeiface, arping_bind):
                    errors.append("Duplicate host found with IP {0}.".format(
                        responses["ipaddr"]))
        if len(errors) > 0:
            self.log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #5
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname != "blank":
                responses[fieldname] = self.edits[index].get_edit_text()

        password = responses["FUEL_ACCESS/password"]

        # Validate each field
        errors = []
        warnings = []

        # Passwords must match
        if password != responses["CONFIRM_PASSWORD"] and \
                password != self.defaults['FUEL_ACCESS/password']['value']:
            errors.append("Passwords do not match.")

        # Password must not be empty
        if len(password) == 0:
            errors.append("Password must not be empty.")

        # Password needs to be in ASCII character set
        try:
            if password.decode('ascii'):
                pass
        except UnicodeDecodeError:
            errors.append("Password contains non-ASCII characters.")

        # Passwords should be at least 8 symbols
        if len(password) < 8:
            warnings.append("8 symbols")

        # Passwords should contain at least one digit
        if re.search(r"\d", password) is None:
            warnings.append("one digit")

        if re.search(r"[A-Z]", password) is None:
            warnings.append("one uppercase letter")

        if re.search(r"[a-z]", password) is None:
            warnings.append("one lowercase letter")

        if re.search(r"[!#$%&'()*+,-./[\\\]^_`{|}~" + r'"]', password) is None:
            warnings.append("one special character")

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False

        if len(warnings) > 0:
            self.parent.footer.set_text("Warning: Password should have "
                                        "at least %s." % (warnings[0]))
        else:
            self.parent.footer.set_text("No errors found.")

        # Remove confirm from responses so it isn't saved
        del responses["CONFIRM_PASSWORD"]
        return responses
예제 #6
0
    def check(self, args):
        """Validates all fields have valid values and some sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()

        # Refresh networking to make sure IP matches
        self.getNetwork()

        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname != "blank" and "label" not in fieldname:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # Set internal_{ipaddress,netmask,interface}
        responses["ADMIN_NETWORK/interface"] = self.activeiface
        responses["ADMIN_NETWORK/netmask"] = self.netsettings[
            self.activeiface]["netmask"]
        responses["ADMIN_NETWORK/mac"] = self.netsettings[
            self.activeiface]["mac"]
        responses["ADMIN_NETWORK/ipaddress"] = self.netsettings[
            self.activeiface]["addr"]

        # ensure management interface is valid
        if responses["ADMIN_NETWORK/interface"] not in self.netsettings.keys():
            errors.append("Management interface not valid")
        else:
            self.parent.footer.set_text("Scanning for DHCP servers. \
Please wait...")
            self.parent.refreshScreen()

            try:
                dhcptimeout = 5
                dhcp_server_data = network.search_external_dhcp(
                    self.activeiface, dhcptimeout)
            except network.NetworkException:
                log.warning('DHCP scan failed.')
                dhcp_server_data = []

            num_dhcp = len(dhcp_server_data)
            if num_dhcp == 0:
                log.debug("No DHCP servers found")
            else:
                # Problem exists, but permit user to continue
                log.error("%s foreign DHCP server(s) found: %s" %
                          (num_dhcp, dhcp_server_data))

                # Build dialog elements
                dhcp_info = []
                dhcp_info.append(urwid.Padding(
                                 urwid.Text(("header", "!!! WARNING !!!")),
                                 "center"))
                dhcp_info.append(widget.TextLabel("You have selected an \
interface that contains one or more DHCP servers. This will impact \
provisioning. You should disable these DHCP servers before you continue, or \
else deployment will likely fail."))
                dhcp_info.append(widget.TextLabel(""))
                for index, dhcp_server in enumerate(dhcp_server_data):
                    dhcp_info.append(widget.TextLabel("DHCP Server #%s:" %
                                     (index + 1)))
                    dhcp_info.append(widget.TextLabel("IP address: %-10s" %
                                     dhcp_server['server_ip']))
                    dhcp_info.append(widget.TextLabel("MAC address: %-10s" %
                                     dhcp_server['mac']))
                    dhcp_info.append(widget.TextLabel(""))
                dialog.display_dialog(self, urwid.Pile(dhcp_info),
                                      "DHCP Servers Found on %s"
                                      % self.activeiface)
            # Ensure pool start and end are on the same subnet as mgmt_if
            # Ensure mgmt_if has an IP first
            if len(self.netsettings[responses[
               "ADMIN_NETWORK/interface"]]["addr"]) == 0:
                errors.append("Go to Interfaces to configure management \
interface first.")
            else:
                # Ensure ADMIN_NETWORK/interface is not running DHCP
                if self.netsettings[responses[
                        "ADMIN_NETWORK/interface"]]["bootproto"] == "dhcp":
                    errors.append("%s is running DHCP. Change it to static "
                                  "first." % self.activeiface)
                # Ensure DHCP Pool Start and DHCP Pool are valid IPs
                try:
                    if netaddr.valid_ipv4(responses[
                                          "ADMIN_NETWORK/dhcp_pool_start"]):
                        dhcp_start = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_pool_start"])
                        if not dhcp_start:
                            raise BadIPException("Not a valid IP address")
                    else:
                        raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Pool Start")
                try:
                    if netaddr.valid_ipv4(responses[
                            "ADMIN_NETWORK/dhcp_gateway"]):
                        dhcp_gateway = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_gateway"])
                        if not dhcp_gateway:
                            raise BadIPException("Not a valid IP address")
                    else:
                            raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Gateway")

                try:
                    if netaddr.valid_ipv4(responses[
                            "ADMIN_NETWORK/dhcp_pool_end"]):
                        dhcp_end = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_pool_end"])
                        if not dhcp_end:
                            raise BadIPException("Not a valid IP address")
                    else:
                        raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Pool end")

                # Ensure pool start and end are in the same
                # subnet of each other
                netmask = self.netsettings[responses[
                                           "ADMIN_NETWORK/interface"
                                           ]]["netmask"]
                if not network.inSameSubnet(
                        responses["ADMIN_NETWORK/dhcp_pool_start"],
                        responses["ADMIN_NETWORK/dhcp_pool_end"], netmask):
                    errors.append("DHCP Pool start and end are not in the "
                                  "same subnet.")

                # Ensure pool start and end are in the right netmask
                mgmt_if_ipaddr = self.netsettings[responses[
                    "ADMIN_NETWORK/interface"]]["addr"]
                if network.inSameSubnet(responses[
                                        "ADMIN_NETWORK/dhcp_pool_start"],
                                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Pool start does not match management"
                                  " network.")
                if network.inSameSubnet(responses[
                                        "ADMIN_NETWORK/dhcp_pool_end"],
                                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Pool end does not match management "
                                  "network.")

                if network.inSameSubnet(responses[
                                        "ADMIN_NETWORK/dhcp_gateway"],
                                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Gateway does not match management "
                                  "network.")

                self.parent.footer.set_text("Scanning for duplicate IP address"
                                            "es. Please wait...")
                # Bind arping to mgmt_if_ipaddr if it assigned
                assigned_ips = [v.get('addr') for v in
                                self.netsettings.itervalues()]
                arping_bind = mgmt_if_ipaddr in assigned_ips
                if network.duplicateIPExists(mgmt_if_ipaddr, self.activeiface,
                                             arping_bind):
                    errors.append("Duplicate host found with IP {0}.".format(
                        mgmt_if_ipaddr))

        # Extra checks for post-deployment changes
        if utils.is_post_deployment():
            settings = self.parent.settings

            # Admin interface cannot change
            if self.activeiface != settings["ADMIN_NETWORK"]["interface"]:
                errors.append("Cannot change admin interface after deployment")

            # PXE network range must contain previous PXE network range
            old_range = network.range(
                settings["ADMIN_NETWORK"]["dhcp_pool_start"],
                settings["ADMIN_NETWORK"]["dhcp_pool_end"])
            new_range = network.range(
                responses["ADMIN_NETWORK/dhcp_pool_start"],
                responses["ADMIN_NETWORK/dhcp_pool_end"])
            if old_range[0] not in new_range:
                errors.append("DHCP range must contain previous values.")
            if old_range[-1] not in new_range:
                errors.append("DHCP range can only be increased after "
                              "deployment.")

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #7
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()
        ntp_enabled = False

        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank":
                pass
            elif fieldname == "ntpenabled":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    ntp_enabled = True
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        if self.parent.save_only:
            return responses

        # Validate each field
        errors = []
        warnings = []
        if not ntp_enabled:
            # Disabled NTP means passing no NTP servers to save method
            # Even though nodes will use Fuel Master, NTP[1,2,3] are empty so
            # Fuel Master can initialize itself as a time source.
            responses = {
                'NTP1': "",
                'NTP2': "",
                'NTP3': ""}
            self.parent.footer.set_text("No errors found.")
            log.info("No errors found")
            return responses

        for ntpfield, ntpvalue in responses.iteritems():
            # NTP must be under 255 chars
            if len(ntpvalue) >= 255:
                errors.append("%s must be under 255 chars." %
                              self.defaults[ntpfield]['label'])

            # NTP needs to have valid chars
            if re.search('[^a-zA-Z0-9-.]', ntpvalue):
                errors.append("%s contains illegal characters." %
                              self.defaults[ntpfield]['label'])

            # ensure external NTP is valid
            if len(ntpvalue) > 0:
                # Validate first NTP address
                try:
                    # Try to test NTP via ntpdate
                    if not self.checkNTP(ntpvalue):
                        warnings.append("%s unable to perform NTP."
                                        % self.defaults[ntpfield]['label'])
                except Exception:
                    warnings.append("%s unable to sync time with server.: %s"
                                    % self.defaults[ntpfield]['label'])
        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            if len(warnings) > 0:
                msg = ["NTP configuration has the following warnings:"]
                msg.extend(warnings)
                msg.append("You may see errors during provisioning and "
                           "in system logs. NTP errors are not fatal.")
                warning_msg = '\n'.join(str(line) for line in msg)
                dialog.display_dialog(self, widget.TextLabel(warning_msg),
                                      "NTP Warnings")
                log.warning(warning_msg)
            self.parent.footer.set_text("No errors found.")
            log.info("No errors found")
            return responses
예제 #8
0
    def check(self, args):
        """Validate that all fields have valid values through sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank":
                pass
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # hostname must be under 60 chars
        if len(responses["HOSTNAME"]) >= 60:
            errors.append("Hostname must be under 60 chars.")

        # hostname must not be empty
        if len(responses["HOSTNAME"]) == 0:
            errors.append("Hostname must not be empty.")

        # hostname needs to have valid chars
        if re.search('[^a-z0-9-]', responses["HOSTNAME"]):
            errors.append(
                "Hostname must contain only alphanumeric and hyphen.")

        # domain must be under 180 chars
        if len(responses["DNS_DOMAIN"]) >= 180:
            errors.append("Domain must be under 180 chars.")

        # domain must not be empty
        if len(responses["DNS_DOMAIN"]) == 0:
            errors.append("Domain must not be empty.")

        # domain needs to have valid chars
        if re.match('[^a-z0-9-.]', responses["DNS_DOMAIN"]):
            errors.append(
                "Domain must contain only alphanumeric, period and hyphen.")
        # ensure external DNS is valid
        if len(responses["DNS_UPSTREAM"]) == 0:
            # We will allow empty if user doesn't need external networking
            # and present a strongly worded warning
            msg = "If you continue without DNS, you may not be able to access"\
                  + " external data necessary for installation needed for " \
                  + "some OpenStack Releases."

            dialog.display_dialog(
                self, widget.TextLabel(msg), "Empty DNS Warning")

        else:
            upstream_nameservers = responses["DNS_UPSTREAM"].split(',')

            # external DNS must contain only numbers, periods, and commas
            # Needs more serious ip address checking
            if re.match('[^0-9.,]', responses["DNS_UPSTREAM"]):
                errors.append(
                    "External DNS must contain only IP addresses and commas.")

            # Ensure local IPs are not in upstream list
            host_ips = network.list_host_ip_addresses()
            for nameserver in upstream_nameservers:
                if nameserver in host_ips:
                    errors.append("Host IPs cannot be in upstream DNS.")
                    break

            if len(upstream_nameservers) > 3:
                errors.append(
                    "Unable to specify more than 3 External DNS addresses.")

            # ensure test DNS name isn't empty
            if len(responses["TEST_DNS"]) == 0:
                errors.append("Test DNS must not be empty.")
            # Validate first IP address
            for nameserver in upstream_nameservers:
                if not netaddr.valid_ipv4(nameserver):
                    errors.append("Not a valid IP address for DNS server:"
                                  " {0}".format(nameserver))

            # Try to resolve with first address
            if not self.checkDNS(upstream_nameservers[0]):
                # Warn user that DNS resolution failed, but continue
                msg = "Unable to resolve %s.\n\n" % responses['TEST_DNS']\
                      + "Possible causes for DNS failure include:\n"\
                      + "* Invalid DNS server\n"\
                      + "* Invalid gateway\n"\
                      + "* Other networking issue\n\n"\
                      + "Fuel Setup can save this configuration, but "\
                      + "you may want to correct your settings."
                dialog.display_dialog(self, widget.TextLabel(msg),
                                      "DNS Failure Warning")
                self.parent.refreshScreen()

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #9
0
    def check(self, args):
        """Validate that all fields have valid values through sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank":
                pass
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # hostname must be under 60 chars
        if len(responses["HOSTNAME"]) >= 60:
            errors.append("Hostname must be under 60 chars.")

        # hostname must not be empty
        if len(responses["HOSTNAME"]) == 0:
            errors.append("Hostname must not be empty.")

        # hostname needs to have valid chars
        if re.search('[^a-z0-9-]', responses["HOSTNAME"]):
            errors.append(
                "Hostname must contain only alphanumeric and hyphen.")

        # domain must be under 180 chars
        if len(responses["DNS_DOMAIN"]) >= 180:
            errors.append("Domain must be under 180 chars.")

        # domain must not be empty
        if len(responses["DNS_DOMAIN"]) == 0:
            errors.append("Domain must not be empty.")

        # domain needs to have valid chars
        if re.match('[^a-z0-9-.]', responses["DNS_DOMAIN"]):
            errors.append(
                "Domain must contain only alphanumeric, period and hyphen.")
        # ensure external DNS is valid
        if len(responses["DNS_UPSTREAM"]) == 0:
            # We will allow empty if user doesn't need external networking
            # and present a strongly worded warning
            msg = "If you continue without DNS, you may not be able to access"\
                  + " external data necessary for installation needed for " \
                  + "some OpenStack Releases."

            dialog.display_dialog(self, widget.TextLabel(msg),
                                  "Empty DNS Warning")

        else:
            upstream_nameservers = responses["DNS_UPSTREAM"].split(',')

            # external DNS must contain only numbers, periods, and commas
            # Needs more serious ip address checking
            if re.match('[^0-9.,]', responses["DNS_UPSTREAM"]):
                errors.append(
                    "External DNS must contain only IP addresses and commas.")

            # Ensure local IPs are not in upstream list
            host_ips = network.list_host_ip_addresses()
            for nameserver in upstream_nameservers:
                if nameserver in host_ips:
                    errors.append("Host IPs cannot be in upstream DNS.")
                    break

            if len(upstream_nameservers) > 3:
                errors.append(
                    "Unable to specify more than 3 External DNS addresses.")

            # ensure test DNS name isn't empty
            if len(responses["TEST_DNS"]) == 0:
                errors.append("Test DNS must not be empty.")
            # Validate first IP address
            for nameserver in upstream_nameservers:
                if not netaddr.valid_ipv4(nameserver):
                    errors.append("Not a valid IP address for DNS server:"
                                  " {0}".format(nameserver))

            # Try to resolve with first address
            if not self.checkDNS(upstream_nameservers[0]):
                # Warn user that DNS resolution failed, but continue
                msg = "Unable to resolve %s.\n\n" % responses['TEST_DNS']\
                      + "Possible causes for DNS failure include:\n"\
                      + "* Invalid DNS server\n"\
                      + "* Invalid gateway\n"\
                      + "* Other networking issue\n\n"\
                      + "Fuel Setup can save this configuration, but "\
                      + "you may want to correct your settings."
                dialog.display_dialog(self, widget.TextLabel(msg),
                                      "DNS Failure Warning")
                self.parent.refreshScreen()

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #10
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank":
                pass
            elif fieldname == "ntpenabled":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    responses["ntpenabled"] = "Yes"
                else:
                    responses["ntpenabled"] = "No"
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []
        warnings = []
        if responses['ntpenabled'] == "No":
            # Disabled NTP means passing no NTP servers to save method
            # Even though nodes will use Fuel Master, NTP[1,2,3] are empty so
            # Fuel Master can initialize itself as a time source.
            responses = {
                'NTP1': "",
                'NTP2': "",
                'NTP3': ""}
            self.parent.footer.set_text("No errors found.")
            log.info("No errors found")
            return responses
        if all(map(lambda f: (len(responses[f]) == 0), self.fields)):
            pass
            # We will allow empty if user doesn't need external networking
            # and present a strongly worded warning
            # msg = "If you continue without NTP, you may have issues with "\
            #      + "deployment due to time synchronization issues. These "\
            #      + "problems are exacerbated in virtualized deployments."

            # dialog.display_dialog(
            #    self, widget.TextLabel(msg), "Empty NTP Warning")
        del responses['ntpenabled']
        for ntpfield, ntpvalue in responses.iteritems():
            # NTP must be under 255 chars
            if len(ntpvalue) >= 255:
                errors.append("%s must be under 255 chars." %
                              self.defaults[ntpfield]['label'])

            # NTP needs to have valid chars
            if re.search('[^a-zA-Z0-9-.]', ntpvalue):
                errors.append("%s contains illegal characters." %
                              self.defaults[ntpfield]['label'])

            # ensure external NTP is valid
            if len(ntpvalue) > 0:
                # Validate first NTP address
                try:
                    # Try to test NTP via ntpdate
                    if not self.checkNTP(ntpvalue):
                        warnings.append("%s unable to perform NTP."
                                        % self.defaults[ntpfield]['label'])
                except Exception:
                    warnings.append("%s unable to sync time with server.: %s"
                                    % self.defaults[ntpfield]['label'])
        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            if len(warnings) > 0:
                msg = ["NTP configuration has the following warnings:"]
                msg.extend(warnings)
                msg.append("You may see errors during provisioning and "
                           "in system logs. NTP errors are not fatal.")
                warning_msg = '\n'.join(str(line) for line in msg)
                dialog.display_dialog(self, widget.TextLabel(warning_msg),
                                      "NTP Warnings")
                log.warning(warning_msg)
            self.parent.footer.set_text("No errors found.")
            log.info("No errors found")
            return responses
예제 #11
0
    def check(self, args):
        """Validates all fields have valid values and some sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()

        # Refresh networking to make sure IP matches
        self.getNetwork()

        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname != "blank" and "label" not in fieldname:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # Set internal_{ipaddress,netmask,interface}
        responses["ADMIN_NETWORK/interface"] = self.activeiface
        responses["ADMIN_NETWORK/netmask"] = self.netsettings[
            self.activeiface]["netmask"]
        responses["ADMIN_NETWORK/mac"] = self.netsettings[
            self.activeiface]["mac"]
        responses["ADMIN_NETWORK/ipaddress"] = self.netsettings[
            self.activeiface]["addr"]

        # ensure management interface is valid
        if responses["ADMIN_NETWORK/interface"] not in self.netsettings.keys():
            errors.append("Management interface not valid")
        else:
            self.parent.footer.set_text("Scanning for DHCP servers. \
Please wait...")
            self.parent.refreshScreen()

            try:
                dhcptimeout = 5
                dhcp_server_data = network.search_external_dhcp(
                    self.activeiface, dhcptimeout)
            except network.NetworkException:
                log.warning('DHCP scan failed.')
                dhcp_server_data = []

            num_dhcp = len(dhcp_server_data)
            if num_dhcp == 0:
                log.debug("No DHCP servers found")
            else:
                # Problem exists, but permit user to continue
                log.error("%s foreign DHCP server(s) found: %s" %
                          (num_dhcp, dhcp_server_data))

                # Build dialog elements
                dhcp_info = []
                dhcp_info.append(
                    urwid.Padding(urwid.Text(("header", "!!! WARNING !!!")),
                                  "center"))
                dhcp_info.append(
                    widget.TextLabel("You have selected an \
interface that contains one or more DHCP servers. This will impact \
provisioning. You should disable these DHCP servers before you continue, or \
else deployment will likely fail."))
                dhcp_info.append(widget.TextLabel(""))
                for index, dhcp_server in enumerate(dhcp_server_data):
                    dhcp_info.append(
                        widget.TextLabel("DHCP Server #%s:" % (index + 1)))
                    dhcp_info.append(
                        widget.TextLabel("IP address: %-10s" %
                                         dhcp_server['server_ip']))
                    dhcp_info.append(
                        widget.TextLabel("MAC address: %-10s" %
                                         dhcp_server['mac']))
                    dhcp_info.append(widget.TextLabel(""))
                dialog.display_dialog(
                    self, urwid.Pile(dhcp_info),
                    "DHCP Servers Found on %s" % self.activeiface)
            # Ensure pool start and end are on the same subnet as mgmt_if
            # Ensure mgmt_if has an IP first
            if len(self.netsettings[responses["ADMIN_NETWORK/interface"]]
                   ["addr"]) == 0:
                errors.append("Go to Interfaces to configure management \
interface first.")
            else:
                # Ensure ADMIN_NETWORK/interface is not running DHCP
                if self.netsettings[responses["ADMIN_NETWORK/interface"]][
                        "bootproto"] == "dhcp":
                    errors.append("%s is running DHCP. Change it to static "
                                  "first." % self.activeiface)
                # Ensure DHCP Pool Start and DHCP Pool are valid IPs
                try:
                    if netaddr.valid_ipv4(
                            responses["ADMIN_NETWORK/dhcp_pool_start"]):
                        dhcp_start = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_pool_start"])
                        if not dhcp_start:
                            raise BadIPException("Not a valid IP address")
                    else:
                        raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Pool Start")
                try:
                    if netaddr.valid_ipv4(
                            responses["ADMIN_NETWORK/dhcp_gateway"]):
                        dhcp_gateway = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_gateway"])
                        if not dhcp_gateway:
                            raise BadIPException("Not a valid IP address")
                    else:
                        raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Gateway")

                try:
                    if netaddr.valid_ipv4(
                            responses["ADMIN_NETWORK/dhcp_pool_end"]):
                        dhcp_end = netaddr.IPAddress(
                            responses["ADMIN_NETWORK/dhcp_pool_end"])
                        if not dhcp_end:
                            raise BadIPException("Not a valid IP address")
                    else:
                        raise BadIPException("Not a valid IP address")
                except Exception:
                    errors.append("Invalid IP address for DHCP Pool end")

                # Ensure pool start and end are in the same
                # subnet of each other
                netmask = self.netsettings[
                    responses["ADMIN_NETWORK/interface"]]["netmask"]
                if not network.inSameSubnet(
                        responses["ADMIN_NETWORK/dhcp_pool_start"],
                        responses["ADMIN_NETWORK/dhcp_pool_end"], netmask):
                    errors.append("DHCP Pool start and end are not in the "
                                  "same subnet.")

                # Ensure pool start and end are in the right netmask
                mgmt_if_ipaddr = self.netsettings[
                    responses["ADMIN_NETWORK/interface"]]["addr"]
                if network.inSameSubnet(
                        responses["ADMIN_NETWORK/dhcp_pool_start"],
                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Pool start does not match management"
                                  " network.")
                if network.inSameSubnet(
                        responses["ADMIN_NETWORK/dhcp_pool_end"],
                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Pool end does not match management "
                                  "network.")

                if network.inSameSubnet(
                        responses["ADMIN_NETWORK/dhcp_gateway"],
                        mgmt_if_ipaddr, netmask) is False:
                    errors.append("DHCP Gateway does not match management "
                                  "network.")

                self.parent.footer.set_text("Scanning for duplicate IP address"
                                            "es. Please wait...")
                # Bind arping to mgmt_if_ipaddr if it assigned
                assigned_ips = [
                    v.get('addr') for v in self.netsettings.itervalues()
                ]
                arping_bind = mgmt_if_ipaddr in assigned_ips
                if network.duplicateIPExists(mgmt_if_ipaddr, self.activeiface,
                                             arping_bind):
                    errors.append("Duplicate host found with IP {0}.".format(
                        mgmt_if_ipaddr))

        # Extra checks for post-deployment changes
        if utils.is_post_deployment():
            settings = self.parent.settings

            # Admin interface cannot change
            if self.activeiface != settings["ADMIN_NETWORK"]["interface"]:
                errors.append("Cannot change admin interface after deployment")

            # PXE network range must contain previous PXE network range
            old_range = network.range(
                settings["ADMIN_NETWORK"]["dhcp_pool_start"],
                settings["ADMIN_NETWORK"]["dhcp_pool_end"])
            new_range = network.range(
                responses["ADMIN_NETWORK/dhcp_pool_start"],
                responses["ADMIN_NETWORK/dhcp_pool_end"])
            if old_range[0] not in new_range:
                errors.append("DHCP range must contain previous values.")
            if old_range[-1] not in new_range:
                errors.append("DHCP range can only be increased after "
                              "deployment.")

        if len(errors) > 0:
            log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses
예제 #12
0
    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        # Get field information
        responses = dict()
        self.parent.footer.set_text("Checking data...")
        for index, fieldname in enumerate(self.fields):
            if fieldname == "blank" or fieldname == "ifname":
                pass
            elif fieldname == "bootproto":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    responses["bootproto"] = "none"
                else:
                    responses["bootproto"] = "dhcp"
            elif fieldname == "onboot":
                rb_group = self.edits[index].rb_group
                if rb_group[0].state:
                    responses["onboot"] = "yes"
                else:
                    responses["onboot"] = "no"
            else:
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        # Check for the duplicate IP provided
        for k, v in six.iteritems(self.netsettings):
            if (k != self.activeiface and responses["ipaddr"] != ''
                    and responses["ipaddr"] == v.get('addr')):
                errors.append("The same IP address {0} is assigned for "
                              "interfaces '{1}' and '{2}'.".format(
                                  responses["ipaddr"], k, self.activeiface))
                break

        if responses["onboot"] == "no":
            numactiveifaces = 0
            for iface in self.netsettings:
                if self.netsettings[iface]['addr'] != "":
                    numactiveifaces += 1
            if numactiveifaces < 2 and \
                    self.netsettings[self.activeiface]['addr'] != "":
                # Block user because puppet l23network fails if all interfaces
                # are disabled.
                errors.append("Cannot disable all interfaces.")
        elif responses["bootproto"] == "dhcp":
            self.parent.footer.set_text("Scanning for DHCP servers. "
                                        "Please wait...")
            self.parent.refreshScreen()
            try:
                dhcptimeout = 5
                dhcp_server_data = network.search_external_dhcp(
                    self.activeiface, dhcptimeout)
            except network.NetworkException:
                self.log.warning("dhcp_checker failed to check on %s" %
                                 self.activeiface)
                dhcp_server_data = []

            if len(dhcp_server_data) < 1:
                errors.append("No DHCP servers found. Cannot enable DHCP")

        # Check ipaddr, netmask, gateway only if static
        elif responses["bootproto"] == "none":
            try:
                if netaddr.valid_ipv4(responses["ipaddr"]):
                    if not netaddr.IPAddress(responses["ipaddr"]):
                        raise BadIPException("Not a valid IP address")
                else:
                    raise BadIPException("Not a valid IP address")
            except (BadIPException, Exception):
                errors.append("Not a valid IP address: %s" %
                              responses["ipaddr"])
            try:
                if netaddr.valid_ipv4(responses["netmask"]):
                    netmask = netaddr.IPAddress(responses["netmask"])
                    if netmask.is_netmask is False:
                        raise BadIPException("Not a valid IP address")
                else:
                    raise BadIPException("Not a valid IP address")
            except (BadIPException, Exception):
                errors.append("Not a valid netmask: %s" % responses["netmask"])
            try:
                if len(responses["gateway"]) > 0:
                    # Check if gateway is valid
                    if netaddr.valid_ipv4(responses["gateway"]) is False:
                        raise BadIPException("Gateway IP address is not valid")
                    # Check if gateway is in same subnet
                    if network.inSameSubnet(responses["ipaddr"],
                                            responses["gateway"],
                                            responses["netmask"]) is False:
                        raise BadIPException("Gateway IP is not in same "
                                             "subnet as IP address")
            except (BadIPException, Exception) as e:
                errors.append(e)
            self.parent.footer.set_text("Scanning for duplicate IP address..")
            if len(responses["ipaddr"]) > 0:
                if self.netsettings[self.activeiface]['link'].upper() != "UP":
                    try:
                        network.upIface(self.activeiface)
                    except NetworkException as e:
                        errors.append("Cannot activate {0} to check for "
                                      "duplicate IP.".format(self.activeiface))

                # Bind arping to requested IP if it's already assigned
                assigned_ips = [
                    v.get('addr') for v in self.netsettings.itervalues()
                ]
                arping_bind = responses["ipaddr"] in assigned_ips

                if network.duplicateIPExists(responses["ipaddr"],
                                             self.activeiface, arping_bind):
                    errors.append("Duplicate host found with IP {0}.".format(
                        responses["ipaddr"]))
        if len(errors) > 0:
            self.log.error("Errors: %s %s" % (len(errors), errors))
            ModuleHelper.display_failed_check_dialog(self, errors)
            return False
        else:
            self.parent.footer.set_text("No errors found.")
            return responses