def free_addresses(used_ranges_path, addresses): if not os.path.exists(used_ranges_path): return f = utils.sync_open(used_ranges_path, "a+") pool = addrpool.AddressPool() for r in f.read().strip().split(): pool.add_used_range(r) for address in addresses: # FIXME: ip/netmasks management should be improved pool.free_address(address) f.truncate(0) f.write("\n".join(pool.dump_used_ranges())) f.write("\n") # trailing newline f.close()
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
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)