Example #1
0
File: main.py Project: ngsru/heaver
def shutdown(args, config):
    must_be_root()
    names = ops.ls()

    for name in names:
        if ops.is_running(name):
            try:
                ops.stop(name)
                try:
                    box_config = ops.get_box_config(name)
                except Exception as e:
                    report.die("Cannot load '%s' config, is it broken? %s" % (name, e))
                if os.path.exists(ops.get_box_home(name, "heaver_root_generated")):
                    imager = image.get_image_operator(config["image"])
                    if box_config["datamounts"]:
                        for mountpoint, source in box_config["datamounts"]:
                            imager.disassemble_instance(source)
                    imager.disassemble_instance(box_config["root"])
            except ops.InvocationError as e:
                report.die("LXC is broken, cannot stop container %s: %s" % (name, e))
            except ops.ContainerNotFound as e:
                # WTF? Should not happen (containers in ops.ls() already exists)
                report.die("Container %s just disappeared, panic!" % name)

            send_status_soft(args, config)
            print report.format(dict(status="OK", action="shutdown", id=name,
                message="Container %s stopped at shutdown" % name))
Example #2
0
def main(args, config):

    if not (args.create or args.destroy or args.add or args.remove or args.list or args.sync):
        report.die("No action given")

    if args.list and (args.create or args.destroy or args.add or args.remove):
        report.die("Cannot show list and perform actions!")

    if args.create and args.destroy:
        report.die("Cannot create and destroy clone simultaneously (-CD given)")

    if args.add and args.remove:
        report.die("Cannot add and remove image simultaneously (-AR given)")

    operator = image.get_image_operator(config["image"])

    if args.sync:
        sync(operator, args)

    if args.list:
        list_images(operator, args)

    if args.add:
        add(operator, args)

    if args.create:
        create(operator, args)

    if args.destroy:
        destroy(operator, args)

    if args.remove:
        remove(operator, args)
Example #3
0
File: main.py Project: ngsru/heaver
def stop(args, config):
    must_be_root()
    names = must_get_names(args)
    for name in names:
        try:
            ops.stop(name)
            try:
                box_config = ops.get_box_config(name)
            except Exception as e:
                report.die("Cannot load '%s' config, is it broken? %s" % (name, e))
            if os.path.exists(ops.get_box_home(name, "heaver_root_generated")):
                imager = image.get_image_operator(config["image"])
                if box_config["datamounts"]:
                    for mountpoint, source in box_config["datamounts"]:
                        imager.disassemble_instance(source)
                imager.disassemble_instance(box_config["root"])
        except ops.InvocationError as e:
            report.die("LXC is broken, cannot stop container %s: %s" % (name, e))
        except ops.ContainerNotFound as e:
            report.die("Container %s just disappeared, panic!" % name)
        try:
            running_flag = ops.get_box_home(name, "heaver_box_running")
            if os.path.exists(running_flag):
                os.unlink(running_flag)
        except Exception as e:
            pass # FIXME: should not happen, warn user/log?
	send_status_soft(args, config)
        print report.format(dict(status="OK", action="stop", id=name,
            message="Container %s stopped" % name))
Example #4
0
def main(args, config):

    if not (args.create or args.destroy or args.add or args.remove or args.list
            or args.sync):
        report.die("No action given")

    if args.list and (args.create or args.destroy or args.add or args.remove):
        report.die("Cannot show list and perform actions!")

    if args.create and args.destroy:
        report.die(
            "Cannot create and destroy clone simultaneously (-CD given)")

    if args.add and args.remove:
        report.die("Cannot add and remove image simultaneously (-AR given)")

    operator = image.get_image_operator(config["image"])

    if args.sync:
        sync(operator, args)

    if args.list:
        list_images(operator, args)

    if args.add:
        add(operator, args)

    if args.create:
        create(operator, args)

    if args.destroy:
        destroy(operator, args)

    if args.remove:
        remove(operator, args)
