Esempio n. 1
0
def connect_to_server(server=None, port=None):

    if server is None:
        server = os.environ.get("COBBLER_SERVER", "")
    if server == "":
        raise InfoException("--server must be specified")

    try_urls = []
    if port is None:
        try_urls = [
            "https://%s:443/cobbler_api" % (server),
            "http://%s:80/cobbler_api" % (server),
        ]
    else:
        try_urls = [
            "https://%s:%s/cobbler_api" % (server, port),
            "http://%s:%s/cobbler_api" % (server, port),
        ]

    for url in try_urls:
        print("- looking for Cobbler at %s" % url)
        server = __try_connect(url)
        if server is not None:
            return server
    raise InfoException("Could not find Cobbler.")
Esempio n. 2
0
def create_qemu_image_file(path, size, driver_type):
    if driver_type not in VALID_DRIVER_TYPES:
        raise InfoException("Invalid QEMU image type: %s" % driver_type)

    cmd = ["qemu-img", "create", "-f", driver_type, path, "%sG" % size]
    try:
        subprocess_call(cmd)
    except:
        traceback.print_exc()
        raise InfoException("Image file create failed: %s" %
                            string.join(cmd, " "))
Esempio n. 3
0
def libvirt_enable_autostart(domain_name):
    import libvirt
    try:
        conn = libvirt.open("qemu:///system")
        conn.listDefinedDomains()
        domain = conn.lookupByName(domain_name)
        domain.setAutostart(1)
    except:
        raise InfoException("libvirt could not find domain %s" % domain_name)

    if not domain.autostart:
        raise InfoException("Could not enable autostart on domain %s." %
                            domain_name)
Esempio n. 4
0
def urlread(url):
    """
    to support more distributions, implement (roughly) some
    parts of urlread and urlgrab from urlgrabber, in ways that
    are less cool and less efficient.
    """
    print("- reading URL: %s" % url)
    if url is None or url == "":
        raise InfoException("invalid URL: %s" % url)

    elif url[0:3] == "nfs":
        try:
            ndir = os.path.dirname(url[6:])
            nfile = os.path.basename(url[6:])
            nfsdir = tempfile.mkdtemp(prefix="koan_nfs", dir="/tmp")
            nfsfile = os.path.join(nfsdir, nfile)
            cmd = ["mount", "-t", "nfs", "-o", "ro", ndir, nfsdir]
            subprocess_call(cmd)
            fd = open(nfsfile)
            data = fd.read()
            fd.close()
            cmd = ["umount", nfsdir]
            subprocess_call(cmd)
            return data
        except:
            traceback.print_exc()
            raise InfoException("Couldn't mount and read URL: %s" % url)

    elif url[0:4] == "http":
        try:
            fd = urllib2.urlopen(url)
            data = fd.read()
            fd.close()
            return data
        except:
            traceback.print_exc()
            raise InfoException("Couldn't download: %s" % url)
    elif url[0:4] == "file":
        try:
            fd = open(url[5:])
            data = fd.read()
            fd.close()
            return data
        except:
            raise InfoException("Couldn't read file from URL: %s" % url)

    else:
        raise InfoException("Unhandled URL protocol: %s" % url)
