Exemplo n.º 1
0
 def set_class_name(self, name):
     if not isinstance(name, str):
         raise CX(_("class name must be a string"))
     for x in name:
         if not x.isalnum() and x not in ["_", "-", ".", ":", "+"]:
             raise CX(_("invalid characters in class name: '%s'" % name))
     self.class_name = name
Exemplo n.º 2
0
 def set_parent(self, parent_name):
     """
     Instead of a --distro, set the parent of this object to another profile
     and use the values from the parent instead of this one where the values
     for this profile aren't filled in, and blend them together where they
     are dictionaries.  Basically this enables profile inheritance.  To use this,
     the object MUST have been constructed with is_subobject=True or the
     default values for everything will be screwed up and this will likely NOT
     work.  So, API users -- make sure you pass is_subobject=True into the
     constructor when using this.
     """
     old_parent = self.get_parent()
     if isinstance(old_parent, item.Item):
         old_parent.children.pop(self.name, 'pass')
     if parent_name is None or parent_name == '':
         self.parent = ''
         return
     if parent_name == self.name:
         # check must be done in two places as set_parent could be called before/after
         # set_name...
         raise CX(_("self parentage is weird"))
     found = self.collection_mgr.profiles().find(name=parent_name)
     if found is None:
         raise CX(_("profile %s not found, inheritance not possible") % parent_name)
     self.parent = parent_name
     self.depth = found.depth + 1
     parent = self.get_parent()
     if isinstance(parent, item.Item):
         parent.children[self.name] = self
Exemplo n.º 3
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]
Exemplo n.º 4
0
Arquivo: api.py Projeto: akurz/cobbler
    def auto_add_repos(self):
        """
        Import any repos this server knows about and mirror them.
        Credit: Seth Vidal.
        """
        self.log("auto_add_repos")
        try:
            import yum
        except:
            raise CX(_("yum is not installed"))

        version = yum.__version__
        (a, b, c) = version.split(".")
        version = a * 1000 + b * 100 + c
        if version < 324:
            raise CX(_("need yum > 3.2.4 to proceed"))

        base = yum.YumBase()
        base.doRepoSetup()
        repos = base.repos.listEnabled()
        if len(repos) == 0:
            raise CX(_("no repos enabled/available -- giving up."))

        for repo in repos:
            url = repo.urls[0]
            cobbler_repo = self.new_repo()
            auto_name = repo.name.replace(" ", "")
            # FIXME: probably doesn't work for yum-rhn-plugin ATM
            cobbler_repo.set_mirror(url)
            cobbler_repo.set_name(auto_name)
            print "auto adding: %s (%s)" % (auto_name, url)
            self._collection_mgr.repos().add(cobbler_repo, save=True)
Exemplo n.º 5
0
    def __duplication_checks(self, ref, check_for_duplicate_names, check_for_duplicate_netinfo):
        """
        Prevents adding objects with the same name.
        Prevents adding or editing to provide the same IP, or MAC.
        Enforcement is based on whether the API caller requests it.
        """
        # always protect against duplicate names
        if check_for_duplicate_names:
            match = None
            if isinstance(ref, item_system.System):
                match = self.api.find_system(ref.name)
            elif isinstance(ref, item_profile.Profile):
                match = self.api.find_profile(ref.name)
            elif isinstance(ref, item_distro.Distro):
                match = self.api.find_distro(ref.name)
            elif isinstance(ref, item_repo.Repo):
                match = self.api.find_repo(ref.name)
            elif isinstance(ref, item_image.Image):
                match = self.api.find_image(ref.name)
            elif isinstance(ref, item_mgmtclass.Mgmtclass):
                match = self.api.find_mgmtclass(ref.name)
            else:
                raise CX("internal error, unknown object type")

            if match:
                raise CX(_("An object already exists with that name.  Try 'edit'?"))

        # the duplicate mac/ip checks can be disabled.
        if not check_for_duplicate_netinfo:
            return

        if isinstance(ref, item_system.System):
            for (name, intf) in ref.interfaces.iteritems():
                match_ip = []
                match_mac = []
                match_hosts = []
                input_mac = intf["mac_address"]
                input_ip = intf["ip_address"]
                input_dns = intf["dns_name"]
                if not self.api.settings().allow_duplicate_macs and input_mac is not None and input_mac != "":
                    match_mac = self.api.find_system(mac_address=input_mac, return_list=True)
                if not self.api.settings().allow_duplicate_ips and input_ip is not None and input_ip != "":
                    match_ip = self.api.find_system(ip_address=input_ip, return_list=True)
                # it's ok to conflict with your own net info.

                if not self.api.settings().allow_duplicate_hostnames and input_dns is not None and input_dns != "":
                    match_hosts = self.api.find_system(dns_name=input_dns, return_list=True)

                for x in match_mac:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s. The MAC address (%s) is already used by system %s (%s)") % (ref.name, intf["mac_address"], x.name, name))
                for x in match_ip:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s. The IP address (%s) is already used by system %s (%s)") % (ref.name, intf["ip_address"], x.name, name))
                for x in match_hosts:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s.  The dns name (%s) is already used by system %s (%s)") % (ref.name, intf["dns_name"], x.name, name))
Exemplo n.º 6
0
 def rename_interface(self, names):
     """
     Used to rename an interface.
     """
     (name, newname) = names
     if name not in self.interfaces:
         raise CX(_("Interface %s does not exist" % name))
     if newname in self.interfaces:
         raise CX(_("Interface %s already exists" % newname))
     else:
         self.interfaces[newname] = self.interfaces[name]
         del self.interfaces[name]