Example #5
0
File: main.py Project: ngsru/heaver
def make_tarball(args, config):
    must_be_root()
    if not args.name:
        report.die("No container chosen (tarball cannot be feed with --all)")

    name = args.name
    if name not in ops.ls():
        report.die("No such container: '%s'" % name)

    if ops.is_running(name):
        report.die("Container '%s' must be stopped for tarballing" % name)

    tar_path = args.tarball
    if tar_path == "<generated>":
        # make temporary path for tarball
        import tempfile
        try:
            tar_fd, tar_path = tempfile.mkstemp(dir=HEAVER_TMPDIR, prefix="%s.tar." % name)
            tar_file = os.fdopen(tar_fd, "w")
        except Exception as e: # FIXME: proper exceptions?
            report.die("Cannot create tarball of container '%s': '%s'" % (name, e))
    else:
        try:
            tar_file = open(tar_path, "wb")
        except Exception as e: # FIXME: proper exceptions?
            # cannot open file - no directory or no write access
            report.die("Cannot create tarball of container '%s': %s" % (name, e))

    box_config = ops.get_box_config(name)
    imager = image.get_image_operator(config["image"])
    imager.assemble_instance(box_config["root"])
    try:
        ops.write_tarball(name, tar_file)
    except Exception as e: # FIXME: proper exceptions?
        tar_file.close()
        os.unlink(tar_path)
        report.die("Cannot create tarball of container '%s': %s" % (name, e))

    tar_file.close()
    print report.format(dict(status="OK", action="tarball", data=tar_path,
        message="Tarball of container '%s' created at '%s'" % (name, tar_path)))
Example #6
0
File: main.py Project: ngsru/heaver
def start(args, config):
    must_be_root()
    names = must_get_names(args)

    # start
    for name in names:
        try:
            try:
                box_config = ops.get_box_config(name)
            except Exception as e:
                report.die("Cannot load '%s' config, is it broken? %s" % (name, e))
            if os.path.exists(ops.get_box_home(name, "heaver_root_generated")):
                imager = image.get_image_operator(config["image"])
                imager.assemble_instance(box_config["root"])

                if box_config["datamounts"]:
                    root = box_config["root"]
                    for mountpoint, source in box_config["datamounts"]:
                        imager.assemble_instance(source)
                        # since 'mountpoint' starts with / we need to remove it
                        mountpoint = mountpoint.lstrip("/")
                        mount_path = os.path.join(root, mountpoint)
                        if not os.path.exists(mount_path):
                            os.makedirs(mount_path)

            ops.start(name)
        except ops.InvocationError as e:
            report.die("LXC is broken, cannot start container %s: %s" % (name, e))
        except ops.ContainerNotFound as e:
            report.die("Container %s just disappeared, panic!" % name)
        try:
            running_flag = ops.get_box_home(name, "heaver_box_running")
            open(running_flag, "w").close()
        except Exception as e:
            pass # FIXME: should not happen, warn user/log?

	send_status_soft(args, config)
        print report.format(dict(status="OK", action="start", id=name,
            message="Container %s started" % name))
Example #7
0
File: main.py Project: ngsru/heaver
def get_status(config):
    if "hostname" in config:
        hostname = config["hostname"]
    else:
        import platform
        hostname = platform.node()

    status = dict(la=ops.get_la(), ram=ops.get_ram(), oom=ops.get_oom_stats(),
                  boxes=ops.ls(), hostname=hostname)
    used_ranges = utils.sync_open(config["net"]["used_ranges_path"], "a+")
    networks = must_load_net_config(config["net"]["networks"], used_ranges.read().strip().split())
    used_ranges.close()

    ips_free = 0
    for net in networks.values():
        ips_free += net["pool"].count_free_addresses()

    status["ips_free"] = ips_free

    imager = image.get_image_operator(config["image"])
    status["fs"] = imager.get_free_space()
    status["now"] = time.time()
    return status