Esempio n. 5
0
def input_string_or_dict(options, delim=None, allow_multiples=True):
    """
    Older cobbler files stored configurations in a flat way, such that all values for strings.
    Newer versions of cobbler allow dictionaries.  This function is used to allow loading
    of older value formats so new users of cobbler aren't broken in an upgrade.
    """

    if options is None:
        return {}
    elif isinstance(options, list):
        raise InfoException("No idea what to do with list: %s" % options)
    elif isinstance(options, type("")):
        new_dict = {}
        tokens = string.split(options, delim)
        for t in tokens:
            tokens2 = string.split(t, "=")
            if len(tokens2) == 1:
                # this is a singleton option, no value
                key = tokens2[0]
                value = None
            else:
                key = tokens2[0]
                value = tokens2[1]

            # if we're allowing multiple values for the same key,
            # check to see if this token has already been
            # inserted into the dictionary of values already

            if key in new_dict.keys() and allow_multiples:
                # if so, check to see if there is already a list of values
                # otherwise convert the dictionary value to an array, and add
                # the new value to the end of the list
                if isinstance(new_dict[key], list):
                    new_dict[key].append(value)
                else:
                    new_dict[key] = [new_dict[key], value]
            else:
                new_dict[key] = value

        # dict.pop is not avail in 2.2
        if "" in new_dict:
            del new_dict[""]
        return new_dict
    elif isinstance(options, type({})):
        options.pop('', None)
        return options
    else:
        raise InfoException("invalid input type: %s" % type(options))
Esempio n. 6
0
def find_vm(conn, vmid):
    """
    Extra bonus feature: vmid = -1 returns a list of everything
    This function from Func:  fedorahosted.org/func
    """

    vms = []

    # this block of code borrowed from virt-manager:
    # get working domain's name
    ids = conn.listDomainsID()
    for id in ids:
        vm = conn.lookupByID(id)
        vms.append(vm)

    # get defined domain
    names = conn.listDefinedDomains()
    for name in names:
        vm = conn.lookupByName(name)
        vms.append(vm)

    if vmid == -1:
        return vms

    for vm in vms:
        if vm.name() == vmid:
            return vm

    raise InfoException("koan could not find the VM to watch: %s" % vmid)
Esempio n. 7
0
def start_install(name=None,
                  ram=None,
                  disks=None,
                  mac=None,
                  uuid=None,
                  extra=None,
                  vcpus=None,
                  profile_data=None,
                  arch=None,
                  no_gfx=False,
                  fullvirt=True,
                  bridge=None,
                  virt_type=None,
                  virt_auto_boot=False,
                  qemu_driver_type=None,
                  qemu_net_type=None):

    if "file" in profile_data:
        raise InfoException("vmware does not work with --image yet")

    mac = None
    if "interfaces" not in profile_data:
        print "- vmware installation requires a system, not a profile"
        return 1
    for iname in profile_data["interfaces"]:
        intf = profile_data["interfaces"][iname]
        mac = intf["mac_address"]
    if mac is None:
        print "- no MAC information available in this record, cannot install"
        return 1

    print "DEBUG: name=%s" % name
    print "DEBUG: ram=%s" % ram
    print "DEBUG: mac=%s" % mac
    print "DEBUG: disks=%s" % disks
    # starts vmware using PXE.  disk/mem info come from Cobbler
    # rest of the data comes from PXE which is also intended
    # to be managed by Cobbler.

    if not os.path.exists(IMAGE_DIR):
        os.makedirs(IMAGE_DIR)
    if not os.path.exists(VMX_DIR):
        os.makedirs(VMX_DIR)

    if len(disks) != 1:
        raise VirtCreateException(
            "vmware support is limited to 1 virtual disk")

    disksize = disks[0][1]

    image = "%s/%s" % (IMAGE_DIR, name)
    print "- saving virt disk image as %s" % image
    make_disk(disksize, image)
    vmx = "%s/%s" % (VMX_DIR, name)
    print "- saving vmx file as %s" % vmx
    make_vmx(vmx, image, name, mac, ram)
    register_vmx(vmx)
    start_vm(vmx)
Esempio n. 8
0
def subprocess_call(cmd, ignore_rc=0):
    """
    Wrapper around subprocess.call(...)
    """
    print("- %s" % cmd)
    rc = subprocess.call(cmd)
    if rc != 0 and not ignore_rc:
        raise InfoException("command failed (%s)" % rc)
    return rc
