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