Example #8
0
File: main.py Project: ngsru/heaver
def create(args, config):
    must_be_root()
    if not args.name:
        report.die("No container chosen (create cannot be feed with --all)")
    if ops.exists(args.name):
        report.die("Container %s already exists" % args.name)

    if not args.root and not args.image:
        report.die("Either image or root must be given (-i or -r)")

    if "limits" not in config:
        report.die("No \"limits\" section in config")

    must_be_correct_limits_config(config["limits"])
    if args.limit is not None and len(args.limit) > 0:
        for limit in args.limit:
            name, _delim, value = limit.partition("=")
            config["limits"][name] = value
        # recheck config
        must_be_correct_limits_config(config["limits"])

    key = None
    if args.key:
        try:
            with open(args.key) as key_file:
                key = key_file.read()
        except Exception as e:
            report.die("Cannot read given key file: %s" % e)
    elif args.raw_key:
        key = args.raw_key

    root_generated = False
    data_mounts = []
    if args.root:
        root = args.root
    else:
        imager = image.get_image_operator(config["image"])
        try:
            images = []
            for img_arg in args.image:
                images.append(img_arg.split(":")[0])
            status = imager.sync_images(images)
            for img_name, img_status in status:
                if img_status == "error":
                    report.die("Cannot sync image '%s'" % img_name)
            # find root image (it's without additional path)
            root_images = filter(lambda img: not ":" in img or img.endswith(":/"), args.image)
            if len(root_images) == 0:
                report.die("No root image specified")

            if len(root_images) > 1:
                report.die("Only one root image may be used")
            root_image = root_images[0].split(":")[0]
            root = imager.create_instance(root_image, args.name)

            data_images = list(args.image)
            data_images.remove(root_images[0])

            for data_image in data_images:
                image_name, _semicolon, mountpoint = data_image.partition(":")
                data_root = imager.create_instance(image_name, args.name)
                data_mounts.append((mountpoint, data_root))

        except Exception as e:
            import traceback
            tb = traceback.format_exc()
            report.die("Cannot acquire root with image id '%s': %s\n%s" % (args.image, e, tb))
        root_generated = True

    if root[0] != "/":
        root = os.path.join(os.getcwd(), root)

    box_config = dict(root=root, networks=dict(), key=key, datamounts=data_mounts)
    # set up limits

    box_config["limits"] = config["limits"]
    box_config["raw"] = dict()
    if "cgroup" in config:
        for name, value in config["cgroup"].items():
            if name == "cpuset.cpus" and value == "auto":
                value = get_balanced_cpu()
            box_config["raw"]["cgroup." + name] = value

    # set up network
    all_ips = []
    if args.net is None:
        must_be_correct_net_config(config["net"])
        used_ranges = utils.sync_open(config["net"]["used_ranges_path"], "a+")
        networks = must_load_net_config(config["net"]["networks"],
                                        used_ranges.read().strip().split())
        args.net = [networks.items()[0][1]["bridge"]]
        used_ranges.close()

    if args.net or args.raw_net:
        must_be_correct_net_config(config["net"])
        used_ranges = utils.sync_open(config["net"]["used_ranges_path"], "a+")
        networks = must_load_net_config(config["net"]["networks"],
                                        used_ranges.read().strip().split())
        bridge_count = 0
        if args.raw_net is not None:
            bridge_count = len(args.raw_net)
            for idx, net in enumerate(args.raw_net):
                bridge, hwaddr, ips = must_parse_net_arg(net)
                for ip, mask in ips:
                    all_ips.append(ip)
                net_config = dict(type="veth", ips=ips, link=bridge, flags="up")
                if hwaddr:
                    net_config["hwaddr"] = hwaddr
                if idx == 0:
                    net_config["gateway"] = "auto"
                box_config["networks"]["eth%d" % idx] = net_config
        if args.net is not None:
            for idx, net in enumerate(args.net):
                net_idx = idx + bridge_count
                name, _semicolon, ip_count_str = net.partition(":")
                if name not in networks:
                    report.die("No such network: %s" % name)
                if ip_count_str != "":
                    try:
                        ip_count = int(ip_count_str)
                    except:
                        report.die("Ip count for network '%s' is not an int" % name)
                else:
                    ip_count = 1

                network = networks[name]
                hwaddr, ips = must_gen_net(network, ip_count)
                for ip, mask in ips:
                    all_ips.append(ip)
                bridge = network["bridge"]
                if net_idx == 0:
                    gateway = network.get("gateway")
                else:
                    gateway = None
                net_config = dict(type="veth", ips=ips, link=bridge, flags="up", gateway=gateway,
                                  hwaddr=hwaddr)
                box_config["networks"]["eth%d" % net_idx] = net_config

        # overwrite config
        used_ranges.truncate(0)
        used_ranges.write("\n".join(networks.values()[0]["pool"].dump_used_ranges()))
        used_ranges.write("\n") # trailing newline
        used_ranges.close()
    try:
        ops.create(args.name, box_config)
    except ops.InvalidConfig as e:
        report.die("Internal error, invalid config: %r" % e)

        import traceback
        print traceback.format_exc()

        if all_ips:
            try:
                free_addresses(config["net"]["used_ranges_path"], all_ips)
            except e:
                report.die("Failed to free addresses, do it yourself: %s" % e)
    except ops.CreationError as e:
        report.die("Cannot create container: %r" % e)

    except Exception as e:
        import traceback
        report.die("!!! Unhandled exception !!!\n%s\n%s" % (traceback.format_exc(), e))

    # if root was generated, remember it
    if root_generated:
        root_gen_path = ops.get_box_home(args.name, "heaver_root_generated")
        try:
            open(root_gen_path, "w").close()
        except Exception as e:
            pass #FIXME: warn user about it

    msg = dict(status="OK", action="create", id=args.name)
    if all_ips:
        msg["message"] = "Created container %s with addresses: %s" % (args.name,
            ", ".join(all_ips))
        msg["data"] = dict(ips=all_ips)
    else:
        msg["message"] = "Created container %s" % args.name
    
    # send status to upstream if possible
    send_status_soft(args, config)

    print report.format(msg)