Exemplo n.º 7
0
    def remove(self, name, with_delete=True, with_sync=True, with_triggers=True, recursive=True, 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()

        # first see if any Groups use this distro
        if not recursive:
            for v in self.config.systems():
                if v.image is not None and v.image.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:
                    self.config.api.remove_system(k, recursive=True, logger=logger)

            if with_delete:
                if with_triggers:
                    utils.run_triggers(self.config.api, obj, "/var/lib/cobbler/triggers/delete/image/pre/*", [], logger)
                if with_sync:
                    lite_sync = action_litesync.BootLiteSync(self.config, logger=logger)
                    lite_sync.remove_single_image(name)

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

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

            return True

        raise CX(_("cannot delete an object that does not exist: %s") % name)
Exemplo n.º 8
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)
Exemplo n.º 9
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()
        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/file/*", [], 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/file/post/*", [], logger)
                    utils.run_triggers(self.collection_mgr.api, obj, "/var/lib/cobbler/triggers/change/*", [], logger)

            return

        raise CX(_("cannot delete an object that does not exist: %s") % name)
Exemplo n.º 10
0
    def set_profile(self, profile_name):
        """
        Set the system to use a certain named profile. The profile
        must have already been loaded into the Profiles collection.
        """
        old_parent = self.get_parent()
        if profile_name in ["delete", "None", "~", ""] or profile_name is None:
            self.profile = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return True

        self.image = ""         # mutual exclusion rule

        p = self.config.profiles().find(name=profile_name)
        if p is not None:
            self.profile = profile_name
            self.depth = p.depth + 1            # subprofiles have varying depths.
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return True
        raise CX(_("invalid profile name: %s") % profile_name)
Exemplo n.º 11
0
    def set_image(self, image_name):
        """
        Set the system to use a certain named image.  Works like set_profile
        but cannot be used at the same time.  It's one or the other.
        """
        old_parent = self.get_parent()
        if image_name in ["delete", "None", "~", ""] or image_name is None:
            self.image = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return True

        self.profile = ""       # mutual exclusion rule

        img = self.config.images().find(name=image_name)

        if img is not None:
            self.image = image_name
            self.depth = img.depth + 1
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return True
        raise CX(_("invalid image name (%s)") % image_name)
Exemplo n.º 12
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 = ""
        scheme = auth = hostname = path = ""
        # we'll discard the protocol if it's supplied, for legacy support
        if filename.find("://") != -1:
            scheme, uri = filename.split("://")
            filename = uri
        else:
            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, then check if we had a scheme; if
        #    we did, then grab all before the first forward slash as the
        #    hostname; otherwise, we've got a bad file
        if filename.find(":") != -1:
            hostname, filename = filename.split(":")
        elif filename[0] != '/':
            if len(scheme) > 0:
                index = filename.find("/")
                hostname = filename[:index]
                filename = filename[index:]
            else:
                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
        return True
Exemplo n.º 13
0
 def set_interface_type(self, type, interface):
     interface_types = ["bridge", "bridge_slave", "bond", "bond_slave", "bonded_bridge_slave", "bmc", "na", ""]
     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
Exemplo n.º 14
0
    def __get_interface(self, name):

        if not name:
            raise CX(_("No network interface name provided"))
        if name not in self.interfaces:
            self.__create_interface(name)

        return self.interfaces[name]
Exemplo n.º 15
0
    def __write_named_conf(self):
        """
        Write out the named.conf main config file from the template.
        """
        settings_file = self.settings.bind_chroot_path + self.settings_file
        template_file = "/etc/cobbler/named.template"
        # forward_zones = self.settings.manage_forward_zones
        # reverse_zones = self.settings.manage_reverse_zones

        metadata = {'forward_zones': self.__forward_zones().keys(),
                    'reverse_zones': [],
                    'zone_include': ''}

        for zone in metadata['forward_zones']:
                txt = """
zone "%(zone)s." {
    type master;
    file "%(zone)s";
};
""" % {'zone': zone}
                metadata['zone_include'] = metadata['zone_include'] + txt

        for zone in self.__reverse_zones().keys():
            # IPv6 zones are : delimited
            if ":" in zone:
                # if IPv6, assume xxxx:xxxx:xxxx:xxxx
                #                 0123456789012345678
                long_zone = (self.__expand_IPv6(zone + '::1'))[:19]
                tokens = list(re.sub(':', '', long_zone))
                tokens.reverse()
                arpa = '.'.join(tokens) + '.ip6.arpa'
            else:
                # IPv4 address split by '.'
                tokens = zone.split('.')
                tokens.reverse()
                arpa = '.'.join(tokens) + '.in-addr.arpa'
                #
            metadata['reverse_zones'].append((zone, arpa))
            txt = """
zone "%(arpa)s." {
    type master;
    file "%(zone)s";
};
""" % {'arpa': arpa, 'zone': zone}
            metadata['zone_include'] = metadata['zone_include'] + txt

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error reading template from file: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        if self.logger is not None:
            self.logger.info("generating %s" % settings_file)
        self.templar.render(template_data, metadata, settings_file, None)
Exemplo n.º 16
0
 def set_supported_boot_loaders(self, supported_boot_loaders):
     """
     Some distributions, particularly on powerpc, can only be netbooted using
     specific bootloaders.
     """
     if len(supported_boot_loaders) < 1:
         raise CX(_("No valid supported boot loaders specified for distro '%s'" % self.name))
     self.supported_boot_loaders = supported_boot_loaders
     self.boot_loader = supported_boot_loaders[0]
Exemplo n.º 17
0
 def set_ipv6_address(self, address, interface):
     """
     Assign a IP or hostname in DHCP when this MAC boots.
     Only works if manage_dhcp is set in /etc/cobbler/settings
     """
     intf = self.__get_interface(interface)
     if address == "" or utils.is_ip(address):
         intf["ipv6_address"] = address.strip()
         return True
     raise CX(_("invalid format for IPv6 IP address (%s)") % address)
Exemplo n.º 18
0
 def set_kernel_options_post(self, options):
     """
     Post kernel options are a space delimited list,
     like 'a=b c=d e=f g h i=j' or a dict.
     """
     (success, value) = utils.input_string_or_dict(options, allow_multiples=True)
     if not success:
         raise CX(_("invalid post kernel options"))
     else:
         self.kernel_options_post = value
Exemplo n.º 19
0
 def set_yumopts(self, options):
     """
     Kernel options are a space delimited list,
     like 'a=b c=d e=f g h i=j' or a dictionary.
     """
     (success, value) = utils.input_string_or_dict(options, allow_multiples=False)
     if not success:
         raise CX(_("invalid yum options"))
     else:
         self.yumopts = value
Exemplo n.º 20
0
 def set_environment(self, options):
     """
     Yum can take options from the environment.  This puts them there before
     each reposync.
     """
     (success, value) = utils.input_string_or_dict(options, allow_multiples=False)
     if not success:
         raise CX(_("invalid environment options"))
     else:
         self.environment = value
Exemplo n.º 21
0
 def set_priority(self, priority):
     """
     Set the priority of the repository.  1= highest, 99=default
     Only works if host is using priorities plugin for yum.
     """
     try:
         priority = int(str(priority))
     except:
         raise CX(_("invalid priority level: %s") % priority)
     self.priority = priority
Exemplo n.º 22
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
Exemplo n.º 23
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
Exemplo n.º 24
0
 def set_initrd(self, initrd):
     """
     Specifies an initrd image.  Path search works as in set_kernel.
     File must be named appropriately.
     """
     if initrd is None or initrd == "":
         raise CX("initrd not specified")
     if utils.find_initrd(initrd):
         self.initrd = initrd
         return
     raise CX(_("initrd not found"))
Exemplo n.º 25
0
    def generate_autoinstall_for_profile(self, g):

        g = self.api.find_profile(name=g)
        if g is None:
            return "# profile not found"

        distro = g.get_conceptual_parent()
        if distro is None:
            raise CX(_("profile %(profile)s references missing distro %(distro)s") % {"profile": g.name, "distro": g.distro})

        return self.generate_autoinstall(profile=g)
Exemplo n.º 26
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
Exemplo n.º 27
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."))
Exemplo n.º 28
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.
     """
     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
Exemplo n.º 29
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 = action_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)
Exemplo n.º 30
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 
Exemplo n.º 31
0
    def find(self, name=None, return_list=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.
        """
        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:
            return self.listing.get(kargs["name"].lower(), None)

        self.lock.acquire()
        try:
            for (name, obj) in self.listing.iteritems():
                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
Exemplo n.º 32
0
    def __find_compare(self, from_search, from_obj):

        if isinstance(from_obj, basestring):
            # FIXME: fnmatch is only used for string to string comparisions
            # which should cover most major usage, if not, this deserves fixing
            if fnmatch.fnmatch(from_obj.lower(), from_search.lower()):
                return True
            else:
                return False
        else:
            if isinstance(from_search, basestring):
                if isinstance(from_obj, list):
                    from_search = utils.input_string_or_list(from_search)
                    for x in from_search:
                        if x not in from_obj:
                            return False
                    return True
                if isinstance(from_obj, dict):
                    (junk, from_search) = utils.input_string_or_dict(
                        from_search, allow_multiples=True)
                    for x in from_search.keys():
                        y = from_search[x]
                        if x not in from_obj:
                            return False
                        if not (y == from_obj[x]):
                            return False
                    return True
                if isinstance(from_obj, bool):
                    if from_search.lower() in ["true", "1", "y", "yes"]:
                        inp = True
                    else:
                        inp = False
                    if inp == from_obj:
                        return True
                    return False

            raise CX(_("find cannot compare type: %s") % type(from_obj))
Exemplo n.º 33
0
def write_genders_file(config, profiles_genders, distros_genders,
                       mgmtcls_genders):
    """
    genders file is over-written when manage_genders is set in
    /var/lib/cobbler/settings.
    """

    templar_inst = cobbler.templar.Templar(config)
    try:
        f2 = open(template_file, "r")
    except:
        raise CX(_("error reading template: %s") % template_file)
    template_data = ""
    template_data = f2.read()
    f2.close()

    metadata = {
        "date": time.asctime(time.gmtime()),
        "profiles_genders": profiles_genders,
        "distros_genders": distros_genders,
        "mgmtcls_genders": mgmtcls_genders
    }

    templar_inst.render(template_data, metadata, settings_file, None)
Exemplo n.º 34
0
 def set_ipv6_default_gateway(self, address, interface):
     intf = self.__get_interface(interface)
     if address == "" or utils.is_ip(address):
         intf["ipv6_default_gateway"] = address.strip()
         return True
     raise CX(_("invalid format for IPv6 IP address (%s)") % address)
Exemplo n.º 35
0
    def rename(self, ref, newname, with_sync=True, with_triggers=True, logger=None):
        """
        Allows an object "ref" to be given a newname without affecting the rest
        of the object tree.
        """
        # Nothing to do when it is the same name
        if newname == ref.name:
            return True

        # make a copy of the object, but give it a new name.
        oldname = ref.name
        newref = ref.make_clone()
        newref.set_name(newname)

        self.add(newref, with_triggers=with_triggers, save=True)

        # for mgmt classes, update all objects that use it
        if ref.COLLECTION_TYPE == "mgmtclass":
            for what in ["distro", "profile", "system"]:
                items = self.api.find_items(what, {"mgmt_classes": oldname})
                for item in items:
                    for i in range(0, len(item.mgmt_classes)):
                        if item.mgmt_classes[i] == oldname:
                            item.mgmt_classes[i] = newname
                    self.api.add_item(what, item, save=True)

        # for a repo, rename the mirror directory
        if ref.COLLECTION_TYPE == "repo":
            path = "/var/www/cobbler/repo_mirror/%s" % ref.name
            if os.path.exists(path):
                newpath = "/var/www/cobbler/repo_mirror/%s" % newref.name
                os.renames(path, newpath)

        # for a distro, rename the mirror and references to it
        if ref.COLLECTION_TYPE == 'distro':
            path = utils.find_distro_path(self.api.settings(), ref)

            # create a symlink for the new distro name
            utils.link_distro(self.api.settings(), newref)

            # test to see if the distro path is based directly
            # on the name of the distro. If it is, things need
            # to updated accordingly
            if os.path.exists(path) and path == "/var/www/cobbler/ks_mirror/%s" % ref.name:
                newpath = "/var/www/cobbler/ks_mirror/%s" % newref.name
                os.renames(path, newpath)

                # update any reference to this path ...
                distros = self.api.distros()
                for d in distros:
                    if d.kernel.find(path) == 0:
                        d.set_kernel(d.kernel.replace(path, newpath))
                        d.set_initrd(d.initrd.replace(path, newpath))
                        self.config.serialize_item(self, d)

        # now descend to any direct ancestors and point them at the new object allowing
        # the original object to be removed without orphanage.  Direct ancestors
        # will either be profiles or systems.  Note that we do have to care as
        # set_parent is only really meaningful for subprofiles. We ideally want a more
        # generic set_parent.
        kids = ref.get_children()
        for k in kids:
            if k.COLLECTION_TYPE == "distro":
                raise CX(_("internal error, not expected to have distro child objects"))
            elif k.COLLECTION_TYPE == "profile":
                if k.parent != "":
                    k.set_parent(newname)
                else:
                    k.set_distro(newname)
                self.api.profiles().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
            elif k.COLLECTION_TYPE == "system":
                k.set_profile(newname)
                self.api.systems().add(k, save=True, with_sync=with_sync, with_triggers=with_triggers)
            elif k.COLLECTION_TYPE == "repo":
                raise CX(_("internal error, not expected to have repo child objects"))
            else:
                raise CX(_("internal error, unknown child type (%s), cannot finish rename" % k.COLLECTION_TYPE))

        # now delete the old version
        self.remove(oldname, with_delete=True, with_triggers=with_triggers)
        return True
Exemplo n.º 36
0
    def write_dhcp_file(self):
        """
        DHCP files are written when manage_dhcp is set in
        /etc/cobbler/settings.
        """

        template_file = "/etc/cobbler/dhcp.template"
        blender_cache = {}

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error reading template: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        # use a simple counter for generating generic names where a hostname
        # is not available
        counter = 0

        # we used to just loop through each system, but now we must loop
        # through each network interface of each system.
        dhcp_tags = {"default": {}}
        yaboot = "/yaboot"

        # FIXME: ding should evolve into the new dhcp_tags dict
        ding = {}

        for system in self.systems:
            if not system.is_management_supported(cidr_ok=False):
                continue

            profile = system.get_conceptual_parent()
            distro = profile.get_conceptual_parent()

            # if distro is None then the profile is really an image record
            for (name, interface) in system.interfaces.iteritems():

                # this is really not a per-interface setting
                # but we do this to make the templates work
                # without upgrade
                interface["gateway"] = system.gateway
                mac = interface["mac_address"]

                if interface["interface_type"] in ("bond_slave",
                                                   "bridge_slave",
                                                   "bonded_bridge_slave"):

                    if interface["interface_master"] not in system.interfaces:
                        # Can't write DHCP entry; master interface does not exist
                        continue

                    if system.name not in ding:
                        ding[system.name] = {interface["interface_master"]: []}
                    else:
                        ding[system.name][interface["interface_master"]] = []

                    if len(ding[system.name][
                            interface["interface_master"]]) == 0:
                        ding[system.name][
                            interface["interface_master"]].append(mac)

                    ip = system.interfaces[
                        interface["interface_master"]]["ip_address"]
                    netmask = system.interfaces[
                        interface["interface_master"]]["netmask"]
                    dhcp_tag = system.interfaces[
                        interface["interface_master"]]["dhcp_tag"]
                    host = system.interfaces[
                        interface["interface_master"]]["dns_name"]

                    if ip is None or ip == "":
                        for (nam2, int2) in system.interfaces.iteritems():
                            if (nam2.startswith(interface["interface_master"] +
                                                ".")
                                    and int2["ip_address"] is not None
                                    and int2["ip_address"] != ""):
                                ip = int2["ip_address"]
                                break

                    interface["ip_address"] = ip
                    interface["netmask"] = netmask
                else:
                    ip = interface["ip_address"]
                    netmask = interface["netmask"]
                    dhcp_tag = interface["dhcp_tag"]
                    host = interface["dns_name"]

                if distro is not None:
                    interface["distro"] = distro.to_dict()

                if mac is None or mac == "":
                    # can't write a DHCP entry for this system
                    continue

                counter = counter + 1

                # the label the entry after the hostname if possible
                if host is not None and host != "":
                    if name != "eth0":
                        interface["name"] = "%s-%s" % (host, name)
                    else:
                        interface["name"] = "%s" % (host)
                else:
                    interface["name"] = "generic%d" % counter

                # add references to the system, profile, and distro
                # for use in the template
                if system.name in blender_cache:
                    blended_system = blender_cache[system.name]
                else:
                    blended_system = utils.blender(self.api, False, system)
                    blender_cache[system.name] = blended_system

                interface["next_server"] = blended_system["next_server"]
                interface["netboot_enabled"] = blended_system[
                    "netboot_enabled"]
                interface["hostname"] = blended_system["hostname"]
                interface["owner"] = blended_system["name"]
                interface["enable_gpxe"] = blended_system["enable_gpxe"]
                interface["name_servers"] = blended_system["name_servers"]

                if not self.settings.always_write_dhcp_entries:
                    if not interface["netboot_enabled"] and interface['static']:
                        continue

                if distro is not None:
                    if distro.arch.startswith("ppc"):
                        if blended_system["boot_loader"] == "pxelinux":
                            del interface["filename"]
                        elif distro.boot_loader == "grub2" or blended_system[
                                "boot_loader"] == "grub2":
                            interface[
                                "filename"] = "boot/grub/powerpc-ieee1275/core.elf"
                        else:
                            interface["filename"] = yaboot

                if dhcp_tag == "":
                    dhcp_tag = blended_system["dhcp_tag"]
                    if dhcp_tag == "":
                        dhcp_tag = "default"

                if dhcp_tag not in dhcp_tags:
                    dhcp_tags[dhcp_tag] = {mac: interface}
                else:
                    dhcp_tags[dhcp_tag][mac] = interface

        # we are now done with the looping through each interface of each system
        metadata = {
            "date":
            time.asctime(time.gmtime()),
            "cobbler_server":
            "%s:%s" % (self.settings.server, self.settings.http_port),
            "next_server":
            self.settings.next_server,
            "yaboot":
            yaboot,
            "dhcp_tags":
            dhcp_tags
        }

        if self.logger is not None:
            self.logger.info("generating %s" % self.settings_file)
        self.templar.render(template_data, metadata, self.settings_file, None)
Exemplo n.º 37
0
class Distro(item.Item):
    """
    A Cobbler distribution object
    """

    TYPE_NAME = _("distro")
    COLLECTION_TYPE = "distro"

    def __init__(self, *args, **kwargs):
        """
        This creates a Distro object.

        :param args: Place for extra parameters in this distro object.
        :param kwargs: Place for extra parameters in this distro object.
        """
        super(Distro, self).__init__(*args, **kwargs)
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.autoinstall_meta = {}
        self.source_repos = []
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}
        self.remote_grub_kernel = ""
        self.remote_grub_initrd = ""

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):
        """
        Clone a distro object.

        :return: The cloned object. Not persisted on the disk or in a database.
        """
        _dict = self.to_dict()
        cloned = Distro(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        """
        Return the list of fields and their properties
        """
        return FIELDS

    def get_parent(self):
        """
        Distros don't have parent objects.
        """
        return None

    def check_if_valid(self):
        """
        Check if a distro object is valid. If invalid an exception is raised.
        """
        if self.name is None:
            raise CX("name is required")
        if self.kernel is None:
            raise CX("Error with distro %s - kernel is required" % (self.name))
        if self.initrd is None:
            raise CX("Error with distro %s - initrd is required" % (self.name))

        # self.remote_grub_kernel has to be set in set_remote_boot_kernel and here
        # in case the distro is read from json file (setters are not called).
        if self.remote_boot_kernel:
            self.remote_grub_kernel = grub.parse_grub_remote_file(
                self.remote_boot_kernel)
            if not self.remote_grub_kernel:
                raise CX("Invalid URL for remote boot kernel: %s" %
                         self.remote_boot_kernel)
        if self.remote_boot_initrd:
            self.remote_grub_initrd = grub.parse_grub_remote_file(
                self.remote_boot_initrd)
            if not self.remote_grub_initrd:
                raise CX("Invalid URL for remote boot initrd: %s" %
                         self.remote_boot_initrd)

        if utils.file_is_remote(self.kernel):
            if not utils.remote_file_exists(self.kernel):
                raise CX("Error with distro %s - kernel '%s' not found" %
                         (self.name, self.kernel))
        elif not os.path.exists(self.kernel):
            raise CX("Error with distro %s - kernel '%s' not found" %
                     (self.name, self.kernel))

        if utils.file_is_remote(self.initrd):
            if not utils.remote_file_exists(self.initrd):
                raise CX("Error with distro %s - initrd path '%s' not found" %
                         (self.name, self.initrd))
        elif not os.path.exists(self.initrd):
            raise CX("Error with distro %s - initrd path '%s' not found" %
                     (self.name, self.initrd))

    #
    # specific methods for item.Distro
    #

    def set_kernel(self, kernel):
        """
        Specifies a kernel. The kernel parameter is a full path, a filename in the configured kernel directory (set in
        /etc/cobbler.conf) or a directory path that would contain a selectable kernel. Kernel naming conventions are
        checked, see docs in the utils module for ``find_kernel``.

        :param kernel:
        :raises CX: If the kernel was not found
        """
        if kernel is None or kernel == "":
            raise CX("kernel not specified")
        if utils.find_kernel(kernel):
            self.kernel = kernel
            return
        raise CX("kernel not found: %s" % kernel)

    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

    def set_tree_build_time(self, datestamp):
        """
        Sets the import time of the distro. If not imported, this field is not meaningful.

        :param datestamp: The datestamp to save the builddate. There is an attempt to convert it to a float, so please
                          make sure it is compatible to this.
        """
        self.tree_build_time = float(datestamp)

    def set_breed(self, breed):
        """
        Set the Operating system breed.

        :param breed: The new breed to set.
        """
        return utils.set_breed(self, breed)

    def set_os_version(self, os_version):
        """
        Set the Operating System Version.

        :param os_version: The new OS Version.
        """
        return utils.set_os_version(self, os_version)

    def set_initrd(self, initrd):
        """
        Specifies an initrd image. Path search works as in set_kernel. File must be named appropriately.

        :param initrd: The new path to the ``initrd``.
        """
        if initrd is None or initrd == "":
            raise CX("initrd not specified")
        if utils.find_initrd(initrd):
            self.initrd = initrd
            return
        raise CX(_("initrd not found"))

    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

    def set_source_repos(self, repos):
        """
        A list of http:// URLs on the Cobbler server that point to yum configuration files that can be used to
        install core packages. Use by ``cobbler import`` only.

        :param repos: The list of URLs.
        """
        self.source_repos = repos

    def set_arch(self, arch):
        """
        The field is mainly relevant to PXE provisioning.

        Using an alternative distro type allows for dhcpd.conf templating to "do the right thing" with those
        systems -- this also relates to bootloader configuration files which have different syntax for different
        distro types (because of the bootloaders).

        This field is named "arch" because mainly on Linux, we only care about the architecture, though if (in the
        future) new provisioning types are added, an arch value might be something like "bsd_x86".

        :param arch: The architecture of the operating system distro.
        """
        return utils.set_arch(self, arch)

    def get_arch(self):
        """
        Return the architecture of the distribution

        :return: Return the current architecture.
        """
        return self.arch

    def set_supported_boot_loaders(self, supported_boot_loaders):
        """
        Some distributions, particularly on powerpc, can only be netbooted using specific bootloaders.

        :param supported_boot_loaders: The bootloaders which are available for being set.
        """
        if len(supported_boot_loaders) < 1:
            raise CX(
                _("No valid supported boot loaders specified for distro '%s'" %
                  self.name))
        self.supported_boot_loaders = supported_boot_loaders
        self.boot_loader = supported_boot_loaders[0]

    def set_boot_loader(self, name):
        """
        Set the bootloader for the distro.

        :param name: The name of the bootloader. Must be one of the supported ones.
        """
        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

    def set_redhat_management_key(self, management_key):
        """
        Set the redhat management key. This is probably only needed if you have spacewalk, uyuni or SUSE Manager
        running.

        :param management_key: The redhat management key.
        """
        if management_key is None:
            self.redhat_management_key = ""
        self.redhat_management_key = management_key

    def get_redhat_management_key(self):
        """
        Get the redhat management key. This is probably only needed if you have spacewalk, uyuni or SUSE Manager
        running.

        :return: The key as a string.
        :rtype: str
        """
        return self.redhat_management_key
Exemplo n.º 38
0
    def write_dhcp_file(self):
        """
        DHCP files are written when manage_dhcp is set in
        /var/lib/cobbler/settings.
        """

        settings_file = "/etc/dnsmasq.conf"
        template_file = "/etc/cobbler/dnsmasq.template"

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error writing template to file: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        system_definitions = {}
        counter = 0

        # we used to just loop through each system, but now we must loop
        # through each network interface of each system.

        for system in self.systems:

            if not system.is_management_supported(cidr_ok=False):
                continue

            profile = system.get_conceptual_parent()
            distro = profile.get_conceptual_parent()
            for (name, interface) in list(system.interfaces.items()):

                mac = interface["mac_address"]
                ip = interface["ip_address"]
                host = interface["dns_name"]
                ipv6 = interface["ipv6_address"]

                if mac is None or mac == "":
                    # can't write a DHCP entry for this system
                    continue

                counter += 1

                # In many reallife situations there is a need to control the IP address
                # and hostname for a specific client when only the MAC address is available.
                # In addition to that in some scenarios there is a need to explicitly
                # label a host with the applicable architecture in order to correctly
                # handle situations where we need something other than pxelinux.0.
                # So we always write a dhcp-host entry with as much info as possible
                # to allow maximum control and flexibility within the dnsmasq config

                systxt = "dhcp-host=net:" + distro.arch.lower() + "," + mac

                if host is not None and host != "":
                    systxt += "," + host

                if ip is not None and ip != "":
                    systxt += "," + ip
                if ipv6 is not None and ipv6 != "":
                    systxt += ",[%s]" % ipv6

                systxt += "\n"

                dhcp_tag = interface["dhcp_tag"]
                if dhcp_tag == "":
                    dhcp_tag = "default"

                if dhcp_tag not in system_definitions:
                    system_definitions[dhcp_tag] = ""
                system_definitions[
                    dhcp_tag] = system_definitions[dhcp_tag] + systxt

        # we are now done with the looping through each interface of each system

        metadata = {
            "insert_cobbler_system_definitions":
            system_definitions.get("default", ""),
            "date":
            time.asctime(time.gmtime()),
            "cobbler_server":
            self.settings.server,
            "next_server":
            self.settings.next_server,
        }

        # now add in other DHCP expansions that are not tagged with "default"
        for x in list(system_definitions.keys()):
            if x == "default":
                continue
            metadata["insert_cobbler_system_definitions_%s" %
                     x] = system_definitions[x]

        self.templar.render(template_data, metadata, settings_file, None)
Exemplo n.º 39
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 = action_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)
Exemplo n.º 40
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()

        # first see if any Groups use this distro
        if not recursive:
            for v in self.collection_mgr.profiles():
                if v.distro and v.distro.lower() == name:
                    raise CX(_("removal would orphan profile: %s") % v.name)

        obj = self.find(name=name)

        if obj is not None:
            kernel = obj.kernel
            if recursive:
                kids = obj.get_children()
                for k in kids:
                    self.collection_mgr.api.remove_profile(
                        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/distro/pre/*", [],
                        logger)
                if with_sync:
                    lite_sync = litesync.CobblerLiteSync(self.collection_mgr,
                                                         logger=logger)
                    lite_sync.remove_single_distro(name)
            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/distro/post/*", [],
                        logger)
                    utils.run_triggers(self.collection_mgr.api, obj,
                                       "/var/lib/cobbler/triggers/change/*",
                                       [], logger)

            # look through all mirrored directories and find if any directory is holding
            # this particular distribution's kernel and initrd
            settings = self.collection_mgr.settings()
            possible_storage = glob.glob(settings.webdir + "/distro_mirror/*")
            path = None
            for storage in possible_storage:
                if os.path.dirname(obj.kernel).find(storage) != -1:
                    path = storage
                    continue

            # if we found a mirrored path above, we can delete the mirrored storage /if/
            # no other object is using the same mirrored storage.
            if with_delete and path is not None and os.path.exists(
                    path) and kernel.find(settings.webdir) != -1:
                # this distro was originally imported so we know we can clean up the associated
                # storage as long as nothing else is also using this storage.
                found = False
                distros = self.api.distros()
                for d in distros:
                    if d.kernel.find(path) != -1:
                        found = True
                if not found:
                    utils.rmtree(path)
Exemplo n.º 41
0
    def __duplication_checks(self, ref, check_for_duplicate_names, check_for_duplicate_netinfo):
        """
        Prevents adding objects with the same name.
        Prevents adding or editing to provide the same IP, or MAC.
        Enforcement is based on whether the API caller requests it.
        """
        # always protect against duplicate names
        if check_for_duplicate_names:
            match = None
            if isinstance(ref, item_system.System):
                match = self.api.find_system(ref.name)
            elif isinstance(ref, item_profile.Profile):
                match = self.api.find_profile(ref.name)
            elif isinstance(ref, item_distro.Distro):
                match = self.api.find_distro(ref.name)
            elif isinstance(ref, item_repo.Repo):
                match = self.api.find_repo(ref.name)
            elif isinstance(ref, item_image.Image):
                match = self.api.find_image(ref.name)
            elif isinstance(ref, item_mgmtclass.Mgmtclass):
                match = self.api.find_mgmtclass(ref.name)
            elif isinstance(ref, item_package.Package):
                match = self.api.find_package(ref.name)
            elif isinstance(ref, item_file.File):
                match = self.api.find_file(ref.name)
            else:
                raise CX("internal error, unknown object type")

            if match:
                raise CX(_("An object already exists with that name.  Try 'edit'?"))

        # the duplicate mac/ip checks can be disabled.
        if not check_for_duplicate_netinfo:
            return

        if isinstance(ref, item_system.System):
            for (name, intf) in ref.interfaces.iteritems():
                match_ip = []
                match_mac = []
                match_hosts = []
                input_mac = intf["mac_address"]
                input_ip = intf["ip_address"]
                input_dns = intf["dns_name"]
                if not self.api.settings().allow_duplicate_macs and input_mac is not None and input_mac != "":
                    match_mac = self.api.find_system(mac_address=input_mac, return_list=True)
                if not self.api.settings().allow_duplicate_ips and input_ip is not None and input_ip != "":
                    match_ip = self.api.find_system(ip_address=input_ip, return_list=True)
                # it's ok to conflict with your own net info.

                if not self.api.settings().allow_duplicate_hostnames and input_dns is not None and input_dns != "":
                    match_hosts = self.api.find_system(dns_name=input_dns, return_list=True)

                for x in match_mac:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s. The MAC address (%s) is already used by system %s (%s)") % (ref.name, intf["mac_address"], x.name, name))
                for x in match_ip:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s. The IP address (%s) is already used by system %s (%s)") % (ref.name, intf["ip_address"], x.name, name))
                for x in match_hosts:
                    if x.name != ref.name:
                        raise CX(_("Can't save system %s.  The dns name (%s) is already used by system %s (%s)") % (ref.name, intf["dns_name"], x.name, name))
Exemplo n.º 42
0
class System(item.Item):
    """
    A Cobbler system object.
    """

    TYPE_NAME = _("system")
    COLLECTION_TYPE = "system"

    def __init__(self, *args, **kwargs):
        super(System, self).__init__(*args, **kwargs)
        self.interfaces = dict()
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.autoinstall_meta = {}
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}

    #
    # override some base class methods first (item.Item)
    #

    def get_fields(self):
        return FIELDS

    def make_clone(self):
        _dict = self.to_dict()
        cloned = System(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def from_dict(self, seed_data):
        # FIXME: most definitely doesn't grok interfaces yet.
        return utils.from_dict_from_fields(self, seed_data, FIELDS)

    def get_parent(self):
        """
        Return object next highest up the tree.
        """
        if (self.parent is None or self.parent == '') and self.profile:
            return self.collection_mgr.profiles().find(name=self.profile)
        elif (self.parent is None or self.parent == '') and self.image:
            return self.collection_mgr.images().find(name=self.image)
        else:
            return self.collection_mgr.systems().find(name=self.parent)

    def check_if_valid(self):
        if self.name is None or self.name == "":
            raise CX("name is required")
        if self.profile is None or self.profile == "":
            if self.image is None or self.image == "":
                raise CX(
                    "Error with system %s - profile or image is required" %
                    (self.name))

    #
    # specific methods for item.System
    #

    def __create_interface(self, interface):

        self.interfaces[interface] = {}
        for field in NETWORK_INTERFACE_FIELDS:
            self.interfaces[interface][field[0]] = field[1]

    def __get_interface(self, name):

        if not name:
            raise CX(_("No network interface name provided"))
        if name not in self.interfaces:
            self.__create_interface(name)

        return self.interfaces[name]

    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."))

    def rename_interface(self, names):
        """
        Used to rename an interface.
        """
        (name, newname) = names
        if name not in self.interfaces:
            raise CX(_("Interface %s does not exist" % name))
        if newname in self.interfaces:
            raise CX(_("Interface %s already exists" % newname))
        else:
            self.interfaces[newname] = self.interfaces[name]
            del self.interfaces[name]

    def set_boot_loader(self, name):
        if name not in utils.get_supported_system_boot_loaders():
            raise CX(_("Invalid boot loader name: %s" % name))
        self.boot_loader = name

    def set_server(self, server):
        """
        If a system can't reach the boot server at the value configured in settings
        because it doesn't have the same name on it's subnet this is there for an override.
        """
        if server is None or server == "":
            server = "<<inherit>>"
        self.server = server

    def set_next_server(self, server):
        if server is None or server == "" or server == "<<inherit>>":
            self.next_server = "<<inherit>>"
        else:
            server = server.strip()
            self.next_server = validate.ipv4_address(server)

    def set_proxy(self, proxy):
        if proxy is None or proxy == "":
            proxy = "<<inherit>>"
        self.proxy = proxy

    def get_mac_address(self, interface):
        """
        Get the mac address, which may be implicit in the object name or explicit with --mac-address.
        Use the explicit location first.
        """

        intf = self.__get_interface(interface)

        if intf["mac_address"] != "":
            return intf["mac_address"].strip()
        else:
            return None

    def get_ip_address(self, interface):
        """
        Get the IP address for the given interface.
        """
        intf = self.__get_interface(interface)
        if intf["ip_address"] != "":
            return intf["ip_address"].strip()
        else:
            return ""

    def is_management_supported(self, cidr_ok=True):
        """
        Can only add system PXE records if a MAC or IP address is available, else it's a koan
        only record.
        """
        if self.name == "default":
            return True
        for (name, x) in list(self.interfaces.items()):
            mac = x.get("mac_address", None)
            ip = x.get("ip_address", None)
            if ip is not None and not cidr_ok and ip.find("/") != -1:
                # ip is in CIDR notation
                return False
            if mac is not None or ip is not None:
                # has ip and/or mac
                return True
        return False

    def set_dhcp_tag(self, dhcp_tag, interface):
        intf = self.__get_interface(interface)
        intf["dhcp_tag"] = dhcp_tag

    def set_cnames(self, cnames, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(cnames)
        intf["cnames"] = data

    def set_static_routes(self, routes, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(routes)
        intf["static_routes"] = data

    def set_status(self, status):
        self.status = status

    def set_static(self, truthiness, interface):
        intf = self.__get_interface(interface)
        intf["static"] = utils.input_boolean(truthiness)

    def set_management(self, truthiness, interface):
        intf = self.__get_interface(interface)
        intf["management"] = utils.input_boolean(truthiness)

# ---

    def set_dns_name(self, dns_name, interface):
        """
        Set DNS name for interface.

        @param: str dns_name (dns name)
        @param: str interface (interface name)
        @returns: True or CX
        """
        dns_name = validate.hostname(dns_name)
        if dns_name != "" and utils.input_boolean(
                self.collection_mgr._settings.allow_duplicate_hostnames
        ) is False:
            matched = self.collection_mgr.api.find_items(
                "system", {"dns_name": dns_name})
            for x in matched:
                if x.name != self.name:
                    raise CX("DNS name duplicated: %s" % dns_name)

        intf = self.__get_interface(interface)
        intf["dns_name"] = dns_name

    def set_hostname(self, hostname):
        """
        Set hostname.

        @param: str hostname (hostname for system)
        @returns: True or CX
        """
        self.hostname = validate.hostname(hostname)

    def set_ip_address(self, address, interface):
        """
        Set IPv4 address on interface.

        @param: str address (ip address)
        @param: str interface (interface name)
        @returns: True or CX
        """
        address = validate.ipv4_address(address)
        if address != "" and utils.input_boolean(
                self.collection_mgr._settings.allow_duplicate_ips) is False:
            matched = self.collection_mgr.api.find_items(
                "system", {"ip_address": address})
            for x in matched:
                if x.name != self.name:
                    raise CX("IP address duplicated: %s" % address)

        intf = self.__get_interface(interface)
        intf["ip_address"] = address

    def set_mac_address(self, address, interface):
        """
        Set mac address on interface.

        @param: str address (mac address)
        @param: str interface (interface name)
        @returns: True or CX
        """
        address = validate.mac_address(address)
        if address == "random":
            address = utils.get_random_mac(self.collection_mgr.api)
        if address != "" and utils.input_boolean(
                self.collection_mgr._settings.allow_duplicate_macs) is False:
            matched = self.collection_mgr.api.find_items(
                "system", {"mac_address": address})
            for x in matched:
                if x.name != self.name:
                    raise CX("MAC address duplicated: %s" % address)

        intf = self.__get_interface(interface)
        intf["mac_address"] = address

    def set_gateway(self, gateway):
        """
        Set a gateway IPv4 address.

        @param: str gateway (ip address)
        @returns: True or CX
        """
        self.gateway = validate.ipv4_address(gateway)

    def set_name_servers(self, data):
        """
        Set the DNS servers.

        @param: str/list data (string or list of nameservers)
        @returns: True or CX
        """
        self.name_servers = validate.name_servers(data)

    def set_name_servers_search(self, data):
        """
        Set the DNS search paths.

        @param: str/list data (string or list of search domains)
        @returns: True or CX
        """
        self.name_servers_search = validate.name_servers_search(data)

    def set_netmask(self, netmask, interface):
        """
        Set the netmask for given interface.

        @param: str netmask (netmask)
        @param: str interface (interface name)
        @returns: True or CX
        """
        intf = self.__get_interface(interface)
        intf["netmask"] = validate.ipv4_netmask(netmask)

    def set_if_gateway(self, gateway, interface):
        """
        Set the per-interface gateway.

        @param: str gateway (ipv4 address for the gateway)
        @param: str interface (interface name)
        @returns: True or CX
        """
        intf = self.__get_interface(interface)
        intf["if_gateway"] = validate.ipv4_address(gateway)

# --

    def set_virt_bridge(self, bridge, interface):
        if bridge == "":
            bridge = self.settings.default_virt_bridge
        intf = self.__get_interface(interface)
        intf["virt_bridge"] = bridge

    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

    def set_interface_master(self, interface_master, interface):
        intf = self.__get_interface(interface)
        intf["interface_master"] = interface_master

    def set_bonding_opts(self, bonding_opts, interface):
        intf = self.__get_interface(interface)
        intf["bonding_opts"] = bonding_opts

    def set_bridge_opts(self, bridge_opts, interface):
        intf = self.__get_interface(interface)
        intf["bridge_opts"] = bridge_opts

    def set_ipv6_autoconfiguration(self, truthiness):
        self.ipv6_autoconfiguration = utils.input_boolean(truthiness)

    def set_ipv6_default_device(self, interface_name):
        if interface_name is None:
            interface_name = ""
        self.ipv6_default_device = interface_name

    def set_ipv6_address(self, address, interface):
        """
        Set IPv6 address on interface.

        @param: str address (ip address)
        @param: str interface (interface name)
        @returns: True or CX
        """
        address = validate.ipv6_address(address)
        if address != "" and utils.input_boolean(
                self.collection_mgr._settings.allow_duplicate_ips) is False:
            matched = self.collection_mgr.api.find_items(
                "system", {"ipv6_address": address})
            for x in matched:
                if x.name != self.name:
                    raise CX("IP address duplicated: %s" % address)

        intf = self.__get_interface(interface)
        intf["ipv6_address"] = address

    def set_ipv6_prefix(self, prefix, interface):
        """
        Assign a IPv6 prefix
        """
        intf = self.__get_interface(interface)
        intf["ipv6_prefix"] = prefix.strip()

    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

    def set_ipv6_default_gateway(self, address, interface):
        intf = self.__get_interface(interface)
        if address == "" or utils.is_ip(address):
            intf["ipv6_default_gateway"] = address.strip()
            return
        raise CX(_("invalid format for IPv6 IP address (%s)") % address)

    def set_ipv6_static_routes(self, routes, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(routes)
        intf["ipv6_static_routes"] = data

    def set_ipv6_mtu(self, mtu, interface):
        intf = self.__get_interface(interface)
        intf["ipv6_mtu"] = mtu

    def set_mtu(self, mtu, interface):
        intf = self.__get_interface(interface)
        intf["mtu"] = mtu

    def set_connected_mode(self, truthiness, interface):
        intf = self.__get_interface(interface)
        intf["connected_mode"] = utils.input_boolean(truthiness)

    def set_enable_gpxe(self, enable_gpxe):
        """
        Sets whether or not the system will use gPXE for booting.
        """
        self.enable_gpxe = utils.input_boolean(enable_gpxe)

    def set_profile(self, profile_name):
        """
        Set the system to use a certain named profile. The profile
        must have already been loaded into the Profiles collection.
        """
        old_parent = self.get_parent()
        if profile_name in ["delete", "None", "~", ""] or profile_name is None:
            self.profile = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return

        self.image = ""  # mutual exclusion rule

        p = self.collection_mgr.profiles().find(name=profile_name)
        if p is not None:
            self.profile = profile_name
            self.depth = p.depth + 1  # subprofiles have varying depths.
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return
        raise CX(_("invalid profile name: %s") % profile_name)

    def set_image(self, image_name):
        """
        Set the system to use a certain named image.  Works like set_profile
        but cannot be used at the same time.  It's one or the other.
        """
        old_parent = self.get_parent()
        if image_name in ["delete", "None", "~", ""] or image_name is None:
            self.image = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return

        self.profile = ""  # mutual exclusion rule

        img = self.collection_mgr.images().find(name=image_name)

        if img is not None:
            self.image = image_name
            self.depth = img.depth + 1
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return
        raise CX(_("invalid image name (%s)") % image_name)

    def set_virt_cpus(self, num):
        return utils.set_virt_cpus(self, num)

    def set_virt_file_size(self, num):
        return utils.set_virt_file_size(self, num)

    def set_virt_disk_driver(self, driver):
        return utils.set_virt_disk_driver(self, driver)

    def set_virt_auto_boot(self, num):
        return utils.set_virt_auto_boot(self, num)

    def set_virt_pxe_boot(self, num):
        return utils.set_virt_pxe_boot(self, num)

    def set_virt_ram(self, num):
        return utils.set_virt_ram(self, num)

    def set_virt_type(self, vtype):
        return utils.set_virt_type(self, vtype)

    def set_virt_path(self, path):
        return utils.set_virt_path(self, path, for_system=True)

    def set_netboot_enabled(self, netboot_enabled):
        """
        If true, allows per-system PXE files to be generated on sync (or add).  If false,
        these files are not generated, thus eliminating the potential for an infinite install
        loop when systems are set to PXE boot first in the boot order.  In general, users
        who are PXE booting first in the boot order won't create system definitions, so this
        feature primarily comes into play for programmatic users of the API, who want to
        initially create a system with netboot enabled and then disable it after the system installs,
        as triggered by some action in automatic installation file's  %post section.
        For this reason, this option is not urfaced in the CLI, output, or documentation (yet).

        Use of this option does not affect the ability to use PXE menus.  If an admin has machines
        set up to PXE only after local boot fails, this option isn't even relevant.
        """
        self.netboot_enabled = utils.input_boolean(netboot_enabled)

    def set_autoinstall(self, autoinstall):
        """
        Set the automatic installation template filepath, this must be a local file.

        @param str local automatic installation template file path
        """

        autoinstall_mgr = autoinstall_manager.AutoInstallationManager(
            self.collection_mgr)
        self.autoinstall = autoinstall_mgr.validate_autoinstall_template_file_path(
            autoinstall)

    def set_power_type(self, power_type):
        if power_type is None:
            power_type = ""
        power_manager.validate_power_type(power_type)
        self.power_type = power_type

    def set_power_user(self, power_user):
        if power_user is None:
            power_user = ""
        utils.safe_filter(power_user)
        self.power_user = power_user

    def set_power_pass(self, power_pass):
        if power_pass is None:
            power_pass = ""
        utils.safe_filter(power_pass)
        self.power_pass = power_pass

    def set_power_address(self, power_address):
        if power_address is None:
            power_address = ""
        utils.safe_filter(power_address)
        self.power_address = power_address

    def set_power_id(self, power_id):
        if power_id is None:
            power_id = ""
        utils.safe_filter(power_id)
        self.power_id = power_id

    def modify_interface(self, _dict):
        """
        Used by the WUI to modify an interface more-efficiently
        """

        for (key, value) in list(_dict.items()):
            (field, interface) = key.split("-", 1)
            field = field.replace("_", "").replace("-", "")

            if field == "bondingopts":
                self.set_bonding_opts(value, interface)

            if field == "bridgeopts":
                self.set_bridge_opts(value, interface)

            if field == "connected_mode":
                self.set_connected_mode(value, interface)

            if field == "cnames":
                self.set_cnames(value, interface)

            if field == "dhcptag":
                self.set_dhcp_tag(value, interface)

            if field == "dnsname":
                self.set_dns_name(value, interface)

            if field == "ifgateway":
                self.set_if_gateway(value, interface)

            if field == "interfacetype":
                self.set_interface_type(value, interface)

            if field == "interfacemaster":
                self.set_interface_master(value, interface)

            if field == "ipaddress":
                self.set_ip_address(value, interface)

            if field == "ipv6address":
                self.set_ipv6_address(value, interface)

            if field == "ipv6defaultgateway":
                self.set_ipv6_default_gateway(value, interface)

            if field == "ipv6mtu":
                self.set_ipv6_mtu(value, interface)

            if field == "ipv6prefix":
                self.set_ipv6_prefix(value, interface)

            if field == "ipv6secondaries":
                self.set_ipv6_secondaries(value, interface)

            if field == "ipv6staticroutes":
                self.set_ipv6_static_routes(value, interface)

            if field == "macaddress":
                self.set_mac_address(value, interface)

            if field == "management":
                self.set_management(value, interface)

            if field == "mtu":
                self.set_mtu(value, interface)

            if field == "netmask":
                self.set_netmask(value, interface)

            if field == "static":
                self.set_static(value, interface)

            if field == "staticroutes":
                self.set_static_routes(value, interface)

            if field == "virtbridge":
                self.set_virt_bridge(value, interface)

    def set_repos_enabled(self, repos_enabled):
        self.repos_enabled = utils.input_boolean(repos_enabled)

    def set_serial_device(self, device_number):
        return utils.set_serial_device(self, device_number)

    def set_serial_baud_rate(self, baud_rate):
        return utils.set_serial_baud_rate(self, baud_rate)

    def get_config_filename(self, interface, loader=None):
        """
        The configuration file for each system pxe uses is either
        a form of the MAC address of the hex version of the IP.  If none
        of that is available, just use the given name, though the name
        given will be unsuitable for PXE configuration (For this, check
        system.is_management_supported()). This same file is used to store
        system config information in the Apache tree, so it's still relevant.

        :param loader: Bootloader type.
        :type loader: str
        :param interface: Name of the interface.
        :type interface: str
        """

        if loader is None:
            loader = self.boot_loader

        if interface not in self.interfaces:
            return None

        if self.name == "default":
            if loader == "grub":
                return None
            return "default"

        mac = self.get_mac_address(interface)
        ip = self.get_ip_address(interface)
        if mac is not None and mac != "":
            if loader == "grub":
                return mac.lower()
            else:
                return "01-" + "-".join(mac.split(":")).lower()
        elif ip is not None and ip != "":
            return utils.get_host_ip(ip)
        else:
            return self.name
Exemplo n.º 43
0
 def to_string(self):
     buf = ""
     buf += _("defaults\n")
     buf += _("kernel options  : %s\n") % self.__dict__['kernel_options']
     return buf
Exemplo n.º 44
0
class Distro(item.Item):
    """
    A cobbler distribution object
    """

    TYPE_NAME = _("distro")
    COLLECTION_TYPE = "distro"

    def __init__(self, *args, **kwargs):
        super(Distro, self).__init__(*args, **kwargs)
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.ks_meta = {}
        self.source_repos = []
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):

        _dict = self.to_dict()
        cloned = Distro(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned


    def get_fields(self):
        """
        Return the list of fields and their properties
        """
        return FIELDS


    def get_parent(self):
        """
        Distros don't have parent objects.
        """
        return None


    def check_if_valid(self):
        if self.name is None:
            raise CX("name is required")
        if self.kernel is None:
            raise CX("Error with distro %s - kernel is required" % (self.name))
        if self.initrd is None:
            raise CX("Error with distro %s - initrd is required" % (self.name))

        if utils.file_is_remote(self.kernel):
            if not utils.remote_file_exists(self.kernel):
                raise CX("Error with distro %s - kernel '%s' not found" % (self.name, self.kernel))
        elif not os.path.exists(self.kernel):
            raise CX("Error with distro %s - kernel not found" % (self.name))

        if utils.file_is_remote(self.initrd):
            if not utils.remote_file_exists(self.initrd):
                raise CX("Error with distro %s - initrd path not found" % (self.name))
        elif not os.path.exists(self.initrd):
            raise CX("Error with distro %s - initrd path not found" % (self.name))


    #
    # specific methods for item.Distro
    #

    def set_kernel(self, kernel):
        """
        Specifies a kernel.  The kernel parameter is a full path, a filename
        in the configured kernel directory (set in /etc/cobbler.conf) or a
        directory path that would contain a selectable kernel.  Kernel
        naming conventions are checked, see docs in the utils module
        for find_kernel.
        """
        if kernel is None or kernel == "":
            raise CX("kernel not specified")
        if utils.find_kernel(kernel):
            self.kernel = kernel
            return
        raise CX("kernel not found: %s" % kernel)


    def set_tree_build_time(self, datestamp):
        """
        Sets the import time of the distro.
        If not imported, this field is not meaningful.
        """
        self.tree_build_time = float(datestamp)


    def set_breed(self, breed):
        return utils.set_breed(self, breed)


    def set_os_version(self, os_version):
        return utils.set_os_version(self, os_version)


    def set_initrd(self, initrd):
        """
        Specifies an initrd image.  Path search works as in set_kernel.
        File must be named appropriately.
        """
        if initrd is None or initrd == "":
            raise CX("initrd not specified")
        if utils.find_initrd(initrd):
            self.initrd = initrd
            return
        raise CX(_("initrd not found"))


    def set_source_repos(self, repos):
        """
        A list of http:// URLs on the cobbler server that point to
        yum configuration files that can be used to
        install core packages.  Use by cobbler import only.
        """
        self.source_repos = repos


    def set_arch(self, arch):
        """
        The field is mainly relevant to PXE provisioning.

        Using an alternative distro type allows for dhcpd.conf templating
        to "do the right thing" with those systems -- this also relates to
        bootloader configuration files which have different syntax for different
        distro types (because of the bootloaders).

        This field is named "arch" because mainly on Linux, we only care about
        the architecture, though if (in the future) new provisioning types
        are added, an arch value might be something like "bsd_x86".

        """
        return utils.set_arch(self, arch)
Exemplo n.º 45
0
class Repo(item.Item):
    """
    A Cobbler repo object.
    """

    TYPE_NAME = _("repo")
    COLLECTION_TYPE = "repo"

    def __init__(self, *args, **kwargs):
        super(Repo, self).__init__(*args, **kwargs)
        self.breed = None
        self.arch = None
        self.environment = {}
        self.yumopts = {}
        self.rsyncopts = {}

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):
        """
        Clone this file object. Please manually adjust all value yourself to make the cloned object unique.

        :return: The cloned instance of this object.
        """
        _dict = self.to_dict()
        cloned = Repo(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        """
        Return all fields which this class has with its current values.

        :return: This is a list with lists.
        """
        return FIELDS

    def get_parent(self):
        """
        Currently the Cobbler object space does not support subobjects of this object as it is conceptually not useful.
        """
        return None

    def check_if_valid(self):
        """
        Checks if the object is valid. Currently checks for name and mirror to be present.
        """
        if self.name is None:
            raise CX("name is required")
        if self.mirror is None:
            raise CX("Error with repo %s - mirror is required" % (self.name))

    #
    # specific methods for item.File
    #

    def _guess_breed(self):
        """
        Guess the breed of a mirror.
        """
        # backwards compatibility
        if not self.breed:
            if self.mirror.startswith("http://") or self.mirror.startswith("https://") or self.mirror.startswith("ftp://"):
                self.set_breed("yum")
            elif self.mirror.startswith("rhn://"):
                self.set_breed("rhn")
            else:
                self.set_breed("rsync")

    def set_mirror(self, mirror):
        """
        A repo is (initially, as in right now) is something that can be rsynced.
        reposync/repotrack integration over HTTP might come later.

        :param mirror: The mirror URI.
        """
        self.mirror = mirror
        if not self.arch:
            if mirror.find("x86_64") != -1:
                self.set_arch("x86_64")
            elif mirror.find("x86") != -1 or mirror.find("i386") != -1:
                self.set_arch("i386")
        self._guess_breed()

    def set_keep_updated(self, keep_updated):
        """
        This allows the user to disable updates to a particular repo for whatever reason.

        :param keep_updated: This may be a bool-like value if the repository shall be keept up to date or not.
        """
        self.keep_updated = utils.input_boolean(keep_updated)

    def set_yumopts(self, options):
        """
        Kernel options are a space delimited list.

        :param options: Something like 'a=b c=d e=f g h i=j' or a dictionary.
        """
        (success, value) = utils.input_string_or_dict(options, allow_multiples=False)
        if not success:
            raise CX(_("invalid yum options"))
        else:
            self.yumopts = value

    def set_rsyncopts(self, options):
        """
        rsync options are a space delimited list

        :param options: Something like '-a -S -H -v'
        """
        (success, value) = utils.input_string_or_dict(options, allow_multiples=False)
        if not success:
            raise CX(_("invalid rsync options"))
        else:
            self.rsyncopts = value

    def set_environment(self, options):
        """
        Yum can take options from the environment. This puts them there before each reposync.

        :param options: These are environment variables which are set before each reposync.
        """
        (success, value) = utils.input_string_or_dict(options, allow_multiples=False)
        if not success:
            raise CX(_("invalid environment options"))
        else:
            self.environment = value

    def set_priority(self, priority):
        """
        Set the priority of the repository. Only works if host is using priorities plugin for yum.

        :param priority: Must be a value between 1 and 99. 1 is the highest whereas 99 is the default and lowest.
        """
        try:
            priority = int(str(priority))
        except:
            raise CX(_("invalid priority level: %s") % priority)
        self.priority = priority

    def set_rpm_list(self, rpms):
        """
        Rather than mirroring the entire contents of a repository (Fedora Extras, for instance, contains games, and we
        probably don't want those), make it possible to list the packages one wants out of those repos, so only those
        packages and deps can be mirrored.

        :param rpms: The rpm to mirror. This may be a string or list.
        """
        self.rpm_list = utils.input_string_or_list(rpms)

    def set_createrepo_flags(self, createrepo_flags):
        """
        Flags passed to createrepo when it is called. Common flags to use would be ``-c cache`` or ``-g comps.xml`` to
        generate group information.

        :param createrepo_flags: The createrepo flags which are passed additionally to the default ones.
        """
        if createrepo_flags is None:
            createrepo_flags = ""
        self.createrepo_flags = createrepo_flags

    def set_breed(self, breed):
        """
        Setter for the operating system breed.

        :param breed: The new breed to set. If this argument evaluates to false then nothing will be done.
        """
        if breed:
            return utils.set_repo_breed(self, breed)

    def set_os_version(self, os_version):
        """
        Setter for the operating system version.

        :param os_version: The new operating system version. If this argument evaluates to false then nothing will be
                           done.
        """
        if os_version:
            return utils.set_repo_os_version(self, os_version)

    def set_arch(self, arch):
        """
        Override the arch used for reposync

        :param arch: The new arch which will be used.
        """
        return utils.set_arch(self, arch, repo=True)

    def set_mirror_locally(self, value):
        """
        Setter for the local mirror property.

        :param value: The new value for ``mirror_locally``.
        """
        self.mirror_locally = utils.input_boolean(value)

    def set_apt_components(self, value):
        """
        Setter for the apt command property.

        :param value: The new value for ``apt_components``.
        """
        self.apt_components = utils.input_string_or_list(value)

    def set_apt_dists(self, value):
        """
        Setter for the apt dists.

        :param value: The new value for ``apt_dists``.
        :return: ``True`` if everything went correctly.
        """
        self.apt_dists = utils.input_string_or_list(value)
        return True

    def set_proxy(self, value):
        """
        Setter for the proxy setting of the repository.

        :param value: The new proxy which will be used for the repository.
        :return: ``True`` if this succeeds.
        """
        self.proxy = value
        return True
Exemplo n.º 46
0
    def write_dhcp_file(self):
        """
        DHCP files are written when manage_dhcp is set in
        /etc/cobbler/settings.
        """

        template_file = "/etc/cobbler/dhcp.template"
        blender_cache = {}

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error reading template: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        # use a simple counter for generating generic names where a hostname
        # is not available
        counter = 0

        # we used to just loop through each system, but now we must loop
        # through each network interface of each system.
        dhcp_tags = {"default": {}}
        yaboot = "/yaboot"

        # FIXME: ding should evolve into the new dhcp_tags dict
        ding = {}
        ignore_macs = []

        for system in self.systems:
            if not system.is_management_supported(cidr_ok=False):
                continue

            profile = system.get_conceptual_parent()
            distro = profile.get_conceptual_parent()

            # if distro is None then the profile is really an image record
            for (name, system_interface) in list(system.interfaces.items()):

                # We make a copy because we may modify it before adding it to the dhcp_tags
                # and we don't want to affect the master copy.
                interface = copy.deepcopy(system_interface)

                if interface["if_gateway"]:
                    interface["gateway"] = interface["if_gateway"]
                else:
                    interface["gateway"] = system.gateway

                mac = interface["mac_address"]

                if interface["interface_type"] in ("bond_slave",
                                                   "bridge_slave",
                                                   "bonded_bridge_slave"):

                    if interface["interface_master"] not in system.interfaces:
                        # Can't write DHCP entry; master interface does not exist
                        continue

                    # We may have multiple bonded interfaces, so we need a composite index into ding.
                    name_master = "%s-%s" % (system.name,
                                             interface["interface_master"])
                    if name_master not in ding:
                        ding[name_master] = {interface["interface_master"]: []}

                    if len(ding[name_master][
                            interface["interface_master"]]) == 0:
                        ding[name_master][
                            interface["interface_master"]].append(mac)
                    else:
                        ignore_macs.append(mac)

                    ip = system.interfaces[
                        interface["interface_master"]]["ip_address"]
                    netmask = system.interfaces[
                        interface["interface_master"]]["netmask"]
                    dhcp_tag = system.interfaces[
                        interface["interface_master"]]["dhcp_tag"]
                    host = system.interfaces[
                        interface["interface_master"]]["dns_name"]

                    if ip is None or ip == "":
                        for (nam2, int2) in list(system.interfaces.items()):
                            if (nam2.startswith(interface["interface_master"] +
                                                ".")
                                    and int2["ip_address"] is not None
                                    and int2["ip_address"] != ""):
                                ip = int2["ip_address"]
                                break

                    interface["ip_address"] = ip
                    interface["netmask"] = netmask
                else:
                    ip = interface["ip_address"]
                    netmask = interface["netmask"]
                    dhcp_tag = interface["dhcp_tag"]
                    host = interface["dns_name"]

                if distro is not None:
                    interface["distro"] = distro.to_dict()

                if mac is None or mac == "":
                    # can't write a DHCP entry for this system
                    continue

                counter = counter + 1

                # the label the entry after the hostname if possible
                if host is not None and host != "":
                    if name != "eth0":
                        interface["name"] = "%s-%s" % (host, name)
                    else:
                        interface["name"] = "%s" % (host)
                else:
                    interface["name"] = "generic%d" % counter

                # add references to the system, profile, and distro
                # for use in the template
                if system.name in blender_cache:
                    blended_system = blender_cache[system.name]
                else:
                    blended_system = utils.blender(self.api, False, system)
                    blender_cache[system.name] = blended_system

                interface["next_server"] = blended_system["next_server"]
                interface["netboot_enabled"] = blended_system[
                    "netboot_enabled"]
                interface["hostname"] = blended_system["hostname"]
                interface["owner"] = blended_system["name"]
                interface["enable_gpxe"] = blended_system["enable_gpxe"]
                interface["name_servers"] = blended_system["name_servers"]
                interface["mgmt_parameters"] = blended_system[
                    "mgmt_parameters"]

                # Explicitly declare filename for other (non x86) archs as in DHCP discover
                # package mostly the architecture cannot be differed due to missing bits...
                if distro is not None and not interface.get("filename"):
                    if distro.arch == "ppc" or distro.arch == "ppc64":
                        interface["filename"] = yaboot
                    elif distro.arch == "ppc64le":
                        interface["filename"] = "grub/grub.ppc64le"
                    elif distro.arch == "aarch64":
                        interface["filename"] = "grub/grubaa64.efi"

                if not self.settings.always_write_dhcp_entries:
                    if not interface["netboot_enabled"] and interface['static']:
                        continue

                if dhcp_tag == "":
                    dhcp_tag = blended_system.get("dhcp_tag", "")
                    if dhcp_tag == "":
                        dhcp_tag = "default"

                if dhcp_tag not in dhcp_tags:
                    dhcp_tags[dhcp_tag] = {mac: interface}
                else:
                    dhcp_tags[dhcp_tag][mac] = interface

        # remove macs from redundant slave interfaces from dhcp_tags
        # otherwise you get duplicate ip's in the installer
        for dt in list(dhcp_tags.keys()):
            for m in list(dhcp_tags[dt].keys()):
                if m in ignore_macs:
                    del dhcp_tags[dt][m]

        # we are now done with the looping through each interface of each system
        metadata = {
            "date":
            time.asctime(time.gmtime()),
            "cobbler_server":
            "%s:%s" % (self.settings.server, self.settings.http_port),
            "next_server":
            self.settings.next_server,
            "yaboot":
            yaboot,
            "dhcp_tags":
            dhcp_tags
        }

        if self.logger is not None:
            self.logger.info("generating %s" % self.settings_file)
        self.templar.render(template_data, metadata, self.settings_file, None)
Exemplo n.º 47
0
class Repo(item.Item):
    """
    A Cobbler repo object.
    """

    TYPE_NAME = _("repo")
    COLLECTION_TYPE = "repo"

    def __init__(self, *args, **kwargs):
        super(Repo, self).__init__(*args, **kwargs)
        self.breed = None
        self.arch = None
        self.environment = None
        self.yumopts = None

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):

        _dict = self.to_dict()
        cloned = Repo(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        return FIELDS

    def get_parent(self):
        """
        currently the Cobbler object space does not support subobjects of this object
        as it is conceptually not useful.
        """
        return None

    def check_if_valid(self):
        if self.name is None:
            raise CX("name is required")
        if self.mirror is None:
            raise CX("Error with repo %s - mirror is required" % (self.name))

    #
    # specific methods for item.File
    #

    def _guess_breed(self):
        # backwards compatibility
        if (self.breed == "" or self.breed is None):
            if self.mirror.startswith("http://") or self.mirror.startswith(
                    "ftp://"):
                self.set_breed("yum")
            elif self.mirror.startswith("rhn://"):
                self.set_breed("rhn")
            else:
                self.set_breed("rsync")

    def set_mirror(self, mirror):
        """
        A repo is (initially, as in right now) is something that can be rsynced.
        reposync/repotrack integration over HTTP might come later.
        """
        self.mirror = mirror
        if self.arch is None or self.arch == "":
            if mirror.find("x86_64") != -1:
                self.set_arch("x86_64")
            elif mirror.find("x86") != -1 or mirror.find("i386") != -1:
                self.set_arch("i386")
        self._guess_breed()

    def set_keep_updated(self, keep_updated):
        """
        This allows the user to disable updates to a particular repo for whatever reason.
        """
        self.keep_updated = utils.input_boolean(keep_updated)

    def set_yumopts(self, options):
        """
        Kernel options are a space delimited list,
        like 'a=b c=d e=f g h i=j' or a dictionary.
        """
        (success, value) = utils.input_string_or_dict(options,
                                                      allow_multiples=False)
        if not success:
            raise CX(_("invalid yum options"))
        else:
            self.yumopts = value

    def set_environment(self, options):
        """
        Yum can take options from the environment.  This puts them there before
        each reposync.
        """
        (success, value) = utils.input_string_or_dict(options,
                                                      allow_multiples=False)
        if not success:
            raise CX(_("invalid environment options"))
        else:
            self.environment = value

    def set_priority(self, priority):
        """
        Set the priority of the repository.  1= highest, 99=default
        Only works if host is using priorities plugin for yum.
        """
        try:
            priority = int(str(priority))
        except:
            raise CX(_("invalid priority level: %s") % priority)
        self.priority = priority

    def set_rpm_list(self, rpms):
        """
        Rather than mirroring the entire contents of a repository (Fedora Extras, for instance,
        contains games, and we probably don't want those), make it possible to list the packages
        one wants out of those repos, so only those packages + deps can be mirrored.
        """
        self.rpm_list = utils.input_string_or_list(rpms)

    def set_createrepo_flags(self, createrepo_flags):
        """
        Flags passed to createrepo when it is called.  Common flags to use would be
        -c cache or -g comps.xml to generate group information.
        """
        if createrepo_flags is None:
            createrepo_flags = ""
        self.createrepo_flags = createrepo_flags

    def set_breed(self, breed):
        if breed:
            return utils.set_repo_breed(self, breed)

    def set_os_version(self, os_version):
        if os_version:
            return utils.set_repo_os_version(self, os_version)

    def set_arch(self, arch):
        """
        Override the arch used for reposync
        """
        return utils.set_arch(self, arch, repo=True)

    def set_mirror_locally(self, value):
        self.mirror_locally = utils.input_boolean(value)

    def set_apt_components(self, value):
        self.apt_components = utils.input_string_or_list(value)

    def set_apt_dists(self, value):
        self.apt_dists = utils.input_string_or_list(value)
Exemplo n.º 48
0
 def set_boot_loader(self, name):
     if name not in utils.get_supported_system_boot_loaders():
         raise CX(_("Invalid boot loader name: %s" % name))
     self.boot_loader = name
Exemplo n.º 49
0
class Mgmtclass(item.Item):

    TYPE_NAME = _("mgmtclass")
    COLLECTION_TYPE = "mgmtclass"

    def __init__(self, *args, **kwargs):
        super(Mgmtclass, self).__init__(*args, **kwargs)
        self.params = {}

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):
        """
        Clone this file object. Please manually adjust all value yourself to make the cloned object unique.

        :return: The cloned instance of this object.
        """

        _dict = self.to_dict()
        cloned = Mgmtclass(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        """
        Return all fields which this class has with it's current values.

        :return: This is a list with lists.
        """
        return FIELDS

    def check_if_valid(self):
        """
        Check if this object is in a valid state. This currently checks only if the name is present.
        """
        if not self.name:
            raise CX("name is required")

    #
    # specific methods for item.Mgmtclass
    #

    def set_packages(self, packages):
        """
        Setter for the packages of the managementclass.

        :param packages: A string or list which contains the new packages.
        """
        self.packages = utils.input_string_or_list(packages)

    def set_files(self, files):
        """
        Setter for the files of the object.

        :param files: A string or list which contains the new files.
        """
        self.files = utils.input_string_or_list(files)

    def set_params(self, params):
        """
        Setter for the params of the managementclass.

        :param params: The new params for the object.
        """
        (success, value) = utils.input_string_or_dict(params,
                                                      allow_multiples=True)
        if not success:
            raise CX(_("invalid parameters"))
        else:
            self.params = value

    def set_is_definition(self, isdef):
        """
        Setter for property ``is_defintion``.

        :param isdef: The new value for the property.
        """
        self.is_definition = utils.input_boolean(isdef)

    def set_class_name(self, name):
        """
        Setter for the name of the managementclass.

        :param name: The new name of the class. This must not contain "_", "-", ".", ":" or "+".
        :type name: str
        """
        if not isinstance(name, str) and not isinstance(name, oldstr):
            raise CX(_("class name must be a string"))
        for x in name:
            if not x.isalnum() and x not in ["_", "-", ".", ":", "+"]:
                raise CX(_("invalid characters in class name: '%s'" % name))
        self.class_name = name
Exemplo n.º 50
0
class System(item.Item):
    """
    A Cobbler system object.
    """

    TYPE_NAME = _("system")
    COLLECTION_TYPE = "system"

    def __init__(self, *args, **kwargs):
        super(System, self).__init__(*args, **kwargs)
        self.interfaces = dict()
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.ks_meta = {}
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}


    #
    # override some base class methods first (item.Item)
    #

    def get_fields(self):
        return FIELDS


    def make_clone(self):
        ds = self.to_datastruct()
        cloned = System(self.config)
        cloned.from_datastruct(ds)
        return cloned


    def from_datastruct(self, seed_data):
        # FIXME: most definitely doesn't grok interfaces yet.
        return utils.from_datastruct_from_fields(self, seed_data, FIELDS)


    def get_parent(self):
        """
        Return object next highest up the tree.
        """
        if (self.parent is None or self.parent == '') and self.profile:
            return self.config.profiles().find(name=self.profile)
        elif (self.parent is None or self.parent == '') and self.image:
            return self.config.images().find(name=self.image)
        else:
            return self.config.systems().find(name=self.parent)


    def check_if_valid(self):
        if self.name is None or self.name == "":
            raise CX("name is required")
        if self.profile is None or self.profile == "":
            if self.image is None or self.image == "":
                raise CX("Error with system %s - profile or image is required" % (self.name))


    #
    # specific methods for item.Distro
    #

    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]


    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


    def rename_interface(self, names):
        """
        Used to rename an interface.
        """
        (name, newname) = names
        if name not in self.interfaces:
            raise CX(_("Interface %s does not exist" % name))
        if newname in self.interfaces:
            raise CX(_("Interface %s already exists" % newname))
        else:
            self.interfaces[newname] = self.interfaces[name]
            del self.interfaces[name]

        return True


    def set_redhat_management_key(self, key):
        return utils.set_redhat_management_key(self, key)


    def set_redhat_management_server(self, server):
        return utils.set_redhat_management_server(self, server)


    def set_server(self, server):
        """
        If a system can't reach the boot server at the value configured in settings
        because it doesn't have the same name on it's subnet this is there for an override.
        """
        if server is None or server == "":
            server = "<<inherit>>"
        self.server = server
        return True


    def set_proxy(self, proxy):
        if proxy is None or proxy == "":
            proxy = "<<inherit>>"
        self.proxy = proxy
        return True


    def get_mac_address(self, interface):
        """
        Get the mac address, which may be implicit in the object name or explicit with --mac-address.
        Use the explicit location first.
        """

        intf = self.__get_interface(interface)

        if intf["mac_address"] != "":
            return intf["mac_address"].strip()
        else:
            return None


    def get_ip_address(self, interface):
        """
        Get the IP address, which may be implicit in the object name or explict with --ip-address.
        Use the explicit location first.
        """

        intf = self.__get_interface(interface)

        if intf["ip_address"] != "":
            return intf["ip_address"].strip()
        else:
            return ""


    def is_management_supported(self, cidr_ok=True):
        """
        Can only add system PXE records if a MAC or IP address is available, else it's a koan
        only record.
        """
        if self.name == "default":
            return True
        for (name, x) in self.interfaces.iteritems():
            mac = x.get("mac_address", None)
            ip = x.get("ip_address", None)
            if ip is not None and not cidr_ok and ip.find("/") != -1:
                # ip is in CIDR notation
                return False
            if mac is not None or ip is not None:
                # has ip and/or mac
                return True
        return False


    def set_dhcp_tag(self, dhcp_tag, interface):
        intf = self.__get_interface(interface)
        intf["dhcp_tag"] = dhcp_tag
        return True


    def set_dns_name(self, dns_name, interface):
        """
        Set DNS name for interface.

        @param: str dns_name (dns name)
        @param: str interface (interface name)
        @returns: True or CX
        """
        dns_name = validate.hostname(dns_name)
        if dns_name != "" and utils.input_boolean(self.config._settings.allow_duplicate_hostnames) is False:
            matched = self.config.api.find_items("system", {"dns_name": dns_name})
            for x in matched:
                if x.name != self.name:
                    raise CX("DNS name duplicated: %s" % dns_name)

        intf = self.__get_interface(interface)
        intf["dns_name"] = dns_name
        return True


    def set_cnames(self, cnames, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(cnames)
        intf["cnames"] = data
        return True


    def set_static_routes(self, routes, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(routes)
        intf["static_routes"] = data
        return True


    def set_hostname(self, hostname):
        """
        Set hostname.

        @param: str hostname (hostname for system)
        @returns: True or CX
        """
        self.hostname = validate.hostname(hostname)
        return True


    def set_status(self, status):
        self.status = status
        return True


    def set_static(self, truthiness, interface):
        intf = self.__get_interface(interface)
        intf["static"] = utils.input_boolean(truthiness)
        return True


    def set_management(self, truthiness, interface):
        intf = self.__get_interface(interface)
        intf["management"] = utils.input_boolean(truthiness)
        return True


    def set_ip_address(self, address, interface):
        """
        Set IPv4 address on interface.

        @param: str address (ip address)
        @param: str interface (interface name)
        @returns: True or CX
        """
        address = validate.ipv4_address(address)
        if address != "" and utils.input_boolean(self.config._settings.allow_duplicate_ips) is False:
            matched = self.config.api.find_items("system", {"ip_address": address})
            for x in matched:
                if x.name != self.name:
                    raise CX("IP address duplicated: %s" % address)

        intf = self.__get_interface(interface)
        intf["ip_address"] = address
        return True


    def set_mac_address(self, address, interface):
        """
        Set mc address on interface.

        @param: str address (mac address)
        @param: str interface (interface name)
        @returns: True or CX
        """
        address = validate.mac_address(address)
        if address == "random":
            address = utils.get_random_mac(self.config.api)
        if address != "" and utils.input_boolean(self.config._settings.allow_duplicate_macs) is False:
            matched = self.config.api.find_items("system", {"mac_address": address})
            for x in matched:
                if x.name != self.name:
                    raise CX("MAC address duplicated: %s" % address)

        intf = self.__get_interface(interface)
        intf["mac_address"] = address.strip()
        return True


    def set_gateway(self, gateway):
        """
        Set a gateway IPv4 address.

        @param: str gateway (ip address)
        @returns: True or CX
        """
        self.gateway = validate.ipv4_address(gateway)
        return True


    def set_name_servers(self, data):
        """
        Set the DNS servers.

        @param: str/list data (string or list of nameservers)
        @returns: True or CX
        """
        self.name_servers = validate.name_servers(data)
        return True


    def set_name_servers_search(self, data):
        """
        Set the DNS search paths.

        @param: str/list data (string or list of search domains)
        @returns: True or CX
        """
        self.name_servers_search = validate.name_servers_search(data)
        return True


    def set_netmask(self, netmask, interface):
        intf = self.__get_interface(interface)
        intf["netmask"] = netmask
        return True


    def set_if_gateway(self, gateway, interface):
        intf = self.__get_interface(interface)
        if gateway == "" or utils.is_ip(gateway):
            intf["if_gateway"] = gateway
            return True
        raise CX(_("invalid gateway: %s" % gateway))


    def set_virt_bridge(self, bridge, interface):
        if bridge == "":
            bridge = self.settings.default_virt_bridge
        intf = self.__get_interface(interface)
        intf["virt_bridge"] = bridge
        return True


    def set_interface_type(self, type, interface):
        interface_types = ["bridge", "bridge_slave", "bond", "bond_slave", "bonded_bridge_slave", "na", ""]
        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
        return True


    def set_interface_master(self, interface_master, interface):
        intf = self.__get_interface(interface)
        intf["interface_master"] = interface_master
        return True


    def set_bonding_opts(self, bonding_opts, interface):
        intf = self.__get_interface(interface)
        intf["bonding_opts"] = bonding_opts
        return True


    def set_bridge_opts(self, bridge_opts, interface):
        intf = self.__get_interface(interface)
        intf["bridge_opts"] = bridge_opts
        return True


    def set_ipv6_autoconfiguration(self, truthiness):
        self.ipv6_autoconfiguration = utils.input_boolean(truthiness)
        return True


    def set_ipv6_default_device(self, interface_name):
        if interface_name is None:
            interface_name = ""
        self.ipv6_default_device = interface_name
        return True


    def set_ipv6_address(self, address, interface):
        """
        Assign a IP or hostname in DHCP when this MAC boots.
        Only works if manage_dhcp is set in /etc/cobbler/settings
        """
        intf = self.__get_interface(interface)
        if address == "" or utils.is_ip(address):
            intf["ipv6_address"] = address.strip()
            return True
        raise CX(_("invalid format for IPv6 IP address (%s)") % address)


    def set_ipv6_prefix(self, prefix, interface):
        """
        Assign a IPv6 prefix
        """
        intf = self.__get_interface(interface)
        intf["ipv6_prefix"] = prefix.strip()
        return True


    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


    def set_ipv6_default_gateway(self, address, interface):
        intf = self.__get_interface(interface)
        if address == "" or utils.is_ip(address):
            intf["ipv6_default_gateway"] = address.strip()
            return True
        raise CX(_("invalid format for IPv6 IP address (%s)") % address)


    def set_ipv6_static_routes(self, routes, interface):
        intf = self.__get_interface(interface)
        data = utils.input_string_or_list(routes)
        intf["ipv6_static_routes"] = data
        return True


    def set_ipv6_mtu(self, mtu, interface):
        intf = self.__get_interface(interface)
        intf["ipv6_mtu"] = mtu
        return True


    def set_mtu(self, mtu, interface):
        intf = self.__get_interface(interface)
        intf["mtu"] = mtu
        return True


    def set_enable_gpxe(self, enable_gpxe):
        """
        Sets whether or not the system will use gPXE for booting.
        """
        self.enable_gpxe = utils.input_boolean(enable_gpxe)
        return True


    def set_profile(self, profile_name):
        """
        Set the system to use a certain named profile. The profile
        must have already been loaded into the Profiles collection.
        """
        old_parent = self.get_parent()
        if profile_name in ["delete", "None", "~", ""] or profile_name is None:
            self.profile = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return True

        self.image = ""         # mutual exclusion rule

        p = self.config.profiles().find(name=profile_name)
        if p is not None:
            self.profile = profile_name
            self.depth = p.depth + 1            # subprofiles have varying depths.
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return True
        raise CX(_("invalid profile name: %s") % profile_name)


    def set_image(self, image_name):
        """
        Set the system to use a certain named image.  Works like set_profile
        but cannot be used at the same time.  It's one or the other.
        """
        old_parent = self.get_parent()
        if image_name in ["delete", "None", "~", ""] or image_name is None:
            self.image = ""
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            return True

        self.profile = ""       # mutual exclusion rule

        img = self.config.images().find(name=image_name)

        if img is not None:
            self.image = image_name
            self.depth = img.depth + 1
            if isinstance(old_parent, item.Item):
                old_parent.children.pop(self.name, 'pass')
            new_parent = self.get_parent()
            if isinstance(new_parent, item.Item):
                new_parent.children[self.name] = self
            return True
        raise CX(_("invalid image name (%s)") % image_name)


    def set_virt_cpus(self, num):
        return utils.set_virt_cpus(self, num)


    def set_virt_file_size(self, num):
        return utils.set_virt_file_size(self, num)


    def set_virt_disk_driver(self, driver):
        return utils.set_virt_disk_driver(self, driver)


    def set_virt_auto_boot(self, num):
        return utils.set_virt_auto_boot(self, num)

    def set_virt_pxe_boot(self, num):
        return utils.set_virt_pxe_boot(self, num)


    def set_virt_ram(self, num):
        return utils.set_virt_ram(self, num)


    def set_virt_type(self, vtype):
        return utils.set_virt_type(self, vtype)


    def set_virt_path(self, path):
        return utils.set_virt_path(self, path, for_system=True)


    def set_netboot_enabled(self, netboot_enabled):
        """
        If true, allows per-system PXE files to be generated on sync (or add).  If false,
        these files are not generated, thus eliminating the potential for an infinite install
        loop when systems are set to PXE boot first in the boot order.  In general, users
        who are PXE booting first in the boot order won't create system definitions, so this
        feature primarily comes into play for programmatic users of the API, who want to
        initially create a system with netboot enabled and then disable it after the system installs,
        as triggered by some action in kickstart %post.   For this reason, this option is not
        surfaced in the CLI, output, or documentation (yet).

        Use of this option does not affect the ability to use PXE menus.  If an admin has machines
        set up to PXE only after local boot fails, this option isn't even relevant.
        """
        self.netboot_enabled = utils.input_boolean(netboot_enabled)
        return True


    def set_kickstart(self, kickstart):
        """
        Set the kickstart path, this must be a local file.

        @param: str kickstart path to a local kickstart file
        @returns: True or CX
        """
        self.kickstart = validate.kickstart_file_path(kickstart)
        return True


    def set_power_type(self, power_type):
        # FIXME: modularize this better
        if power_type is None:
            power_type = ""
        choices = utils.get_power_types()
        if not choices:
            raise CX("you need to have fence-agents installed")
        if power_type not in choices:
            raise CX("power management type must be one of: %s" % ",".join(choices))
        self.power_type = power_type
        return True


    def set_power_user(self, power_user):
        if power_user is None:
            power_user = ""
        utils.safe_filter(power_user)
        self.power_user = power_user
        return True


    def set_power_pass(self, power_pass):
        if power_pass is None:
            power_pass = ""
        utils.safe_filter(power_pass)
        self.power_pass = power_pass
        return True


    def set_power_address(self, power_address):
        if power_address is None:
            power_address = ""
        utils.safe_filter(power_address)
        self.power_address = power_address
        return True


    def set_power_id(self, power_id):
        if power_id is None:
            power_id = ""
        utils.safe_filter(power_id)
        self.power_id = power_id
        return True


    def modify_interface(self, hash):
        """
        Used by the WUI to modify an interface more-efficiently
        """
        for (key, value) in hash.iteritems():
            (field, interface) = key.split("-", 1)
            field = field.replace("_", "").replace("-", "")

            if field == "macaddress":
                self.set_mac_address(value, interface)

            if field == "mtu":
                self.set_mtu(value, interface)

            if field == "ipaddress":
                self.set_ip_address(value, interface)

            if field == "dnsname":
                self.set_dns_name(value, interface)

            if field == "static":
                self.set_static(value, interface)

            if field == "dhcptag":
                self.set_dhcp_tag(value, interface)

            if field == "netmask":
                self.set_netmask(value, interface)

            if field == "ifgateway":
                self.set_if_gateway(value, interface)

            if field == "virtbridge":
                self.set_virt_bridge(value, interface)

            if field == "interfacetype":
                self.set_interface_type(value, interface)

            if field == "interfacemaster":
                self.set_interface_master(value, interface)

            if field == "bondingopts":
                self.set_bonding_opts(value, interface)

            if field == "bridgeopts":
                self.set_bridge_opts(value, interface)

            if field == "management":
                self.set_management(value, interface)

            if field == "staticroutes":
                self.set_static_routes(value, interface)

            if field == "ipv6address":
                self.set_ipv6_address(value, interface)

            if field == "ipv6prefix":
                self.set_ipv6_prefix(value, interface)

            if field == "ipv6secondaries":
                self.set_ipv6_secondaries(value, interface)

            if field == "ipv6mtu":
                self.set_ipv6_mtu(value, interface)

            if field == "ipv6staticroutes":
                self.set_ipv6_static_routes(value, interface)

            if field == "ipv6defaultgateway":
                self.set_ipv6_default_gateway(value, interface)

            if field == "cnames":
                self.set_cnames(value, interface)

        return True


    def set_monit_enabled(self, monit_enabled):
        """
        If true, allows per-system to start Monit to monitor system services such as apache.
        If monit is not running it will start the service.

        If false, no management of monit will take place. If monit is not running it will not
        be started. If monit is running it will not be stopped or restarted.
        """
        self.monit_enabled = utils.input_boolean(monit_enabled)
        return True


    def set_ldap_enabled(self, ldap_enabled):
        self.ldap_enabled = utils.input_boolean(ldap_enabled)
        return True


    def set_repos_enabled(self, repos_enabled):
        self.repos_enabled = utils.input_boolean(repos_enabled)
        return True


    def set_ldap_type(self, ldap_type):
        if ldap_type is None:
            ldap_type = ""
        ldap_type = ldap_type.lower()
        self.ldap_type = ldap_type
        return True
Exemplo n.º 51
0
class Image(item.Item):
    """
    A Cobbler Image.  Tracks a virtual or physical image, as opposed to a answer
    file (autoinst) led installation.
    """

    TYPE_NAME = _("image")
    COLLECTION_TYPE = "image"

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):

        _dict = self.to_dict()
        cloned = Image(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        return FIELDS

    def get_parent(self):
        """
        Images have no parent object.
        """
        return None

    #
    # specific methods for item.Image
    #

    def set_arch(self, arch):
        """
        The field is mainly relevant to PXE provisioning.
        see comments for set_arch in item_distro.py, this works the same.
        """
        return utils.set_arch(self, arch)

    def set_autoinstall(self, autoinstall):
        """
        Set the automatic installation file path, this must be a local file.

        It may not make sense for images to have automatic installation templates.
        It really doesn't. However if the image type is 'iso' koan can create a virtual
        floppy and shove an answer file on it, to script an installation.  This may
        not be a automatic installation template per se, it might be a Windows answer
        file (SIF) etc.

        @param str local automatic installation template file path
        """

        autoinstall_mgr = autoinstall_manager.AutoInstallationManager(self.collection_mgr)
        self.autoinstall = autoinstall_mgr.validate_autoinstall_template_file_path(autoinstall)

    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

    def set_os_version(self, os_version):
        return utils.set_os_version(self, os_version)

    def set_breed(self, breed):
        return utils.set_breed(self, breed)

    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

    def set_virt_cpus(self, num):
        return utils.set_virt_cpus(self, num)

    def set_network_count(self, num):
        if num is None or num == "":
            num = 1
        try:
            self.network_count = int(num)
        except:
            raise CX("invalid network count (%s)" % num)

    def set_virt_auto_boot(self, num):
        return utils.set_virt_auto_boot(self, num)

    def set_virt_file_size(self, num):
        return utils.set_virt_file_size(self, num)

    def set_virt_disk_driver(self, driver):
        return utils.set_virt_disk_driver(self, driver)

    def set_virt_ram(self, num):
        return utils.set_virt_ram(self, num)

    def set_virt_type(self, vtype):
        return utils.set_virt_type(self, vtype)

    def set_virt_bridge(self, vbridge):
        return utils.set_virt_bridge(self, vbridge)

    def set_virt_path(self, path):
        return utils.set_virt_path(self, path)

    def get_valid_image_types(self):
        return ["direct", "iso", "memdisk", "virt-clone"]
Exemplo n.º 52
0
 def set_if_gateway(self, gateway, interface):
     intf = self.__get_interface(interface)
     if gateway == "" or utils.is_ip(gateway):
         intf["if_gateway"] = gateway
         return True
     raise CX(_("invalid gateway: %s" % gateway))
Exemplo n.º 53
0
class Profile(item.Item):
    """
    A Cobbler profile object.
    """

    TYPE_NAME = _("profile")
    COLLECTION_TYPE = "profile"

    def __init__(self, *args, **kwargs):
        super(Profile, self).__init__(*args, **kwargs)
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.autoinstall_meta = {}
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):
        """
        Clone this file object. Please manually adjust all value yourself to make the cloned object unique.

        :return: The cloned instance of this object.
        """
        _dict = self.to_dict()
        cloned = Profile(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        """
        Return all fields which this class has with its current values.

        :return: This is a list with lists.
        """
        return FIELDS

    def get_parent(self):
        """
        Return object next highest up the tree.
        """
        if not self.parent:
            if self.distro is None:
                return None
            result = self.collection_mgr.distros().find(name=self.distro)
        else:
            result = self.collection_mgr.profiles().find(name=self.parent)
        return result

    def check_if_valid(self):
        """
        Check if the profile is valid. This checks for an existing name and a distro as a conceptual parent.
        """
        # name validation
        if not self.name:
            raise CX("Name is required")

        # distro validation
        distro = self.get_conceptual_parent()
        if distro is None:
            raise CX("Error with profile %s - distro is required" %
                     (self.name))

    #
    # specific methods for item.Profile
    #

    def set_parent(self, parent_name):
        """
        Instead of a ``--distro``, set the parent of this object to another profile and use the values from the parent
        instead of this one where the values for this profile aren't filled in, and blend them together where they
        are dictionaries. Basically this enables profile inheritance. To use this, the object MUST have been
        constructed with ``is_subobject=True`` or the default values for everything will be screwed up and this will
        likely NOT work. So, API users -- make sure you pass ``is_subobject=True`` into the constructor when using this.

        :param parent_name: The name of the parent object.
        """
        old_parent = self.get_parent()
        if isinstance(old_parent, item.Item):
            old_parent.children.pop(self.name, 'pass')
        if not parent_name:
            self.parent = ''
            return
        if parent_name == self.name:
            # check must be done in two places as set_parent could be called before/after
            # set_name...
            raise CX(_("self parentage is weird"))
        found = self.collection_mgr.profiles().find(name=parent_name)
        if found is None:
            raise CX(
                _("profile %s not found, inheritance not possible") %
                parent_name)
        self.parent = parent_name
        self.depth = found.depth + 1
        parent = self.get_parent()
        if isinstance(parent, item.Item):
            parent.children[self.name] = self

    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"))

    def set_name_servers(self, data):
        """
        Set the DNS servers.

        :param data: string or list of nameservers
        :returns: True or throws exception
        :raises CX: If the nameservers are not valid.
        """
        self.name_servers = validate.name_servers(data)

    def set_name_servers_search(self, data):
        """
        Set the DNS search paths.

        :param data: string or list of search domains
        :returns: True or throws exception
        :raises CX: If the search domains are not valid.
        """
        self.name_servers_search = validate.name_servers_search(data)

    def set_proxy(self, proxy):
        """
        Setter for the proxy.

        :param proxy: The new proxy for the profile.
        """
        self.proxy = proxy

    def set_enable_gpxe(self, enable_gpxe):
        """
        Sets whether or not the profile will use gPXE for booting.

        :param enable_gpxe: New boolean value for enabling gPXE.
        """
        self.enable_gpxe = utils.input_boolean(enable_gpxe)

    def set_enable_menu(self, enable_menu):
        """
        Sets whether or not the profile will be listed in the default PXE boot menu. This is pretty forgiving for
        YAML's sake.

        :param enable_menu: New boolean value for enabling the menu.
        """
        self.enable_menu = utils.input_boolean(enable_menu)

    def set_dhcp_tag(self, dhcp_tag):
        """
        Setter for the dhcp tag property.

        :param dhcp_tag:
        """
        if dhcp_tag is None:
            dhcp_tag = ""
        self.dhcp_tag = dhcp_tag

    def set_server(self, server):
        """
        Setter for the server property.

        :param server: If this is None or an emtpy string this will be reset to be inherited from the parent object.
        """
        if server in [None, ""]:
            server = "<<inherit>>"
        self.server = server

    def set_next_server(self, server):
        """
        Setter for the next server value.

        :param server: If this is None or an emtpy string this will be reset to be inherited from the parent object.
        """
        if server in [None, ""]:
            self.next_server = "<<inherit>>"
        else:
            server = server.strip()
            if server != "<<inherit>>":
                self.next_server = validate.ipv4_address(server)
            else:
                self.next_server = server

    def set_filename(self, filename):
        if not filename:
            self.filename = "<<inherit>>"
        else:
            self.filename = filename.strip()

    def set_autoinstall(self, autoinstall):
        """
        Set the automatic OS installation template file path, this must be a local file.

        :param autoinstall: local automatic installation template path
        :type autoinstall: str
        """

        autoinstall_mgr = autoinstall_manager.AutoInstallationManager(
            self.collection_mgr)
        self.autoinstall = autoinstall_mgr.validate_autoinstall_template_file_path(
            autoinstall)

    def set_virt_auto_boot(self, num):
        """
        Setter for booting a virtual machine automatically.

        :param num: The new value for whether to enable it or not.
        """
        utils.set_virt_auto_boot(self, num)

    def set_virt_cpus(self, num):
        """
        Setter for the number of virtual CPU cores to assign to the virtual machine.

        :param num: The number of cpu cores.
        """
        utils.set_virt_cpus(self, num)

    def set_virt_file_size(self, num):
        """
        Setter for the size of the virtual image size.

        :param num: The new size of the image.
        """
        utils.set_virt_file_size(self, num)

    def set_virt_disk_driver(self, driver):
        """
        Setter for the virtual disk driver that will be used.

        :param driver: The new driver.
        """
        utils.set_virt_disk_driver(self, driver)

    def set_virt_ram(self, num):
        """
        Setter for the virtual RAM used for the VM.

        :param num: The number of RAM to use for the VM.
        """
        utils.set_virt_ram(self, num)

    def set_virt_type(self, vtype):
        """
        Setter for the virtual machine type.

        :param vtype: May be on out of "qemu", "kvm", "xenpv", "xenfv", "vmware", "vmwarew", "openvz" or "auto".
        """
        utils.set_virt_type(self, vtype)

    def set_virt_bridge(self, vbridge):
        """
        Setter for the name of the virtual bridge to use.

        :param vbridge: The name of the virtual bridge to use.
        """
        utils.set_virt_bridge(self, vbridge)

    def set_virt_path(self, path):
        """
        Setter of the path to the place where the image will be stored.

        :param path: The path to where the image will be stored.
        """
        utils.set_virt_path(self, path)

    def set_repos(self, repos, bypass_check=False):
        """
        Setter of the repositories for the profile.

        :param repos: The new repositories which will be set.
        :param bypass_check: If repository checks should be checked or not.
        """
        utils.set_repos(self, repos, bypass_check)

    def set_redhat_management_key(self, management_key):
        """
        Setter of the redhat management key.

        :param management_key: The value may be reset by setting it to None.
        """
        if not management_key:
            self.redhat_management_key = "<<inherit>>"
        self.redhat_management_key = management_key

    def get_redhat_management_key(self):
        """
        Getter of the redhat management key of the profile or it's parent.

        :return: Returns the redhat_management_key of the profile.
        """
        return self.redhat_management_key

    def get_arch(self):
        """
        Getter of the architecture of the profile or the parent.

        :return: The architecture.
        """
        parent = self.get_parent()
        if parent:
            return parent.get_arch()
        return None
Exemplo n.º 54
0
 def set_params(self, params):
     (success, value) = utils.input_string_or_dict(params, allow_multiples=True)
     if not success:
         raise CX(_("invalid parameters"))
     else:
         self.params = value
Exemplo n.º 55
0
    def add(self, ref, save=False, with_copy=False, with_triggers=True, with_sync=True, quick_pxe_update=False,
            check_for_duplicate_names=False, check_for_duplicate_netinfo=False, logger=None):
        """
        Add an object to the collection, if it's valid.  Returns True
        if the object was added to the collection.  Returns False if the
        object specified by ref deems itself invalid (and therefore
        won't be added to the collection).

        with_copy is a bit of a misnomer, but lots of internal add operations
        can run with "with_copy" as False. True means a real final commit, as if
        entered from the command line (or basically, by a user).

        With with_copy as False, the particular add call might just be being run
        during deserialization, in which case extra semantics around the add don't really apply.
        So, in that case, don't run any triggers and don't deal with any actual files.
        """
        if ref is None or ref.name is None:
            return False

        try:
            ref.check_if_valid()
        except CX:
            return False

        if ref.uid == '':
            ref.uid = self.config.generate_uid()

        if save is True:
            now = time.time()
            if ref.ctime == 0:
                ref.ctime = now
            ref.mtime = now

        if self.lite_sync is None:
            self.lite_sync = action_litesync.BootLiteSync(self.config, logger=logger)

        # migration path for old API parameter that I've renamed.
        if with_copy and not save:
            save = with_copy

        if not save:
            # for people that aren't quite aware of the API
            # if not saving the object, you can't run these features
            with_triggers = False
            with_sync = False

        # Avoid adding objects to the collection
        # if an object of the same/ip/mac already exists.
        self.__duplication_checks(ref, check_for_duplicate_names, check_for_duplicate_netinfo)

        if ref.COLLECTION_TYPE != self.collection_type():
            raise CX(_("API error: storing wrong data type in collection"))

        if not save:
            # don't need to run triggers, so add it already ...
            self.lock.acquire()
            try:
                self.listing[ref.name.lower()] = ref
            finally:
                self.lock.release()

        # perform filesystem operations
        if save:
            # failure of a pre trigger will prevent the object from being added
            if with_triggers:
                utils.run_triggers(self.api, ref, "/var/lib/cobbler/triggers/add/%s/pre/*" % self.collection_type(), [], logger)
            self.lock.acquire()
            try:
                self.listing[ref.name.lower()] = ref
            finally:
                self.lock.release()

            # save just this item if possible, if not, save
            # the whole collection
            self.config.serialize_item(self, ref)

            if with_sync:
                if isinstance(ref, item_system.System):
                    # we don't need openvz containers to be network bootable
                    if ref.virt_type == "openvz":
                        ref.netboot_enabled = False
                    self.lite_sync.add_single_system(ref.name)
                elif isinstance(ref, item_profile.Profile):
                    # we don't need openvz containers to be network bootable
                    if ref.virt_type == "openvz":
                        ref.enable_menu = 0
                    self.lite_sync.add_single_profile(ref.name)
                elif isinstance(ref, item_distro.Distro):
                    self.lite_sync.add_single_distro(ref.name)
                elif isinstance(ref, item_image.Image):
                    self.lite_sync.add_single_image(ref.name)
                elif isinstance(ref, item_repo.Repo):
                    pass
                elif isinstance(ref, item_mgmtclass.Mgmtclass):
                    pass
                elif isinstance(ref, item_package.Package):
                    pass
                elif isinstance(ref, item_file.File):
                    pass
                else:
                    print _("Internal error. Object type not recognized: %s") % type(ref)
            if not with_sync and quick_pxe_update:
                if isinstance(ref, item_system.System):
                    self.lite_sync.update_system_netboot_status(ref.name)

            # save the tree, so if neccessary, scripts can examine it.
            if with_triggers:
                utils.run_triggers(self.api, ref, "/var/lib/cobbler/triggers/change/*", [], logger)
                utils.run_triggers(self.api, ref, "/var/lib/cobbler/triggers/add/%s/post/*" % self.collection_type(), [], logger)

        # update children cache in parent object
        parent = ref.get_parent()
        if parent is not None:
            parent.children[ref.name] = ref

        return True
Exemplo n.º 56
0
    def __write_secondary_conf(self):
        """
        Write out the secondary.conf secondary config file from the template.
        """
        settings_file = self.settings.bind_chroot_path + '/etc/secondary.conf'
        template_file = "/etc/cobbler/secondary.template"
        # forward_zones = self.settings.manage_forward_zones
        # reverse_zones = self.settings.manage_reverse_zones

        metadata = {
            'forward_zones': list(self.__forward_zones().keys()),
            'reverse_zones': [],
            'zone_include': ''
        }

        for zone in metadata['forward_zones']:
            txt = """
zone "%(zone)s." {
    type slave;
    masters {
        %(master)s;
    };
    file "data/%(zone)s";
};
""" % {
                'zone': zone,
                'master': self.settings.bind_master
            }
            metadata['zone_include'] = metadata['zone_include'] + txt

        for zone in list(self.__reverse_zones().keys()):
            # IPv6 zones are : delimited
            if ":" in zone:
                # if IPv6, assume xxxx:xxxx:xxxx:xxxx for the zone
                #                 0123456789012345678
                long_zone = (self.__expand_IPv6(zone + '::1'))[:19]
                tokens = list(re.sub(':', '', long_zone))
                tokens.reverse()
                arpa = '.'.join(tokens) + '.ip6.arpa'
            else:
                # IPv4 zones split by '.'
                tokens = zone.split('.')
                tokens.reverse()
                arpa = '.'.join(tokens) + '.in-addr.arpa'
                #
            metadata['reverse_zones'].append((zone, arpa))
            txt = """
zone "%(arpa)s." {
    type slave;
    masters {
        %(master)s;
    };
    file "data/%(zone)s";
};
""" % {
                'arpa': arpa,
                'zone': zone,
                'master': self.settings.bind_master
            }
            metadata['zone_include'] = metadata['zone_include'] + txt
            metadata['bind_master'] = self.settings.bind_master

        try:
            f2 = open(template_file, "r")
        except:
            raise CX(_("error reading template from file: %s") % template_file)
        template_data = ""
        template_data = f2.read()
        f2.close()

        if self.logger is not None:
            self.logger.info("generating %s" % settings_file)
        self.templar.render(template_data, metadata, settings_file, None)
Exemplo n.º 57
0
 def check_for_default_password(self, status):
     default_pass = self.settings.default_password_crypted
     if default_pass == "$1$mF86/UHC$WvcIcX2t6crBz2onWxyac.":
         status.append(
             _("The default password used by the sample templates for newly installed machines (default_password_crypted in /etc/cobbler/settings) is still set to 'cobbler' and should be changed, try: \"openssl passwd -1 -salt 'random-phrase-here' 'your-password-here'\" to generate new one"
               ))
Exemplo n.º 58
0
    def remove(self,
               name,
               with_delete=True,
               with_sync=True,
               with_triggers=True,
               recursive=True,
               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()

        # first see if any Groups use this distro
        if not recursive:
            for v in self.collection_mgr.systems():
                if v.image is not None and v.image.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:
                    self.collection_mgr.api.remove_system(k,
                                                          recursive=True,
                                                          logger=logger)

            if with_delete:
                if with_triggers:
                    utils.run_triggers(
                        self.collection_mgr.api, obj,
                        "/var/lib/cobbler/triggers/delete/image/pre/*", [],
                        logger)
                if with_sync:
                    lite_sync = action_litesync.CobblerLiteSync(
                        self.collection_mgr, logger=logger)
                    lite_sync.remove_single_image(name)

            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/image/post/*", [],
                        logger)
                    utils.run_triggers(self.collection_mgr.api, obj,
                                       "/var/lib/cobbler/triggers/change/*",
                                       [], logger)

            return

        raise CX(_("cannot delete an object that does not exist: %s") % name)
Exemplo n.º 59
0
    def __write_zone_files(self):
        """
        Write out the forward and reverse zone files for all configured zones
        """
        default_template_file = "/etc/cobbler/zone.template"
        cobbler_server = self.settings.server
        # this could be a config option too
        serial_filename = "/var/lib/cobbler/bind_serial"
        # need a counter for new bind format
        serial = time.strftime("%Y%m%d00")
        try:
            serialfd = open(serial_filename, "r")
            old_serial = serialfd.readline()
            # same date
            if serial[0:8] == old_serial[0:8]:
                if int(old_serial[8:10]) < 99:
                    serial = "%s%.2i" % (serial[0:8],
                                         int(old_serial[8:10]) + 1)
            else:
                pass
            serialfd.close()
        except:
            pass

        serialfd = open(serial_filename, "w")
        serialfd.write(serial)
        serialfd.close()

        forward = self.__forward_zones()
        reverse = self.__reverse_zones()

        try:
            f2 = open(default_template_file, "r")
        except:
            raise CX(
                _("error reading template from file: %s") %
                default_template_file)
        default_template_data = ""
        default_template_data = f2.read()
        f2.close()

        zonefileprefix = self.settings.bind_chroot_path + self.zonefile_base

        for (zone, hosts) in list(forward.items()):
            metadata = {
                'cobbler_server': cobbler_server,
                'serial': serial,
                'zonename': zone,
                'zonetype': 'forward',
                'cname_record': '',
                'host_record': ''
            }

            if ":" in zone:
                long_zone = (self.__expand_IPv6(zone + '::1'))[:19]
                tokens = list(re.sub(':', '', long_zone))
                tokens.reverse()
                zone_origin = '.'.join(tokens) + '.ip6.arpa.'
            else:
                zone_origin = ''
            # grab zone-specific template if it exists
            try:
                fd = open('/etc/cobbler/zone_templates/%s' % zone)
                # If this is an IPv6 zone, set the origin to the zone for this
                # template
                if zone_origin:
                    template_data = r"\$ORIGIN " + zone_origin + "\n" + fd.read(
                    )
                else:
                    template_data = fd.read()
                fd.close()
            except:
                # If this is an IPv6 zone, set the origin to the zone for this
                # template
                if zone_origin:
                    template_data = r"\$ORIGIN " + zone_origin + "\n" + default_template_data
                else:
                    template_data = default_template_data

            metadata['cname_record'] = self.__pretty_print_cname_records(hosts)
            metadata['host_record'] = self.__pretty_print_host_records(hosts)

            zonefilename = zonefileprefix + zone
            if self.logger is not None:
                self.logger.info("generating (forward) %s" % zonefilename)
            self.templar.render(template_data, metadata, zonefilename, None)

        for (zone, hosts) in list(reverse.items()):
            metadata = {
                'cobbler_server': cobbler_server,
                'serial': serial,
                'zonename': zone,
                'zonetype': 'reverse',
                'cname_record': '',
                'host_record': ''
            }

            # grab zone-specific template if it exists
            try:
                fd = open('/etc/cobbler/zone_templates/%s' % zone)
                template_data = fd.read()
                fd.close()
            except:
                template_data = default_template_data

            metadata['cname_record'] = self.__pretty_print_cname_records(hosts)
            metadata['host_record'] = self.__pretty_print_host_records(
                hosts, rectype='PTR')

            zonefilename = zonefileprefix + zone
            if self.logger is not None:
                self.logger.info("generating (reverse) %s" % zonefilename)
            self.templar.render(template_data, metadata, zonefilename, None)
Exemplo n.º 60
0
class Profile(item.Item):
    """
    A Cobbler profile object.
    """

    TYPE_NAME = _("profile")
    COLLECTION_TYPE = "profile"

    def __init__(self, *args, **kwargs):
        super(Profile, self).__init__(*args, **kwargs)
        self.kernel_options = {}
        self.kernel_options_post = {}
        self.autoinstall_meta = {}
        self.fetchable_files = {}
        self.boot_files = {}
        self.template_files = {}

    #
    # override some base class methods first (item.Item)
    #

    def make_clone(self):
        _dict = self.to_dict()
        cloned = Profile(self.collection_mgr)
        cloned.from_dict(_dict)
        return cloned

    def get_fields(self):
        """
        Return the list of fields and their properties
        """
        return FIELDS

    def get_parent(self):
        """
        Return object next highest up the tree.
        """
        if not self.parent:
            if self.distro is None:
                return None
            result = self.collection_mgr.distros().find(name=self.distro)
        else:
            result = self.collection_mgr.profiles().find(name=self.parent)
        return result

    def check_if_valid(self):
        # name validation
        if not self.name:
            raise CX("Name is required")

        # distro validation
        distro = self.get_conceptual_parent()
        if distro is None:
            raise CX("Error with profile %s - distro is required" %
                     (self.name))

    #
    # specific methods for item.Profile
    #

    def set_parent(self, parent_name):
        """
        Instead of a --distro, set the parent of this object to another profile
        and use the values from the parent instead of this one where the values
        for this profile aren't filled in, and blend them together where they
        are dictionaries.  Basically this enables profile inheritance.  To use this,
        the object MUST have been constructed with is_subobject=True or the
        default values for everything will be screwed up and this will likely NOT
        work.  So, API users -- make sure you pass is_subobject=True into the
        constructor when using this.
        """
        old_parent = self.get_parent()
        if isinstance(old_parent, item.Item):
            old_parent.children.pop(self.name, 'pass')
        if not parent_name:
            self.parent = ''
            return
        if parent_name == self.name:
            # check must be done in two places as set_parent could be called before/after
            # set_name...
            raise CX(_("self parentage is weird"))
        found = self.collection_mgr.profiles().find(name=parent_name)
        if found is None:
            raise CX(
                _("profile %s not found, inheritance not possible") %
                parent_name)
        self.parent = parent_name
        self.depth = found.depth + 1
        parent = self.get_parent()
        if isinstance(parent, item.Item):
            parent.children[self.name] = self

    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"))

    def set_name_servers(self, data):
        """
        Set the DNS servers.

        @param: str/list data (string or list of nameservers)
        @returns: True or CX
        """
        self.name_servers = validate.name_servers(data)

    def set_name_servers_search(self, data):
        """
        Set the DNS search paths.

        @param: str/list data (string or list of search domains)
        @returns: True or CX
        """
        self.name_servers_search = validate.name_servers_search(data)

    def set_proxy(self, proxy):
        self.proxy = proxy

    def set_enable_gpxe(self, enable_gpxe):
        """
        Sets whether or not the profile will use gPXE for booting.
        """
        self.enable_gpxe = utils.input_boolean(enable_gpxe)

    def set_enable_menu(self, enable_menu):
        """
        Sets whether or not the profile will be listed in the default
        PXE boot menu.  This is pretty forgiving for YAML's sake.
        """
        self.enable_menu = utils.input_boolean(enable_menu)

    def set_dhcp_tag(self, dhcp_tag):
        if dhcp_tag is None:
            dhcp_tag = ""
        self.dhcp_tag = dhcp_tag

    def set_server(self, server):
        if server in [None, ""]:
            server = "<<inherit>>"
        self.server = server

    def set_next_server(self, server):
        if server in [None, ""]:
            self.next_server = "<<inherit>>"
        else:
            server = server.strip()
            if server != "<<inherit>>":
                self.next_server = validate.ipv4_address(server)
            else:
                self.next_server = server

    def set_autoinstall(self, autoinstall):
        """
        Set the automatic OS installation template file path,
        this must be a local file.

        @param str local automatic installation template path
        """

        autoinstall_mgr = autoinstall_manager.AutoInstallationManager(
            self.collection_mgr)
        self.autoinstall = autoinstall_mgr.validate_autoinstall_template_file_path(
            autoinstall)

    def set_virt_auto_boot(self, num):
        utils.set_virt_auto_boot(self, num)

    def set_virt_cpus(self, num):
        utils.set_virt_cpus(self, num)

    def set_virt_file_size(self, num):
        utils.set_virt_file_size(self, num)

    def set_virt_disk_driver(self, driver):
        utils.set_virt_disk_driver(self, driver)

    def set_virt_ram(self, num):
        utils.set_virt_ram(self, num)

    def set_virt_type(self, vtype):
        utils.set_virt_type(self, vtype)

    def set_virt_bridge(self, vbridge):
        utils.set_virt_bridge(self, vbridge)

    def set_virt_path(self, path):
        utils.set_virt_path(self, path)

    def set_repos(self, repos, bypass_check=False):
        utils.set_repos(self, repos, bypass_check)

    def set_redhat_management_key(self, management_key):
        if not management_key:
            self.redhat_management_key = "<<inherit>>"
        self.redhat_management_key = management_key

    def get_redhat_management_key(self):
        return self.redhat_management_key