Esempio n. 9
0
def make_floppy(autoinst):

    (fd, floppy_path) = tempfile.mkstemp(suffix='.floppy',
                                         prefix='tmp',
                                         dir="/tmp")
    print("- creating floppy image at %s" % floppy_path)

    # create the floppy image file
    cmd = "dd if=/dev/zero of=%s bs=1440 count=1024" % floppy_path
    print("- %s" % cmd)
    rc = os.system(cmd)
    if not rc == 0:
        raise InfoException("dd failed")

    # vfatify
    cmd = "mkdosfs %s" % floppy_path
    print("- %s" % cmd)
    rc = os.system(cmd)
    if not rc == 0:
        raise InfoException("mkdosfs failed")

    # mount the floppy
    mount_path = tempfile.mkdtemp(suffix=".mnt", prefix='tmp', dir="/tmp")
    cmd = "mount -o loop -t vfat %s %s" % (floppy_path, mount_path)
    print("- %s" % cmd)
    rc = os.system(cmd)
    if not rc == 0:
        raise InfoException("mount failed")

    # download the autoinst file onto the mounted floppy
    print("- downloading %s" % autoinst)
    save_file = os.path.join(mount_path, "unattended.txt")
    urlgrabber.urlgrab(autoinst, filename=save_file)

    # umount
    cmd = "umount %s" % mount_path
    print("- %s" % cmd)
    rc = os.system(cmd)
    if not rc == 0:
        raise InfoException("umount failed")

    # return the path to the completed disk image to pass to virt-install
    return floppy_path
Esempio n. 10
0
def find_vm(conn, vmid):
    """
    Extra bonus feature: vmid = -1 returns a list of everything
    This function from Func:  fedorahosted.org/func
    """

    vms = get_vms(conn)
    for vm in vms:
        if vm.name() == vmid:
            return vm

    raise InfoException("koan could not find the VM to watch: %s" % vmid)
Esempio n. 11
0
def subprocess_get_response(cmd, ignore_rc=False):
    """
    Wrapper around subprocess.check_output(...)
    """
    print "- %s" % cmd
    rc = 0
    result = ""
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    result = p.communicate()[0]
    rc = p.wait()
    if not ignore_rc and rc != 0:
        raise InfoException("command failed (%s)" % rc)
    return rc, result
Esempio n. 12
0
def _sanitize_nics(nics, bridge, profile_bridge, network_count):
    ret = []

    if network_count is not None and not nics:
        # Fill in some stub nics so we can take advantage of the loop logic
        nics = {}
        for i in range(int(network_count)):
            nics["foo%s" % i] = {
                "interface_type": "na",
                "mac_address": None,
                "virt_bridge": None,
            }

    if not nics:
        return ret

    interfaces = sorted(nics.keys())
    counter = -1
    vlanpattern = re.compile("[a-zA-Z0-9]+\.[0-9]+")

    for iname in interfaces:
        counter = counter + 1
        intf = nics[iname]

        if (intf["interface_type"]
                in ("master", "bond", "bridge", "bonded_bridge_slave")
                or vlanpattern.match(iname) or iname.find(":") != -1):
            continue

        mac = intf["mac_address"]

        if not bridge:
            intf_bridge = intf["virt_bridge"]
            if intf_bridge == "":
                if profile_bridge == "":
                    raise InfoException(
                        "virt-bridge setting is not defined in cobbler")
                intf_bridge = profile_bridge

        else:
            if bridge.find(",") == -1:
                intf_bridge = bridge
            else:
                bridges = bridge.split(",")
                intf_bridge = bridges[counter]

        ret.append((intf_bridge, mac))

    return ret
Esempio n. 13
0
def _sanitize_disks(disks):
    ret = []
    for d in disks:
        driver_type = None
        if len(d) > 2:
            driver_type = d[2]

        if d[1] != 0 or d[0].startswith("/dev"):
            ret.append((d[0], d[1], driver_type))
        else:
            raise InfoException(
                "this virtualization type does not work without a disk image, set virt-size in Cobbler to non-zero"
            )

    return ret