Example #9
0
File: main.py Project: ngsru/heaver
def destroy(args, config):
    must_be_root()
    names = must_get_names(args)
    if args.all and not args.force:
        msg = ["Selected containers: %s" % ", ".join(names),
               "Are you sure to destroy all these (probably innocent) containers? [y/N] "]
        decision = raw_input("\n".join(msg))
        if not (decision.lower() == "y" or decision.lower() == "yes"):
            print "Okay"
            return

    for name in names:
        box_root = None
        if not ops.exists(name):
            print report.format(dict(status="OK", action="destroy", id=name,
                message="Container %s already destroyed" % name))
            continue
        try:
            box_config = ops.get_box_config(name)
        except Exception as e:
            report.die("Cannot load '%s' config, is it broken? %s" % (name, e))

        root_generated = os.path.exists(ops.get_box_home(name, "heaver_root_generated"))
        root = box_config.get("root")
        try:
            # Free addresses, associated with box
            ips = []
            for network in box_config["networks"].values():
                for ip, mask in network["ips"]:
                    ips.append(ip)
            free_addresses(config["net"]["used_ranges_path"], ips)
        except Exception as e:
            print "Cannot release assigned to box addresses:", e

            import traceback
            print traceback.format_exc()

        try:
            ops.destroy(name)
        except ops.ContainerBusy as e:
            report.die("Container busy: %s" % e)
        except ops.ContainerNotFound:
            pass
        except ops.InvocationError as e:
            report.die("LXC is broken, cannot destroy container %s: %s" % (name, e))

        # remove root, if it was generated
        if root_generated:
            imager = image.get_image_operator(config["image"])
            try:
                imager.destroy_instance(root)
            except Exception as e:
                report.die("Cannot remove root of container '%s': %s" % (name, e))
            if box_config["datamounts"]:
                for mountpoint, source in box_config["datamounts"]:
                    try:
                        imager.destroy_instance(source)
                    except Exception as e:
                        report.die("Cannot remove datamount '%s' in container'%s': %s" % (source,
                                                                                          name, e))
        send_status_soft(args, config)
        print report.format(dict(status="OK", action="destroy", id=name,
            message="Container %s destroyed" % name))