33import sys
44from enum import Enum
55from pathlib import Path
6+ from typing import List
67
78import typer
89from ruamel .yaml import YAML
@@ -66,12 +67,26 @@ def proportional_memory_strategy(
6667 # This makes sure we utilize all the memory on a node all the time.
6768 cpu_guarantee = (mem_limit / available_node_mem ) * available_node_cpu
6869
69- # Memory is in bytes, let's convert it to GB (with only 1 digit after .) to display
70- mem_display = f"{ mem_limit / 1024 / 1024 / 1024 :.1f} "
71- display_name = f"{ mem_display } GB RAM, upto { cpu_display } CPUs"
70+ # Memory is in bytes, let's convert it to GB or MB (with no digits after 0) to display
71+ if mem_limit < 1024 * 1024 * 1024 :
72+ mem_display = f"{ mem_limit / 1024 / 1024 :.0f} MB"
73+ else :
74+ mem_display = f"{ mem_limit / 1024 / 1024 / 1024 :.0f} GB"
75+
76+ if cpu_guarantee < 2 :
77+ cpu_guarantee_display = f"~{ cpu_guarantee :0.1f} "
78+ else :
79+ cpu_guarantee_display = f"~{ cpu_guarantee :0.0f} "
80+
81+ display_name = f"{ mem_display } RAM, { cpu_guarantee_display } CPUs"
82+ if cpu_guarantee != available_node_cpu :
83+ description = f"Upto ~{ available_node_cpu :.0f} CPUs when available"
84+ else :
85+ description = f"~{ available_node_cpu :.0f} CPUs always available"
7286
7387 choice = {
7488 "display_name" : display_name ,
89+ "description" : description ,
7590 "kubespawner_override" : {
7691 # Guarantee and Limit are the same - this strategy has no oversubscription
7792 "mem_guarantee" : int (mem_limit ),
@@ -90,26 +105,23 @@ def proportional_memory_strategy(
90105 # Use the amount of RAM made available as a slug, to allow combining choices from
91106 # multiple instance types in the same profile. This does mean you can not have
92107 # the same RAM allocation from multiple node selectors. But that's a feature, not a bug.
93- choices [f"mem_{ mem_display .replace ('.' , '_' )} " ] = choice
108+ choice_key = f"mem_{ mem_display .replace ('.' , '_' ).replace (' ' , '_' )} " .lower ()
109+ choices [choice_key ] = choice
94110
95111 # Halve the mem_limit for the next choice
96112 mem_limit = mem_limit / 2
97113
98114 # Reverse the choices so the smallest one is first
99115 choices = dict (reversed (choices .items ()))
100116
101- # Make the smallest choice the default explicitly
102- choices [list (choices .keys ())[0 ]]["default" ] = True
103-
104117 return choices
105118
106119
107120@resource_allocation_app .command ()
108121def choices (
109- instance_type : str = typer .Argument (
110- ..., help = "Instance type to generate Resource Allocation options for"
122+ instance_specification : List [ str ] = typer .Argument (
123+ ..., help = "Instance type and number of choices to generate Resource Allocation options for. Specify as instance_type:count. "
111124 ),
112- num_allocations : int = typer .Option (5 , help = "Number of choices to generate" ),
113125 strategy : ResourceAllocationStrategies = typer .Option (
114126 ResourceAllocationStrategies .PROPORTIONAL_MEMORY_STRATEGY ,
115127 help = "Strategy to use for generating resource allocation choices choices" ,
@@ -121,19 +133,22 @@ def choices(
121133 """
122134 with open (HERE / "node-capacity-info.json" ) as f :
123135 nodeinfo = json .load (f )
124-
125- if instance_type not in nodeinfo :
126- print (
127- f"Capacity information about { instance_type } not available" , file = sys .stderr
128- )
129- print ("TODO: Provide information on how to update it" , file = sys .stderr )
130- sys .exit (1 )
131-
132- # Call appropriate function based on what strategy we want to use
133- if strategy == ResourceAllocationStrategies .PROPORTIONAL_MEMORY_STRATEGY :
134- choices = proportional_memory_strategy (
135- instance_type , nodeinfo [instance_type ], num_allocations
136- )
137- else :
138- raise ValueError (f"Strategy { strategy } is not currently supported" )
136+ choices = {}
137+ for instance_spec in instance_specification :
138+ instance_type , num_allocations = instance_spec .split (":" , 2 )
139+
140+ if instance_type not in nodeinfo :
141+ print (
142+ f"Capacity information about { instance_type } not available" , file = sys .stderr
143+ )
144+ print ("TODO: Provide information on how to update it" , file = sys .stderr )
145+ sys .exit (1 )
146+
147+ # Call appropriate function based on what strategy we want to use
148+ if strategy == ResourceAllocationStrategies .PROPORTIONAL_MEMORY_STRATEGY :
149+ choices .update (proportional_memory_strategy (
150+ instance_type , nodeinfo [instance_type ], int (num_allocations )
151+ ))
152+ else :
153+ raise ValueError (f"Strategy { strategy } is not currently supported" )
139154 yaml .dump (choices , sys .stdout )
0 commit comments