Esempio n. 14
0
def nfsmount(input_path):
    # input:  [user@]server:/foo/bar/x.img as string
    # output:  (dirname where mounted, last part of filename) as 2-element tuple
    # FIXME: move this function to util.py so other modules can use it
    # we have to mount it first
    filename = input_path.split("/")[-1]
    dirpath = string.join(input_path.split("/")[:-1], "/")
    tempdir = tempfile.mkdtemp(suffix='.mnt', prefix='koan_', dir='/tmp')
    mount_cmd = ["/bin/mount", "-t", "nfs", "-o", "ro", dirpath, tempdir]
    print("- running: %s" % mount_cmd)
    rc = subprocess.call(mount_cmd)
    if not rc == 0:
        shutil.rmtree(tempdir, ignore_errors=True)
        raise InfoException("nfs mount failed: %s" % dirpath)
    # NOTE: option for a blocking install might be nice, so we could do this
    # automatically, if supported by virt-install
    print("after install completes, you may unmount and delete %s" % tempdir)
    return (tempdir, filename)
Esempio n. 15
0
def build_commandline(uri,
                      name=None,
                      ram=None,
                      disks=None,
                      uuid=None,
                      extra=None,
                      vcpus=None,
                      profile_data=None,
                      arch=None,
                      gfx_type=None,
                      fullvirt=False,
                      bridge=None,
                      virt_type=None,
                      virt_auto_boot=False,
                      virt_pxe_boot=False,
                      qemu_driver_type=None,
                      qemu_net_type=None,
                      qemu_machine_type=None,
                      wait=0,
                      noreboot=False,
                      osimport=False):

    # Set flags for CLI arguments based on the virtinst_version
    # tuple above. Older versions of python-virtinst don't have
    # a version easily accessible, so it will be None and we can
    # easily disable features based on that (RHEL5 and older usually)

    disable_autostart = False
    disable_virt_type = False
    disable_boot_opt = False
    disable_driver_type = False
    disable_net_model = False
    disable_machine_type = False
    oldstyle_macs = False
    oldstyle_accelerate = False

    if not virtinst_version:
        print("- warning: old virt-install detected, a lot of features will "
              "be disabled")
        disable_autostart = True
        disable_boot_opt = True
        disable_virt_type = True
        disable_driver_type = True
        disable_net_model = True
        disable_machine_type = True
        oldstyle_macs = True
        oldstyle_accelerate = True

    import_exists = False  # avoid duplicating --import parameter
    disable_extra = False  # disable --extra-args on --import
    if osimport:
        disable_extra = True

    is_import = uri.startswith("import")
    if is_import:
        # We use the special value 'import' for imagecreate.py. Since
        # it is connection agnostic, just let virt-install choose the
        # best hypervisor.
        uri = ""
        fullvirt = None

    is_xen = uri.startswith("xen")
    is_qemu = uri.startswith("qemu")
    if is_qemu:
        if virt_type != "kvm":
            fullvirt = True
        else:
            fullvirt = None
        # is libvirt new enough?
        if not utils.check_version_greater_or_equal(virtinst_version, "0.2.0"):
            raise InfoException(
                "need python-virtinst >= 0.2 or virt-install package to do installs for qemu/kvm (depending on your OS)"
            )

    floppy = None
    cdrom = None
    location = None
    importpath = None

    if is_import:
        importpath = profile_data.get("file")
        if not importpath:
            raise InfoException("Profile 'file' required for image install")

    elif "file" in profile_data:
        if is_xen:
            raise InfoException("Xen does not work with --image yet")

        # this is an image based installation
        input_path = profile_data["file"]
        print("- using image location %s" % input_path)
        if input_path.find(":") == -1:
            # this is not an NFS path
            cdrom = input_path
        else:
            (tempdir, filename) = utils.nfsmount(input_path)
            cdrom = os.path.join(tempdir, filename)

        autoinst = profile_data.get("autoinst", "")
        if autoinst != "":
            # we have a (windows?) answer file we have to provide
            # to the ISO.
            print("I want to make a floppy for %s" % autoinst)
            floppy = utils.make_floppy(autoinst)
    elif is_qemu or is_xen:
        # images don't need to source this
        if "install_tree" not in profile_data:
            raise InfoException(
                "Cannot find install source in autoinst file, aborting.")

        if not profile_data["install_tree"].endswith("/"):
            profile_data["install_tree"] = profile_data["install_tree"] + "/"

        location = profile_data["install_tree"]

    disks = _sanitize_disks(disks)
    nics = _sanitize_nics(profile_data.get("interfaces"), bridge,
                          profile_data.get("virt_bridge"),
                          profile_data.get("network_count"))
    if not nics:
        # for --profile you get one NIC, go define a system if you want more.
        # FIXME: can mac still be sent on command line in this case?

        if bridge is None:
            bridge = profile_data["virt_bridge"]

        if bridge == "":
            raise InfoException(
                "virt-bridge setting is not defined in cobbler")
        nics = [(bridge, None)]

    kernel = profile_data.get("kernel_local")
    initrd = profile_data.get("initrd_local")
    breed = profile_data.get("breed")
    os_version = profile_data.get("os_version")
    if os_version and breed == "ubuntu":
        os_version = "ubuntu%s" % os_version
    if os_version and breed == "debian":
        os_version = "debian%s" % os_version

    net_model = None
    disk_bus = None
    machine_type = None

    if is_qemu:
        net_model = qemu_net_type
        disk_bus = qemu_driver_type
        machine_type = qemu_machine_type

    if machine_type is None:
        machine_type = "pc"

    cmd = "virt-install "
    if uri:
        cmd += "--connect %s " % uri

    cmd += "--name %s " % name
    cmd += "--ram %s " % ram
    cmd += "--vcpus %s " % vcpus

    if uuid:
        cmd += "--uuid %s " % uuid

    if virt_auto_boot and not disable_autostart:
        cmd += "--autostart "

    if gfx_type is None:
        cmd += "--nographics "
    else:
        cmd += "--%s " % gfx_type

    if is_qemu and virt_type:
        if not disable_virt_type:
            cmd += "--virt-type %s " % virt_type

    if is_qemu and machine_type and not disable_machine_type:
        cmd += "--machine %s " % machine_type

    if fullvirt or is_qemu or is_import:
        if fullvirt is not None:
            cmd += "--hvm "
        elif oldstyle_accelerate:
            cmd += "--accelerate "

        if virt_pxe_boot or is_xen:
            cmd += "--pxe "
        elif cdrom:
            cmd += "--cdrom %s " % cdrom
        elif location:
            cmd += "--location %s " % location
            if is_qemu and extra and not (virt_pxe_boot) and not (
                    disable_extra):
                cmd += ("--extra-args=\"%s\" " % (extra))
        elif importpath:
            cmd += "--import "
            import_exists = True

        if arch:
            cmd += "--arch %s " % arch
    else:
        cmd += "--paravirt "
        if not disable_boot_opt:
            cmd += ("--boot kernel=%s,initrd=%s,kernel_args=\"%s\" " %
                    (kernel, initrd, extra))
        else:
            if location:
                cmd += "--location %s " % location
                if extra:
                    cmd += "--extra-args=\"%s\" " % extra

    if breed and breed != "other":
        if os_version and os_version != "other":
            if breed == "suse":
                suse_version_re = re.compile("^(opensuse[0-9]+)\.([0-9]+)$")
                if suse_version_re.match(os_version):
                    os_version = suse_version_re.match(os_version).groups()[0]
            # make sure virt-install knows about our os_version,
            # otherwise default it to virtio26 or generic26
            # found = False
            if os_version in supported_variants:
                pass  # os_version is correct
            elif os_version + ".0" in supported_variants:
                # osinfo based virt-install only knows about major.minor
                # variants, not just major variants like it used to. Default
                # to major.0 variant in that case. Lack of backwards
                # compatibility in virt-install grumble grumble.
                os_version = os_version + ".0"
            else:
                if "virtio26" in supported_variants:
                    os_version = "virtio26"
                else:
                    os_version = "generic26"
                print("- warning: virt-install doesn't know this os_version, "
                      "defaulting to %s" % os_version)
            cmd += "--os-variant %s " % os_version
        else:
            distro = "unix"
            if breed in ["debian", "suse", "redhat"]:
                distro = "linux"
            elif breed in ["windows"]:
                distro = "windows"

            cmd += "--os-type %s " % distro

    if importpath:
        # This needs to be the first disk for import to work
        cmd += "--disk path=%s " % importpath

    for path, size, driver_type in disks:
        print("- adding disk: %s of size %s (driver type=%s)" %
              (path, size, driver_type))
        cmd += "--disk path=%s" % (path)
        if str(size) != "0":
            cmd += ",size=%s" % size
        if disk_bus:
            cmd += ",bus=%s" % disk_bus
        if driver_type and not disable_driver_type:
            cmd += ",format=%s" % driver_type
        cmd += " "

    if floppy:
        cmd += "--disk path=%s,device=floppy " % floppy

    for bridge, mac in nics:
        cmd += "--network bridge=%s" % bridge
        if net_model and not disable_net_model:
            cmd += ",model=%s" % net_model
        if mac:
            if oldstyle_macs:
                cmd += " --mac=%s" % mac
            else:
                cmd += ",mac=%s" % mac
        cmd += " "

    cmd += "--wait %d " % int(wait)
    if noreboot:
        cmd += "--noreboot "
    if osimport and not (import_exists):
        cmd += "--import "
    cmd += "--noautoconsole "

    return shlex.split(cmd.strip())
