Example #1
0
    def restart_service(self):
        """
        This restarts the dhcp server and thus applied the newly written config files.

        :raises CX
        """
        # TODO: Reuse the utils method for service restarts
        if self.settings.restart_dhcp:
            rc = utils.subprocess_call("service dnsmasq restart")
            if rc != 0:
                error_msg = "service dnsmasq restart failed"
                self.logger.error(error_msg)
                raise CX(error_msg)
Example #2
0
def mac_address(mac, for_item=True):
    """
    Validate as an Eternet mac address.

    :param mac: mac address
    :type mac: str
    :returns: str mac or CX
    """
    if not isinstance(mac, str):
        raise CX("Invalid input, mac must be a string")
    else:
        mac = mac.lower().strip()

    if for_item is True:
        # this value has special meaning for items
        if mac == "random":
            return mac

    if not netaddr.valid_mac(mac):
        raise CX("Invalid mac address format (%s)" % mac)

    return mac
Example #3
0
 def set_boot_loader(self, name):
     try:
         # If we have already loaded the supported boot loaders from
         # the signature, use that data
         supported_distro_boot_loaders = self.supported_boot_loaders
     except:
         # otherwise, refresh from the signatures / defaults
         self.supported_boot_loaders = utils.get_supported_distro_boot_loaders(self)
         supported_distro_boot_loaders = self.supported_boot_loaders
     if name not in supported_distro_boot_loaders:
         raise CX(_("Invalid boot loader name: %s. Supported boot loaders are: %s" %
                    (name, ' '.join(supported_distro_boot_loaders))))
     self.boot_loader = name
Example #4
0
 def set_image_type(self, image_type):
     """
     Indicates what type of image this is.
     direct     = something like "memdisk", physical only
     iso        = a bootable ISO that pxe's or can be used for virt installs, virtual only
     virt-clone = a cloned virtual disk (FIXME: not yet supported), virtual only
     memdisk    = hdd image (physical only)
     """
     if image_type not in self.get_valid_image_types():
         raise CX(
             _("image type must be on of the following: %s") %
             string.join(self.get_valid_image_types(), ", "))
     self.image_type = image_type
Example #5
0
 def set_interface_type(self, type, interface):
     interface_types = [
         "bridge", "bridge_slave", "bond", "bond_slave",
         "bonded_bridge_slave", "bmc", "na", "infiniband", ""
     ]
     if type not in interface_types:
         raise CX(
             _("interface type value must be one of: %s or blank" %
               ",".join(interface_types)))
     if type == "na":
         type = ""
     intf = self.__get_interface(interface)
     intf["interface_type"] = type
Example #6
0
    def set_network_count(self, num):
        """
        Setter for the number of networks.

        :param num: If None or emtpy will be set to one. Otherwise will be cast to int and then set.
        :type num: int
        """
        if num is None or num == "":
            num = 1
        try:
            self.network_count = int(num)
        except:
            raise CX("invalid network count (%s)" % num)
Example #7
0
    def __get_interface(self, name):

        if name == "" and len(self.interfaces.keys()) == 0:
            raise CX(
                _("No interfaces defined. Please use --interface <interface_name>"
                  ))
        elif name == "" and len(self.interfaces.keys()) == 1:
            name = self.interfaces.keys()[0]
        elif name == "" and len(self.interfaces.keys()) > 1:
            raise CX(
                _("Multiple interfaces defined. Please use --interface <interface_name>"
                  ))
        elif name not in self.interfaces:
            self.interfaces[name] = {
                "mac_address": "",
                "mtu": "",
                "ip_address": "",
                "dhcp_tag": "",
                "netmask": "",
                "if_gateway": "",
                "virt_bridge": "",
                "static": False,
                "interface_type": "",
                "interface_master": "",
                "bonding_opts": "",
                "bridge_opts": "",
                "management": False,
                "dns_name": "",
                "static_routes": [],
                "ipv6_address": "",
                "ipv6_prefix": "",
                "ipv6_secondaries": [],
                "ipv6_mtu": "",
                "ipv6_static_routes": [],
                "ipv6_default_gateway": "",
                "cnames": [],
            }

        return self.interfaces[name]
