Skip to content

Commit 6bb3676

Browse files
committed
contrain milc version
1 parent 5c2c12f commit 6bb3676

File tree

5 files changed

+46
-31
lines changed

5 files changed

+46
-31
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
general.network=$(nfctl demo --echo-name --prefix 'gh-${{ github.run_id }}') \
8686
general.yes=True \
8787
general.verbose=yes || true # FIXME: sometimes config command exits with an error
88-
nfctl demo \
88+
nfctl --wait 3000 demo \
8989
--size medium \
9090
--regions us-west-2 us-east-1 \
9191
--provider AWS

netfoundry/ctl.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
# import milc cli
4646
from milc import cli, questions # noqa: E402
47-
# set milc options using new API
47+
# set milc options (requires milc >= 1.8.0)
4848
cli.milc_options(name='nfctl', author='NetFoundry', version=f'v{netfoundry_version}')
4949
# this creates the config subcommand
5050
from milc.subcommand import config # noqa: F401,E402
@@ -994,7 +994,7 @@ def demo(cli):
994994
spinner.text = f"Waiting for {len(hosted_edge_routers)} hosted router(s) to provision"
995995
with spinner:
996996
for router in hosted_edge_routers:
997-
network.wait_for_statuses(expected_statuses=RESOURCES["edge-routers"].status_symbols["complete"], id=router['id'], type="edge-router", wait=2222, progress=False)
997+
network.wait_for_statuses(expected_statuses=RESOURCES["edge-routers"].status_symbols["complete"], id=router['id'], type="edge-router", wait=cli.config.general.wait, progress=False)
998998
# ensure the router tunneler is available
999999
# network.wait_for_entity_name_exists(entity_name=router['name'], entity_type='endpoint')
10001000
# router_tunneler = network.find_resources(type='endpoint', name=router['name'])[0]
@@ -1105,8 +1105,9 @@ def demo(cli):
11051105
customer_router = network.edge_routers(name=customer_router_name)[0]
11061106
spinner.succeed(sub("Finding", "Found", spinner.text))
11071107

1108-
spinner.text = f"Waiting for customer router {customer_router_name} to be ready for registration"
1109-
# wait for customer router to be PROVISIONED so that registration will be available
1108+
spinner.text = f"Getting registration key for customer router {customer_router_name}"
1109+
# Customer routers don't auto-provision - registration key is available immediately at status NEW
1110+
# The router will only reach PROVISIONED status after manual registration and connection
11101111
with spinner:
11111112
try:
11121113
network.wait_for_statuses(expected_statuses=RESOURCES["edge-routers"].status_symbols["complete"], id=customer_router['id'], type="edge-router", wait=222, progress=False)