Esempio n. 16
0
    def run(self):
        """
        Commence with the registration already.
        """

        # not really required, but probably best that ordinary users don't try
        # to run this not knowing what it does.
        if os.getuid() != 0:
            raise InfoException("root access is required to register")

        print("- preparing to koan home")
        self.conn = utils.connect_to_server(self.server, self.port)
        reg_info = {}
        print("- gathering network info")
        netinfo = utils.get_network_info()
        reg_info["interfaces"] = netinfo
        print("- checking hostname")
        sysname = ""
        if self.hostname != "" and self.hostname != "*AUTO*":
            hostname = self.hostname
            sysname = self.hostname
        else:
            hostname = socket.getfqdn()
            if hostname == "localhost.localdomain":
                if self.hostname == '*AUTO*':
                    hostname = ""
                    sysname = str(time.time())
                else:
                    raise InfoException(
                        "must specify --fqdn, could not discover")
            if sysname == "":
                sysname = hostname

        if self.profile == "":
            raise InfoException("must specify --profile")

        # we'll do a profile check here just to avoid some log noise on the remote end.
        # network duplication checks and profile checks also happen on the
        # remote end.

        avail_profiles = self.conn.get_profiles()
        matched_profile = False
        for x in avail_profiles:
            if x.get("name", "") == self.profile:
                matched_profile = True
                break

        reg_info['name'] = sysname
        reg_info['profile'] = self.profile
        reg_info['hostname'] = hostname

        if not matched_profile:
            raise InfoException(
                "no such remote profile, see 'koan --list-profiles'")

        if not self.batch:
            self.conn.register_new_system(reg_info)
            print("- registration successful, new system name: %s" % sysname)
        else:
            try:
                self.conn.register_new_system(reg_info)
                print("- registration successful, new system name: %s" %
                      sysname)
            except:
                traceback.print_exc()
                print("- registration failed, ignoring because of --batch")

        return