def analyze(config: Dict, job_id: str, wide: bool = False) -> None: if not wide: try: _, columns_str = os.popen("stty size", "r").read().split() except Exception: columns_str = "120" columns = int(columns_str) else: columns = 120 ctx = DefaultContextHandler("[demand-cli]") register_result_handler(ctx) ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) config = ge_driver.preprocess_config(config) autoscaler.calculate_demand(config, ge_env, ge_driver, ctx) key = "[job {}]".format(job_id) results = ctx.by_context[key] for result in results: if isinstance(result, (EarlyBailoutResult, MatchResult)) and result: continue if isinstance(result, HostgroupConstraint) and not result: continue if wide: print(result.message) else: print(result.message[:columns])
def resources(config: Dict, constraint_expr: str) -> None: ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) node_mgr = new_node_manager(config, existing_nodes=ge_driver) filtered = _query_with_constraints(config, constraint_expr, node_mgr.get_buckets()) columns = set() for node in filtered: columns.update(set(node.resources.keys())) columns.update(set(node.resources.keys())) config["output_columns"]
def nodes( config: Dict, constraint_expr: str, output_columns: Optional[List[str]] = None, output_format: Optional[str] = None, ) -> None: """Query nodes""" ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) dcalc = autoscaler.new_demand_calculator(config, ge_env, ge_driver) filtered = _query_with_constraints(config, constraint_expr, dcalc.node_mgr.get_nodes()) demand_result = DemandResult([], filtered, [], []) autoscaler.print_demand(config, demand_result, output_columns)
def buckets( config: Dict, constraint_expr: str, output_columns: Optional[List[str]] = None, output_format: Optional[str] = None, ) -> None: """Prints out autoscale bucket information, like limits etc""" ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) config = ge_driver.preprocess_config(config) node_mgr = new_node_manager(config) specified_output_columns = output_columns output_columns = output_columns or [ "nodearray", "placement_group", "vm_size", "vcpu_count", "pcpu_count", "memory", "available_count", ] if specified_output_columns is None: for bucket in node_mgr.get_buckets(): for resource_name in bucket.resources: if resource_name not in output_columns: output_columns.append(resource_name) for attr in dir(bucket.limits): if attr[0].isalpha() and "count" in attr: value = getattr(bucket.limits, attr) if isinstance(value, int): bucket.resources[attr] = value bucket.example_node._resources[attr] = value filtered = _query_with_constraints(config, constraint_expr, node_mgr.get_buckets()) demand_result = DemandResult([], [f.example_node for f in filtered], [], []) if "all" in output_columns: output_columns = ["all"] config["output_columns"] = output_columns autoscaler.print_demand(config, demand_result, output_columns, output_format)
def demand( config: Dict, jobs: Optional[str] = None, scheduler_nodes: Optional[str] = None, output_columns: Optional[List[str]] = None, output_format: Optional[str] = None, ) -> None: """Runs autoscale in dry run mode to see the demand for new nodes""" logging.debug("Begin demand") ctx = DefaultContextHandler("[demand-cli]") register_result_handler(ctx) ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) config = ge_driver.preprocess_config(config) demand_calc = autoscaler.calculate_demand(config, ge_env, ge_driver, ctx) demand_result = demand_calc.finish() autoscaler.print_demand(config, demand_result, output_columns, output_format) logging.debug("End demand")
def _find_nodes( config: Dict, hostnames: List[str], node_names: List[str] ) -> Tuple[GridEngineDriver, DemandCalculator, List[Node]]: hostnames = hostnames or [] node_names = node_names or [] ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) demand_calc = autoscaler.calculate_demand(config, ge_env, ge_driver) demand_result = demand_calc.finish() by_hostname = partition_single( demand_result.compute_nodes, lambda n: n.hostname_or_uuid.lower() ) by_node_name = partition_single( demand_result.compute_nodes, lambda n: n.name.lower() ) found_nodes = [] for hostname in hostnames: if not hostname: error("Please specify a hostname") if hostname.lower() not in by_hostname: # it doesn't exist in CC, but we still want to delete it # from the cluster by_hostname[hostname.lower()] = SchedulerNode(hostname, {}) found_nodes.append(by_hostname[hostname.lower()]) for node_name in node_names: if not node_name: error("Please specify a node_name") if node_name.lower() not in by_node_name: error( "Could not find a CycleCloud node that has node_name %s." + " Run 'nodes' to see available nodes.", node_name, ) found_nodes.append(by_node_name[node_name.lower()]) return ge_driver, demand_calc, found_nodes
def shell(config: Dict) -> None: """ Provides read only interactive shell. type gehelp() in the shell for more information """ ctx = DefaultContextHandler("[interactive-readonly]") ge_env = environment.from_qconf(config) ge_driver = autoscaler.new_driver(config, ge_env) config = ge_driver.preprocess_config(config) demand_calc = autoscaler.new_demand_calculator(config, ge_env, ge_driver, ctx) queues = ge_env.queues def gehelp() -> None: print("config - dict representing autoscale configuration.") print("dbconn - Read-only SQLite conn to node history") print("demand_calc - DemandCalculator") print("ge_driver - GEDriver object.") print("jobs - List[Job] from ge_driver") print("node_mgr - NodeManager") print("logging - HPCLogging module") print("queues - GridEngineQueue objects") shell_locals = { "config": config, "ctx": ctx, "ge_driver": ge_driver, "demand_calc": demand_calc, "node_mgr": demand_calc.node_mgr, "jobs": ge_env.jobs, "dbconn": demand_calc.node_history.conn, "gehelp": gehelp, "queues": queues, "ge_env": ge_env, } banner = "\nCycleCloud GE Autoscale Shell" interpreter = ReraiseAssertionInterpreter(locals=shell_locals) try: __import__("readline") # some magic - create a completer that is bound to the locals in this interpreter and not # the __main__ interpreter. interpreter.push("import readline, rlcompleter") interpreter.push('readline.parse_and_bind("tab: complete")') interpreter.push("_completer = rlcompleter.Completer(locals())") interpreter.push("def _complete_helper(text, state):") interpreter.push(" ret = _completer.complete(text, state)") interpreter.push(' ret = ret + ")" if ret[-1] == "(" else ret') interpreter.push(" return ret") interpreter.push("") interpreter.push("readline.set_completer(_complete_helper)") for item in interpreter.history_lines: try: if '"""' in item: interpreter.push( "readline.add_history('''%s''')" % item.rstrip("\n") ) else: interpreter.push( 'readline.add_history("""%s""")' % item.rstrip("\n") ) except Exception: pass interpreter.push("from hpc.autoscale.job.job import Job\n") interpreter.push("from hpc.autoscale import hpclogging as logging\n") except ImportError: banner += ( "\nWARNING: `readline` is not installed, so autocomplete will not work." ) interpreter.interact(banner=banner)