Skip to content

Commit 8f1832d

Browse files
committed
pass through the MILC instance as cli() as local instead of global to allow callers from other modules
1 parent 35475f9 commit 8f1832d

File tree

1 file changed

+47
-29
lines changed

1 file changed

+47
-29
lines changed

netfoundry/ctl.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from milc import set_metadata # this function needed to set metadata immediately below
4444
set_metadata(version=f"v{netfoundry_version}", author="NetFoundry", name="nfctl") # must precend import milc.cli
4545
from 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

4848
if 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')
9696
def 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):
107108
def 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')
217221
def 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):
556566
def 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')
688700
def 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')
779791
def 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

Comments
 (0)