Example #8
0
def __connect():
    cp = ConfigParser()
    cp.read("/etc/cobbler/mongodb.conf")

    host = cp.get("connection", "host")
    port = int(cp.get("connection", "port"))
    # TODO: detect connection error
    global mongodb
    try:
        mongodb = Connection(host, port)['cobbler']
    except:
        # FIXME: log error
        raise CX("Unable to connect to Mongo database")
Example #9
0
def snippet_file_path(snippet):
    """
    Validate the snippet file path.

    @param: str snippet (absolute path to a local snippet file)
    @returns: str snippet or CX
    """
    if not isinstance(snippet, basestring):
        raise CX("Invalid input, snippet must be a string")
    else:
        snippet = snippet.strip()

    if snippet.find("..") != -1:
        raise CX("Invalid snippet template file location %s, must be absolute path" % snippet)

    if not snippet.startswith(codes.SNIPPET_TEMPLATE_BASE_DIR):
        raise CX("Invalid snippet template file location %s, it is not inside %s" % (snippet, codes.SNIPPET_TEMPLATE_BASE_DIR))

    if not os.path.isfile(snippet):
        raise CX("Invalid snippet template file location %s, file not found" % snippet)

    return snippet
Example #10
0
def ipv4_netmask(addr):
    """
    Validate an IPv4 netmask.

    @param: str addr (ipv4 netmask)
    @returns: str addr or CX
    """
    if not isinstance(addr, basestring):
        raise CX("Invalid input, addr must be a string")
    else:
        addr = addr.strip()

    if addr == "":
        return addr

    if not netaddr.valid_ipv4(addr):
        raise CX("Invalid IPv4 address format (%s)" % addr)

    if not netaddr.IPAddress(addr).is_netmask():
        raise CX("Invalid IPv4 netmask (%s)" % addr)

    return addr
Example #11
0
    def remove(self, name, with_delete=True, with_sync=True, with_triggers=True, recursive=False, logger=None):
        """
        Remove element named 'name' from the collection
        """
        name = name.lower()
        if not recursive:
            for v in self.collection_mgr.systems():
                if v.profile is not None and v.profile.lower() == name:
                    raise CX(_("removal would orphan system: %s") % v.name)

        obj = self.find(name=name)
        if obj is not None:
            if recursive:
                kids = obj.get_children()
                for k in kids:
                    if k.COLLECTION_TYPE == "profile":
                        self.collection_mgr.api.remove_profile(k.name, recursive=recursive, delete=with_delete, with_triggers=with_triggers, logger=logger)
                    else:
                        self.collection_mgr.api.remove_system(k.name, recursive=recursive, delete=with_delete, with_triggers=with_triggers, logger=logger)

            if with_delete:
                if with_triggers:
                    utils.run_triggers(self.collection_mgr.api, obj, "/var/lib/cobbler/triggers/delete/profile/pre/*", [], logger)
            self.lock.acquire()
            try:
                del self.listing[name]
            finally:
                self.lock.release()
            self.collection_mgr.serialize_delete(self, obj)
            if with_delete:
                if with_triggers:
                    utils.run_triggers(self.collection_mgr.api, obj, "/var/lib/cobbler/triggers/delete/profile/post/*", [], logger)
                    utils.run_triggers(self.collection_mgr.api, obj, "/var/lib/cobbler/triggers/change/*", [], logger)
                if with_sync:
                    lite_sync = litesync.CobblerLiteSync(self.collection_mgr, logger=logger)
                    lite_sync.remove_single_profile(name)
            return

        raise CX(_("cannot delete an object that does not exist: %s") % name)
Example #12
0
    def menu(self, menu: str):
        """
        TODO

        :param menu: The menu for the image.
        :raises CX

        """
        if menu and menu != "":
            menu_list = self.api.menus()
            if not menu_list.find(name=menu):
                raise CX("menu %s not found" % menu)
        self._menu = menu
