4343from milc import set_metadata # this function needed to set metadata immediately below
4444set_metadata (version = f"v{ netfoundry_version } " , author = "NetFoundry" , name = "nfctl" ) # must precend import milc.cli
4545from milc import cli , questions # this uses metadata set above
46- from milc .subcommand import config # this creates the config subcommand
46+ import milc .subcommand . config # this creates the config subcommand
4747
4848if platform .system () == 'Linux' :
4949 # this allows the app the terminate gracefully when piped to a truncating consumer like `head`
@@ -95,10 +95,11 @@ def __call__(self, parser, namespace, values, option_string=None):
9595@cli .entrypoint ('configure the CLI to manage a network' )
9696def main (cli ):
9797 """Configure the CLI to manage a network."""
98- cli . args [ 'login_target' ] = 'organization'
99- cli .args ['report ' ] = False
98+ # assign the default values for options that are evaluted by login() since they're not set by main()'s options
99+ cli .args ['autocomplete ' ] = True
100100 cli .args ['eval' ] = False
101101 login (cli )
102+ cli .log .info (f"try running '{ cli .prog_name } list networks'" )
102103
103104
104105@cli .argument ('-a' , '--autocomplete' , action = 'store_boolean' , default = True , help = "include tab autocomplete configuration in shell eval" )
@@ -107,24 +108,27 @@ def main(cli):
107108def login (cli ):
108109 """Login to an API and cache the expiring token."""
109110 # if logging in to a NF org (default)
110- spinner = get_spinner ("working" )
111+ spinner = get_spinner (cli , "working" )
111112 spinner .text = f"Logging in profile '{ cli .config .general .profile } '"
112113 with spinner :
113- organization , networks = use_organization (spinner = spinner )
114+ organization , networks = use_organization (cli , spinner )
114115 if cli .config .general .network_group and cli .config .general .network :
115116 cli .log .debug (f"configuring network { cli .config .general .network } in group { cli .config .general .network_group } " )
116117 network , network_group = use_network (
118+ cli ,
117119 organization = organization ,
118120 group = cli .config .general .network_group ,
119121 network_name = cli .config .general .network )
120122 elif cli .config .general .network :
121123 cli .log .debug (f"configuring network { cli .config .general .network } and local group if unique name for this organization" )
122124 network , network_group = use_network (
125+ cli ,
123126 organization = organization ,
124127 network_name = cli .config .general .network )
125128 elif cli .config .general .network_group :
126129 cli .log .debug (f"configuring network group { cli .config .general .network_group } " )
127130 network_group = use_network_group (
131+ cli ,
128132 organization ,
129133 group = cli .config .general .network_group )
130134 network = None
@@ -216,7 +220,7 @@ def login(cli):
216220@cli .subcommand ('logout your identity for the current current profile' )
217221def logout (cli ):
218222 """Logout by deleting the cached token."""
219- spinner = get_spinner ("working" )
223+ spinner = get_spinner (cli , "working" )
220224 spinner .text = f"Logging out profile '{ cli .config .general .profile } '"
221225 # use the session with some organization, default is to use the first and there's typically only one
222226 try :
@@ -244,7 +248,7 @@ def copy(cli):
244248 accepts a file to edit as first positional parameter and waits for exit to
245249 return e.g. "code --wait".
246250 """
247- spinner = get_spinner ("working" )
251+ spinner = get_spinner (cli , "working" )
248252 if MUTABLE_RESOURCE_ABBREV .get (cli .args .resource_type ):
249253 cli .args .resource_type = singular (MUTABLE_RESOURCE_ABBREV [cli .args .resource_type ].name )
250254 spinner .text = f"Getting { cli .args .resource_type } for copying"
@@ -253,7 +257,7 @@ def copy(cli):
253257 with spinner :
254258 edit_resource_object , network , network_group , organization = get (cli , echo = False , spinner = spinner )
255259 cli .log .debug (f"opening { cli .args .resource_type } '{ edit_resource_object ['name' ]} ' for copying" )
256- copy_request_object = edit_object_as_yaml (edit_resource_object )
260+ copy_request_object = edit_object_as_yaml (cli , edit_resource_object )
257261 if not copy_request_object : # is False if editing cancelled by empty buffer
258262 return True
259263 else :
@@ -273,7 +277,7 @@ def create(cli):
273277 send create request upon EDITOR exit. If not interactive then send input
274278 object as create request immediately.
275279 """
276- spinner = get_spinner ("working" )
280+ spinner = get_spinner (cli , "working" )
277281 if MUTABLE_RESOURCE_ABBREV .get (cli .args .resource_type ):
278282 cli .args .resource_type = singular (MUTABLE_RESOURCE_ABBREV [cli .args .resource_type ].name )
279283 # get the input object if available, else get the lines (serialized YAML or JSON) and try to deserialize
@@ -302,17 +306,17 @@ def create(cli):
302306 cli .log .error ("failed to parse input lines as an object (deserialized JSON or YAML)" )
303307 sysexit (1 )
304308
305- create_object = edit_object_as_yaml (create_input_object )
309+ create_object = edit_object_as_yaml (cli , create_input_object )
306310 if not create_object : # False if editing cancelled by empty buffer
307311 cli .log .debug = f"Creating { cli .args .resource_type } cancelled"
308312 return True
309313 else :
310314 spinner .text = f"Creating { cli .args .resource_type } "
311315 with spinner :
312- organization , networks = use_organization (spinner = spinner )
316+ organization , networks = use_organization (cli , spinner )
313317 if cli .args .resource_type == "network" :
314318 if cli .config .general .network_group :
315- network_group = use_network_group (organization = organization , )
319+ network_group = use_network_group (cli , organization = organization , )
316320 else :
317321 org_count = len (organization .find_network_groups_by_organization ())
318322 if org_count > 1 :
@@ -321,11 +325,13 @@ def create(cli):
321325 else : # use the only available group
322326 network_group_id = organization .find_network_groups_by_organization ()[0 ]['id' ]
323327 network_group = use_network_group (
328+ cli ,
324329 organization = organization ,
325330 group = network_group_id )
326331 resource = network_group .create_network (** create_object )
327332 else :
328333 network , network_group = use_network (
334+ cli ,
329335 organization = organization ,
330336 group = cli .config .general .network_group ,
331337 network_name = cli .config .general .network )
@@ -344,15 +350,15 @@ def edit(cli):
344350 accepts a file to edit as first positional parameter and waits for exit to
345351 return e.g. "code --wait".
346352 """
347- spinner = get_spinner ("working" )
353+ spinner = get_spinner (cli , "working" )
348354 if MUTABLE_RESOURCE_ABBREV .get (cli .args .resource_type ):
349355 cli .args .resource_type = singular (MUTABLE_RESOURCE_ABBREV [cli .args .resource_type ].name )
350356 cli .args ['accept' ] = None
351357 spinner .text = f"Getting { cli .args .resource_type } for editing"
352358 cli .log .debug (f"opening { cli .args .resource_type } for editing" )
353359 with spinner :
354360 edit_resource_object , network , network_group , organization = get (cli , echo = False , spinner = spinner )
355- update_request_object = edit_object_as_yaml (edit_resource_object )
361+ update_request_object = edit_object_as_yaml (cli , edit_resource_object )
356362 with spinner :
357363 if not update_request_object : # is False if editing cancelled by empty buffer
358364 spinner .text = f"Editing { cli .args .resource_type } cancelled"
@@ -387,14 +393,14 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
387393 matches = []
388394 query_keys = [* cli .args .query ]
389395 if not spinner :
390- spinner = get_spinner ("working" )
396+ spinner = get_spinner (cli , "working" )
391397 else :
392398 cli .log .debug ("got spinner as function param" )
393399 spinner .text = f"Getting { cli .args .resource_type } "
394400 if not echo :
395401 spinner .enabled = False
396402 with spinner :
397- organization , networks = use_organization (spinner = spinner )
403+ organization , networks = use_organization (cli , spinner )
398404 if cli .args .resource_type == "organization" :
399405 if 'id' in query_keys :
400406 if len (query_keys ) > 1 :
@@ -456,12 +462,14 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
456462 else :
457463 if cli .config .general .network_group and not cli .config .general .network :
458464 network_group = use_network_group (
465+ cli ,
459466 organization ,
460467 group = cli .config .general .network_group ,
461468 )
462469 matches = organization .find_networks_by_group (network_group .id , ** cli .args .query )
463470 elif cli .config .general .network :
464471 network , network_group = use_network (
472+ cli ,
465473 organization = organization ,
466474 network_name = cli .config .general .network ,
467475 )
@@ -470,13 +478,15 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
470478 matches = organization .find_networks_by_organization (** cli .args .query )
471479 if len (matches ) == 1 :
472480 network , network_group = use_network (
481+ cli ,
473482 organization = organization ,
474483 network_name = matches [0 ]['name' ],
475484 )
476485 match = organization .get_network (network_id = network .id , embed = embed , accept = cli .args .accept )
477486 else : # is a resource in the network domain
478487 if cli .config .general .network :
479488 network , network_group = use_network (
489+ cli ,
480490 organization = organization ,
481491 group = cli .config .general .network_group , # None unless configured
482492 network_name = cli .config .general .network ,
@@ -556,7 +566,7 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
556566def list (cli , spinner : object = None ):
557567 """Find resources as lists."""
558568 if not spinner :
559- spinner = get_spinner ("working" )
569+ spinner = get_spinner (cli , "working" )
560570 else :
561571 cli .log .debug ("got spinner as function param" )
562572 if RESOURCE_ABBREV .get (cli .args .resource_type ):
@@ -577,7 +587,7 @@ def list(cli, spinner: object = None):
577587 else :
578588 spinner .text = f"Finding all { cli .args .resource_type } "
579589 with spinner :
580- organization , networks = use_organization (spinner = spinner )
590+ organization , networks = use_organization (cli , spinner )
581591 if cli .args .resource_type == "organizations" :
582592 matches = organization .find_organizations (** cli .args .query )
583593 elif cli .args .resource_type in ["network-versions" ]:
@@ -597,6 +607,7 @@ def list(cli, spinner: object = None):
597607 elif cli .args .resource_type == "networks" :
598608 if cli .config .general .network_group :
599609 network_group = use_network_group (
610+ cli ,
600611 organization = organization ,
601612 group = cli .config .general .network_group ,
602613 spinner = spinner )
@@ -606,6 +617,7 @@ def list(cli, spinner: object = None):
606617 else :
607618 if cli .config .general .network :
608619 network , network_group = use_network (
620+ cli ,
609621 organization = organization ,
610622 group = cli .config .general .network_group , # None unless configured
611623 network_name = cli .config .general .network ,
@@ -687,7 +699,7 @@ def list(cli, spinner: object = None):
687699@cli .subcommand ('delete a single resource by type and query' )
688700def delete (cli ):
689701 """Delete a resource in the network domain."""
690- spinner = get_spinner ("working" )
702+ spinner = get_spinner (cli , "working" )
691703 query_keys = [* cli .args .query ]
692704 if MUTABLE_RESOURCE_ABBREV .get (cli .args .resource_type ):
693705 cli .args ['resource_type' ] = singular (MUTABLE_RESOURCE_ABBREV [cli .args .resource_type ].name )
@@ -778,9 +790,9 @@ def delete(cli):
778790@cli .subcommand ('create a functioning demo network' )
779791def demo (cli ):
780792 """Create a demo network or add demo resources to existing network."""
781- spinner = get_spinner ("working" )
793+ spinner = get_spinner (cli , "working" )
782794 with spinner :
783- organization , networks = use_organization (spinner = spinner )
795+ organization , networks = use_organization (cli , spinner )
784796 if cli .config .general .network :
785797 network_name = cli .config .general .network
786798 else :
@@ -812,11 +824,13 @@ def demo(cli):
812824 # create network unless exists
813825 cli .log .setLevel (logging .WARN ) # FIXME: hack to silence redundant spinners
814826 network_group = use_network_group (
827+ cli ,
815828 organization ,
816829 cli .config .general .network_group )
817830 cli .log .setLevel (logging .INFO ) # FIXME: hack to silence redundant spinners
818831 if network_group .network_exists (network_name ):
819832 network , network_group = use_network (
833+ cli ,
820834 organization = organization ,
821835 group = network_group .id ,
822836 network_name = network_name ,
@@ -831,6 +845,7 @@ def demo(cli):
831845 version = cli .config .demo .product_version ,
832846 wait = 0 ) # FIXME: don't use wait > 0 until process-executions beta is launched, until then poll for status
833847 network , network_group = use_network (
848+ cli ,
834849 organization = organization ,
835850 group = cli .config .general .network_group ,
836851 network_name = network_created ['name' ],
@@ -1031,10 +1046,10 @@ def demo(cli):
10311046 cli .log .info ("Demo Guide: https://developer.netfoundry.io/guides/demo/" )
10321047
10331048
1034- def use_organization (prompt : bool = True , spinner : object = None ):
1049+ def use_organization (cli , prompt : bool = True , spinner : object = None ):
10351050 """Cache an expiring token for an identity and configure access to the network domain."""
10361051 if not spinner :
1037- spinner = get_spinner ("working" )
1052+ spinner = get_spinner (cli , "working" )
10381053 else :
10391054 cli .log .debug ("got spinner as function param" )
10401055 spinner .text = f"Loading profile '{ cli .config .general .profile } '"
@@ -1085,7 +1100,7 @@ def use_organization(prompt: bool = True, spinner: object = None):
10851100 return organization , networks
10861101
10871102
1088- def use_network_group (organization : object , group : str = None , spinner : object = None ):
1103+ def use_network_group (cli , organization : object , group : str = None , spinner : object = None ):
10891104 """
10901105 Use a network group.
10911106
@@ -1094,7 +1109,7 @@ def use_network_group(organization: object, group: str = None, spinner: object =
10941109 :param str group: name or UUIDv4 of group to use
10951110 """
10961111 if not spinner :
1097- spinner = get_spinner ("working" )
1112+ spinner = get_spinner (cli , "working" )
10981113 else :
10991114 cli .log .debug ("got spinner as function param" )
11001115 # module will use first available group if not specified, and typically there is only one
@@ -1109,7 +1124,7 @@ def use_network_group(organization: object, group: str = None, spinner: object =
11091124 return network_group
11101125
11111126
1112- def use_network (organization : object , network_name : str = None , group : str = None , spinner : object = None ):
1127+ def use_network (cli , organization : object , network_name : str = None , group : str = None , spinner : object = None ):
11131128 """
11141129 Use a network.
11151130
@@ -1119,13 +1134,14 @@ def use_network(organization: object, network_name: str = None, group: str = Non
11191134 :param group: a network group name or UUID, optional if network name is unique across all available groups
11201135 """
11211136 if not spinner :
1122- spinner = get_spinner ("working" )
1137+ spinner = get_spinner (cli , "working" )
11231138 else :
11241139 cli .log .debug ("got spinner as function param" )
11251140 if not network_name :
11261141 spinner .text = "Finding networks"
11271142 if group :
11281143 network_group = use_network_group (
1144+ cli ,
11291145 organization = organization ,
11301146 group = group ,
11311147 spinner = spinner )
@@ -1141,6 +1157,7 @@ def use_network(organization: object, network_name: str = None, group: str = Non
11411157 sysexit (1 )
11421158 elif group :
11431159 network_group = use_network_group (
1160+ cli ,
11441161 organization = organization ,
11451162 group = group ,
11461163 spinner = spinner )
@@ -1154,6 +1171,7 @@ def use_network(organization: object, network_name: str = None, group: str = Non
11541171 existing_networks = organization .find_networks_by_organization (name = network_name )
11551172 existing_network = existing_networks [0 ]
11561173 network_group = use_network_group (
1174+ cli ,
11571175 organization ,
11581176 group = existing_network ['networkGroupId' ],
11591177 spinner = spinner )
@@ -1185,7 +1203,7 @@ def use_network(organization: object, network_name: str = None, group: str = Non
11851203 return network , network_group
11861204
11871205
1188- def edit_object_as_yaml (edit : object ):
1206+ def edit_object_as_yaml (cli , edit : object ):
11891207 """Edit a resource object as YAML and return as object upon exit.
11901208
11911209 :param obj input: a deserialized (object) to edit and return as yaml
@@ -1234,7 +1252,7 @@ def edit_object_as_yaml(edit: object):
12341252 sysexit (1 )
12351253
12361254
1237- def get_spinner (text ):
1255+ def get_spinner (cli , text ):
12381256 """
12391257 Get a spinner.
12401258
0 commit comments