netfoundry/organization.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ def __init__(self,
159159
self.expiry_seconds = round(self.expiry - epoch)
160160
self.audience = token_cache['audience']
161161

162+
# Check if cached token is expired
163+
if self.expiry_seconds < 0:
164+
self.logger.debug(f"cached token is expired ({self.expiry_seconds}s ago), forcing renewal")
165+
self.token = None
166+
self.expiry = None
167+
self.audience = None
168+
162169
# if the token was found but not the expiry then try to parse to extract the expiry so we can enforce minimum lifespan seconds
163170
if self.token and not self.expiry:
164171
try:
@@ -280,14 +287,16 @@ def __init__(self,
280287
self.expiry_seconds = round(self.expiry - epoch)
281288
self.logger.debug(f"bearer token expiry in {self.expiry_seconds}s")
282289

283-
# renew token if not existing or imminent expiry, else continue
284-
if not self.token or self.expiry_seconds < expiry_minimum:
290+
# renew token if not existing, expired, or imminent expiry, else continue
291+
if not self.token or self.expiry_seconds < 0 or self.expiry_seconds < expiry_minimum:
285292
# we've already done the work to determine the cached token is expired or imminently-expiring, might as well save other runs the same trouble
286293
self.logout()
287294
self.expiry = None
288295
self.audience = None
289296
if self.token and self.expiry_seconds < expiry_minimum:
290297
self.logger.debug(f"token expiry {self.expiry_seconds}s is less than configured minimum {expiry_minimum}s")
298+
if self.expiry_seconds < 0:
299+
self.logger.debug(f"token is expired ({abs(self.expiry_seconds)}s ago), forcing renewal")
291300
if not credentials_configured:
292301
raise NFAPINoCredentials("unable to renew because credentials are not configured")
293302
else:
@@ -430,7 +439,7 @@ def get_caller_identity(self):
430439
except Exception as e:
431440
self.logger.debug(f"failed to get caller identity from url: '{url}', trying next until last, caught {e}")
432441
else:
433-
return(caller)
442+
return caller
434443
raise RuntimeError("failed to get caller identity from any url")
435444

436445
def get_identity(self, identity_id: str):
@@ -444,7 +453,7 @@ def get_identity(self, identity_id: str):
444453
except Exception as e:
445454
raise RuntimeError(f"failed to get identity from url: '{url}', caught {e}")
446455
else:
447-
return(identity)
456+
return identity
448457

449458
def find_identities(self, type: str = 'identities', **kwargs):
450459
"""Get identities as a collection.
@@ -473,7 +482,7 @@ def find_identities(self, type: str = 'identities', **kwargs):
473482
except Exception as e:
474483
raise RuntimeError(f"failed to get identities from url: '{url}', caught {e}")
475484
else:
476-
return(identities)
485+
return identities
477486
get_identities = find_identities
478487

479488
def find_roles(self, **kwargs):
@@ -503,7 +512,7 @@ def find_roles(self, **kwargs):
503512
except Exception as e:
504513
raise RuntimeError(f"failed to get roles from url: '{url}', caught {e}")
505514
else:
506-
return(roles)
515+
return roles
507516

508517
def get_role(self, role_id: str):
509518
"""Get roles as a collection."""
@@ -514,7 +523,7 @@ def get_role(self, role_id: str):
514523
except Exception as e:
515524
raise RuntimeError(f"failed to get role from url: '{url}', caught {e}")
516525
else:
517-
return(role)
526+
return role
518527

519528
def find_organizations(self, **kwargs):
520529
"""Find organizations as a collection.
@@ -536,7 +545,7 @@ def find_organizations(self, **kwargs):
536545
except Exception as e:
537546
raise RuntimeError(f"failed to get organizations from url: '{url}', caught {e}")
538547
else:
539-
return(organizations)
548+
return organizations
540549
get_organizations = find_organizations
541550

542551
def get_organization(self, id):
@@ -551,7 +560,7 @@ def get_organization(self, id):
551560
except Exception as e:
552561
raise RuntimeError(f"failed to get organization from url: '{url}', caught {e}")
553562
else:
554-
return(organization)
563+
return organization
555564

556565
def get_network_group(self, network_group_id):
557566
"""
@@ -565,7 +574,7 @@ def get_network_group(self, network_group_id):
565574
except Exception as e:
566575
raise RuntimeError(f"failed to get network_group from url: '{url}', caught {e}")
567576
else:
568-
return(network_group)
577+
return network_group
569578

570579
def get_network(self, network_id: str, embed: object = None, accept: str = None):
571580
"""Describe a Network by ID.
@@ -593,7 +602,7 @@ def get_network(self, network_id: str, embed: object = None, accept: str = None)
593602

594603
url = self.audience+'core/v2/networks/'+network_id
595604
network, status_symbol = get_generic_resource_by_url(setup=self, url=url, accept=accept, **params)
596-
return(network)
605+
return network
597606

598607
def find_network_groups_by_organization(self, **kwargs):
599608
"""Find network groups as a collection.
@@ -604,7 +613,7 @@ def find_network_groups_by_organization(self, **kwargs):
604613
network_groups = list()
605614
for i in find_generic_resources(setup=self, url=url, embedded=RESOURCES['network-groups']._embedded, **kwargs):
606615
network_groups.extend(i)
607-
return(network_groups)
616+
return network_groups
608617
get_network_groups_by_organization = find_network_groups_by_organization
609618
network_groups = get_network_groups_by_organization
610619

@@ -631,7 +640,7 @@ def find_networks_by_organization(self, name: str = None, deleted: bool = False,
631640
except Exception as e:
632641
raise RuntimeError(f"failed to get networks from url: '{url}', caught {e}")
633642
else:
634-
return(networks)
643+
return networks
635644
get_networks_by_organization = find_networks_by_organization
636645

637646
def network_exists(self, name: str, deleted: bool = False):
@@ -641,9 +650,9 @@ def network_exists(self, name: str, deleted: bool = False):
641650
:param deleted: include deleted networks in results
642651
"""
643652
if self.count_networks_with_name(name=name, deleted=deleted) > 0:
644-
return(True)
653+
return True
645654
else:
646-
return(False)
655+
return False
647656

648657
def count_networks_with_name(self, name: str, deleted: bool = False, unique: bool = True):
649658
"""
@@ -686,5 +695,5 @@ def find_networks_by_group(self, network_group_id: str, deleted: bool = False, a
686695
except Exception as e:
687696
raise RuntimeError(f"failed to get networks from url: '{url}', caught {e}")
688697
else:
689-
return(networks)
698+
return networks
690699
get_networks_by_group = find_networks_by_group

netfoundry/utility.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ def plural(singular):
4343
# if already plural then return, else pluralize
4444
p = inflect.engine()
4545
if singular[-1:] == 's':
46-
return(singular)
46+
return singular
4747
else:
48-
return(p.plural_noun(singular))
48+
return p.plural_noun(singular)
4949

5050

5151
def singular(plural):
5252
"""Singularize a plural form."""
5353
p = inflect.engine()
54-
return(p.singular_noun(plural))
54+
return p.singular_noun(plural)
5555

5656

5757
def kebab2camel(kebab: str, case: str = "lower"): # "lower" dromedary or "upper" Pascal
@@ -485,12 +485,12 @@ def find_generic_resources(setup: object, url: str, headers: dict = dict(), embe
485485
)
486486
response.raise_for_status()
487487
resource_page = response.json()
488-
488+
489489
# Handle non-paginated endpoints that return direct lists
490490
if isinstance(resource_page, list):
491491
yield resource_page
492492
return
493-
493+
494494
if isinstance(resource_page, dict) and resource_page.get('page'):
495495
try:
496496
total_pages = resource_page['page']['totalPages']
@@ -623,9 +623,7 @@ class ResourceType(ResourceTypeParent):
623623
embeddable: bool # legal to request embedding in a parent resource in same domain
624624
parent: str = field(default=str()) # optional parent ResourceType instance name
625625
status: str = field(default='status') # name of property where symbolic status is expressed
626-
_embedded: str = field(default='default') # the key under which lists are found in the API
627-
# e.g. networkControllerList (computed if not provided as dromedary
628-
# case singular)
626+
_embedded: str = field(default='default') # the key under which lists are found in the API e.g. networkControllerList (computed if not provided as dromedary case singular)
629627
create_responses: list = field(default_factory=list) # expected HTTP response codes for create operation
630628
no_update_props: list = field(default_factory=list) # expected HTTP response codes for create operation
631629
create_template: dict = field(default_factory=lambda: {
@@ -932,7 +930,14 @@ def send(self, request, **kwargs):
932930

933931
http = Session() # no cache
934932
HTTP_CACHE_EXPIRE = 33
935-
http_cache = CachedSession(cache_name=f"{get_user_cache_dir()}/http_cache", backend='sqlite', expire_after=HTTP_CACHE_EXPIRE)
933+
http_cache = CachedSession(
934+
cache_name=f"{get_user_cache_dir()}/http_cache_tz",
935+
backend='sqlite',
936+
expire_after=HTTP_CACHE_EXPIRE,
937+
allowable_codes=(200, 203, 300, 301, 308),
938+
timeout=DEFAULT_TIMEOUT,
939+
stale_if_error=True
940+
)
936941
# Mount it for both http and https usage
937942
adapter = TimeoutHTTPAdapter(timeout=DEFAULT_TIMEOUT, max_retries=RETRY_STRATEGY)
938943
http.mount("https://", adapter)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ include_package_data = True
2424
packages = find:
2525
install_requires =
2626
inflect >= 5.3
27-
milc >= 1.6.6
27+
milc >= 1.8.0
2828
packaging >= 20.9
2929
platformdirs >= 2.4
3030
pygments >= 2.11

0 commit comments

Comments
 (0)