Example #13
0
    def set_ipv6_secondaries(self, addresses, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(addresses)
        secondaries = []
        for address in data:
            if address == "" or utils.is_ip(address):
                secondaries.append(address)
            else:
                raise CX(
                    _("invalid format for IPv6 IP address (%s)") % address)

        intf["ipv6_secondaries"] = secondaries
        return True
Example #14
0
    def find(self,
             name: Optional[str] = None,
             return_list: bool = False,
             no_errors=False,
             **kargs):
        """
        Return first object in the collection that maches all item='value' pairs passed, else return None if no objects
        can be found. When return_list is set, can also return a list.  Empty list would be returned instead of None in
        that case.

        :param name: The object name which should be found.
        :param return_list: If a list should be returned or the first match.
        :param no_errors: If errors which are possibly thrown while searching should be ignored or not.
        :param kargs: If name is present, this is optional, otherwise this dict needs to have at least a key with
                      ``name``. You may specify more keys to finetune the search.
        :type kargs: dict
        :return: The first item or a list with all matches.
        """
        matches = []

        # support the old style innovation without kwargs
        if name is not None:
            kargs["name"] = name

        kargs = self.__rekey(kargs)

        # no arguments is an error, so we don't return a false match
        if len(kargs) == 0:
            raise CX("calling find with no arguments")

        # performance: if the only key is name we can skip the whole loop
        if len(kargs) == 1 and "name" in kargs and not return_list:
            try:
                return self.listing.get(kargs["name"].lower(), None)
            except:
                return self.listing.get(kargs["name"], None)

        self.lock.acquire()
        try:
            for (name, obj) in list(self.listing.items()):
                if obj.find_match(kargs, no_errors=no_errors):
                    matches.append(obj)
        finally:
            self.lock.release()

        if not return_list:
            if len(matches) == 0:
                return None
            return matches[0]
        else:
            return matches
Example #15
0
 def set_remote_boot_kernel(self, remote_boot_kernel):
     """
     URL to a remote kernel. If the bootloader supports this feature,
     it directly tries to retrieve the kernel and boot it.
     (grub supports tftp and http protocol and server must be an IP).
     """
     if remote_boot_kernel:
         self.remote_grub_kernel = grub.parse_grub_remote_file(remote_boot_kernel)
         if not self.remote_grub_kernel:
             raise CX("Invalid URL for remote boot kernel: %s" % remote_boot_kernel)
         self.remote_boot_kernel = remote_boot_kernel
         return
     # Set to None or ""
     self.remote_grub_kernel = self.remote_boot_kernel = remote_boot_kernel
Example #16
0
def __parse_config():
    etcfile = '/etc/cobbler/users.conf'
    if not os.path.exists(etcfile):
        raise CX(_("/etc/cobbler/users.conf does not exist"))
    config = ConfigParser.ConfigParser()
    config.read(etcfile)
    alldata = {}
    sections = config.sections()
    for g in sections:
        alldata[str(g)] = {}
        opts = config.options(g)
        for o in opts:
            alldata[g][o] = 1
    return alldata
Example #17
0
    def set_mgmt_parameters(self, mgmt_parameters):
        """
        A YAML string which can be assigned to any object, this is used by Puppet's external_nodes feature.

        :param mgmt_parameters: The management parameters for an item.
        """
        if mgmt_parameters == "<<inherit>>":
            self.mgmt_parameters = mgmt_parameters
        else:
            import yaml
            data = yaml.safe_load(mgmt_parameters)
            if type(data) is not dict:
                raise CX(_("Input YAML in Puppet Parameter field must evaluate to a dictionary."))
            self.mgmt_parameters = data
Example #18
0
def hostname(dnsname):
    """
    Validate the dns name.

    :param dnsname: Hostname or FQDN
    :type dnsname: str
    :returns: dnsname
    :raises CX: If the Hostname/FQDN is not a string or in an invalid format.
    :rtype: str
    """
    if not isinstance(dnsname, str):
        raise CX("Invalid input, dnsname must be a string")
    else:
        dnsname = dnsname.strip()

    if dnsname == "":
        # hostname is not required
        return dnsname

    if not RE_HOSTNAME.match(dnsname):
        raise CX("Invalid hostname format (%s)" % dnsname)

    return dnsname
Example #19
0
 def set_remote_boot_initrd(self, remote_boot_initrd):
     """
     URL to a remote initrd. If the bootloader supports this feature,
     it directly tries to retrieve the initrd and boot it.
     (grub supports tftp and http protocol and server must be an IP).
     """
     if remote_boot_initrd:
         self.remote_grub_initrd = grub.parse_grub_remote_file(remote_boot_initrd)
         if not self.remote_grub_initrd:
             raise CX("Invalid URL for remote boot initrd: %s" % remote_boot_initrd)
         self.remote_boot_initrd = remote_boot_initrd
         return
     # Set to None or ""
     self.remote_grub_initrd = self.remote_boot_initrd = remote_boot_initrd
Example #20
0
    def menu(self, menu: str):
        """
        TODO

        :param menu: The menu for the profile.
        :raises CX
        """
        if not isinstance(menu, str):
            raise TypeError("Field menu of object profile needs to be of type str!")
        if menu and menu != "":
            menu_list = self.api.menus()
            if not menu_list.find(name=menu):
                raise CX("menu %s not found" % menu)
        self._menu = menu
Example #21
0
def ipv4_address(addr):
    """
    Validate an IPv4 address.

    :param addr: (ipv4 address)
    :type addr: str
    :returns: str addr or CX
    """
    if not isinstance(addr, str):
        raise CX("Invalid input, addr must be a string")
    else:
        addr = addr.strip()

    if addr == "":
        return addr

    if not netaddr.valid_ipv4(addr):
        raise CX("Invalid IPv4 address format (%s)" % addr)

    if netaddr.IPAddress(addr).is_netmask():
        raise CX("Invalid IPv4 host address (%s)" % addr)

    return addr
Example #22
0
    def parent(self, value: str):
        """
        Setter for the parent menu of a menu.

        :param value: The name of the parent to set.
        """
        old_parent = self._parent
        if isinstance(old_parent, item.Item):
            old_parent.children.remove(self.name)
        if not value:
            self._parent = ""
            return
        if value == self.name:
            # check must be done in two places as the parent setter could be called before/after setting the name...
            raise CX("self parentage is weird")
        found = self.api.menus().find(name=value)
        if found is None:
            raise CX("menu %s not found" % value)
        self._parent = value
        self.depth = found.depth + 1
        parent = self._parent
        if isinstance(parent, item.Item):
            parent.children.append(self.name)
Example #23
0
 def set_distro(self, distro_name):
     """
     Sets the distro. This must be the name of an existing Distro object in the Distros collection.
     """
     d = self.collection_mgr.distros().find(name=distro_name)
     if d is not None:
         old_parent = self.get_parent()
         if isinstance(old_parent, item.Item):
             old_parent.children.pop(self.name, 'pass')
         self.distro = distro_name
         self.depth = d.depth + 1  # reset depth if previously a subprofile and now top-level
         d.children[self.name] = self
         return
     raise CX("distribution not found")
Example #24
0
    def delete_interface(self, name):
        """
        Used to remove an interface.
        """
        if name in self.interfaces and len(self.interfaces) > 1:
            del self.interfaces[name]
        else:
            if name not in self.interfaces:
                # no interface here to delete
                pass
            else:
                raise CX(_("At least one interface needs to be defined."))

        return True
Example #25
0
    def menu(self, menu: str):
        """
        Setter for the menu property.

        :param menu: The menu for the image.
        :raises CX: In case the menu to be set could not be found.
        """
        if not isinstance(menu, str):
            raise TypeError("Field menu of object profile needs to be of type str!")
        if menu and menu != "":
            menu_list = self.api.menus()
            if not menu_list.find(name=menu):
                raise CX("menu %s not found" % menu)
        self._menu = menu
Example #26
0
    def set_action(self, action):
        """
        All management resources have an action. Action determine weather a most resources should be created or removed,
        and if packages should be installed or uninstalled.

        :param action: The action which should be executed for the management resource. Must be on of "create" or
                       "remove". Parameter is case-insensitive.
        :type action: str
        """
        action = action.lower()
        valid_actions = ['create', 'remove']
        if action not in valid_actions:
            raise CX('%s is not a valid action' % action)
        self.action = action
Example #27
0
    def check_for_invalid_imports(self, data: str):
        """
        Ensure that Cheetah code is not importing Python modules that may allow for advanced privileges by ensuring we
        whitelist the imports that we allow.

        :param data: The Cheetah code to check.
        """
        lines = data.split("\n")
        for line in lines:
            if line.find("#import") != -1:
                rest = line.replace("#import", "").replace(" ", "").strip()
                if self.settings and rest not in self.settings.cheetah_import_whitelist:
                    raise CX("potentially insecure import in template: %s" %
                             rest)
Example #28
0
    def validate_autoinstall_template_file_path(self, autoinstall, for_item=True, new_autoinstall=False):
        """
        Validate the automatic installation template's relative file path.

        :param autoinstall: automatic installation template relative file path
        :type autoinstall: str
        :param for_item: enable/disable special handling for Item objects
        :type for_item: bool
        :param new_autoinstall: when set to true new filenames are allowed
        :type new_autoinstall: bool
        :returns: automatic installation template relative file path
        :rtype: str
        """

        if not isinstance(autoinstall, str):
            raise CX("Invalid input, autoinstall must be a string")
        else:
            autoinstall = autoinstall.strip()

        if autoinstall == "":
            # empty autoinstall is allowed (interactive installations)
            return autoinstall

        if for_item is True:
            # this autoinstall value has special meaning for Items
            # other callers of this function have no use for this
            if autoinstall == "<<inherit>>":
                return autoinstall

        if autoinstall.find("..") != -1:
            raise CX("Invalid automatic installation template file location %s, it must not contain .." % autoinstall)

        autoinstall_path = "%s/%s" % (self.templates_base_dir, autoinstall)
        if not os.path.isfile(autoinstall_path) and not new_autoinstall:
            raise CX("Invalid automatic installation template file location %s, file not found" % autoinstall_path)

        return autoinstall
Example #29
0
    def set_file(self, filename):
        """
        Stores the image location.  This should be accessible on all nodes
        that need to access it.  Format: can be one of the following:
        * username:password@hostname:/path/to/the/filename.ext
        * username@hostname:/path/to/the/filename.ext
        * hostname:/path/to/the/filename.ext
        * /path/to/the/filename.ext
        """
        uri = ""
        auth = hostname = path = ""
        # validate file location format
        if filename.find("://") != -1:
            raise CX("Invalid image file path location, it should not contain a protocol")
        uri = filename

        if filename.find("@") != -1:
            auth, filename = filename.split("@")
        # extract the hostname
        # 1. if we have a colon, then everything before it is a hostname
        # 2. if we don't have a colon, there is no hostname
        if filename.find(":") != -1:
            hostname, filename = filename.split(":")
        elif filename[0] != '/':
            raise CX(_("invalid file: %s" % filename))
        # raise an exception if we don't have a valid path
        if len(filename) > 0 and filename[0] != '/':
            raise CX(_("file contains an invalid path: %s" % filename))
        if filename.find("/") != -1:
            path, filename = filename.rsplit("/", 1)

        if len(filename) == 0:
            raise CX(_("missing filename"))
        if len(auth) > 0 and len(hostname) == 0:
            raise CX(_("a hostname must be specified with authentication details"))

        self.file = uri
Example #30
0
    def remove(self,
               name,
               with_delete=True,
               with_sync=True,
               with_triggers=True,
               recursive=False,
               logger=None):
        """
        Remove element named 'name' from the collection
        """
        # NOTE: with_delete isn't currently meaningful for repos
        # but is left in for consistancy in the API.  Unused.
        name = name.lower()
        obj = self.find(name=name)
        if obj is not None:
            if with_delete:
                if with_triggers:
                    utils.run_triggers(
                        self.collection_mgr.api, obj,
                        "/var/lib/cobbler/triggers/delete/repo/pre/*", [],
                        logger)

            self.lock.acquire()
            try:
                del self.listing[name]
            finally:
                self.lock.release()
            self.collection_mgr.serialize_delete(self, obj)

            if with_delete:
                if with_triggers:
                    utils.run_triggers(
                        self.collection_mgr.api, obj,
                        "/var/lib/cobbler/triggers/delete/repo/post/*", [],
                        logger)
                    utils.run_triggers(self.collection_mgr.api, obj,
                                       "/var/lib/cobbler/triggers/change/*",
                                       [], logger)

                # FIXME: better use config.settings() webdir?
                path = "/var/www/cobbler/repo_mirror/%s" % obj.name
                if os.path.exists("/srv/www/"):
                    path = "/srv/www/cobbler/repo_mirror/%s" % obj.name
                if os.path.exists(path):
                    utils.rmtree(path)

            return

        raise CX(_("cannot delete an object that does not exist: %s") % name)