Skip to content

Commit a41c293

Browse files
committed
Merge branch 'release-v5.8.7'
2 parents 2a5ff3f + 5f16e5d commit a41c293

23 files changed

+187
-99
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
netfoundry/_version.py export-subst
2+
src/netfoundry/_version.py export-subst

.github/workflows/main.yml

+15-17
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,21 @@ jobs:
3030

3131
- name: Install dependencies
3232
run: |
33-
python3 -m pip install --upgrade pip
34-
pip3 install build
33+
python -m pip install --upgrade pip
34+
pip install build
3535
3636
- name: Build Package
37-
run: python3 -m build
37+
run: python -m build
3838

39-
- name: Install NetFoundry from build tarball
40-
run: |
41-
pip3 install ./dist/netfoundry-*.tar.gz
39+
- name: Upload Wheel Artifact
40+
uses: actions/upload-artifact@v3
41+
with:
42+
name: netfoundry-wheel-${{ github.run_id }}
43+
path: dist/netfoundry-*.whl
44+
if-no-files-found: error
45+
46+
- name: Install Wheel
47+
run: pip install dist/netfoundry-*.whl
4248

4349
- name: Read version string
4450
id: read_version
@@ -65,18 +71,17 @@ jobs:
6571
run: |
6672
register-python-argcomplete nfctl
6773
68-
- name: Run the demo script and NF CLI to smoke test installed version
74+
- name: Run the NF CLI demo to test installed version
6975
env:
70-
NETWORK_NAME: github_smoketest_run${{ github.run_id }}
7176
NETFOUNDRY_CLIENT_ID: ${{ secrets.NETFOUNDRY_CLIENT_ID }}
7277
NETFOUNDRY_PASSWORD: ${{ secrets.NETFOUNDRY_PASSWORD }}
7378
NETFOUNDRY_OAUTH_URL: ${{ secrets.NETFOUNDRY_OAUTH_URL }}
7479
run: |
7580
set -x
7681
nfctl config \
77-
general.network=${NETWORK_NAME} \
82+
general.network=$(nfctl demo --echo-name --prefix 'gh-${{ github.run_id }}') \
7883
general.yes=True \
79-
general.verbose=yes || true # workaround https://github.com/netfoundry/python-netfoundry/issues/29
84+
general.verbose=yes
8085
nfctl demo \
8186
--regions us-west-2 us-east-2 \
8287
--provider AWS
@@ -98,13 +103,6 @@ jobs:
98103
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
99104
repository_url: https://test.pypi.org/legacy/
100105

101-
- name: Temporarily Store the Python Package in GitHub # for convenient reference, troubleshooting, investigation, etc...
102-
uses: actions/upload-artifact@v3
103-
with:
104-
name: netfoundry-pypi-${{ github.run_id }}
105-
path: dist/netfoundry-*.tar.gz
106-
if-no-files-found: error
107-
108106
- name: Append 'latest' tag if release
109107
env:
110108
GITHUB_EVENT_ACTION: ${{ github.event.action }}

MANIFEST.in

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
exclude Dockerfile
1+
exclude docker/
22
exclude .gitignore
3-
exclude .github/workflows/*include versioneer.py
4-
include netfoundry/_version.py
3+
exclude .github/workflows/*
54
include versioneer.py
5+
include netfoundry/_version.py
File renamed without changes.
File renamed without changes.

netfoundry/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@
1111
exit(1)
1212

1313
__version__ = _version.get_versions()['version']
14+
15+
from . import _version
16+
__version__ = _version.get_versions()['version']

netfoundry/_version.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# that just contains the computed version number.
77

88
# This file is released into the public domain. Generated by
9-
# versioneer-0.21 (https://github.com/python-versioneer/python-versioneer)
9+
# versioneer-0.22 (https://github.com/python-versioneer/python-versioneer)
1010

1111
"""Git implementation of _version.py."""
1212

@@ -16,6 +16,7 @@
1616
import subprocess
1717
import sys
1818
from typing import Callable, Dict
19+
import functools
1920

2021

2122
def get_keywords():
@@ -73,14 +74,22 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
7374
"""Call the given command(s)."""
7475
assert isinstance(commands, list)
7576
process = None
77+
78+
popen_kwargs = {}
79+
if sys.platform == "win32":
80+
# This hides the console window if pythonw.exe is used
81+
startupinfo = subprocess.STARTUPINFO()
82+
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
83+
popen_kwargs["startupinfo"] = startupinfo
84+
7685
for command in commands:
7786
try:
7887
dispcmd = str([command] + args)
7988
# remember shell=False, so use git.cmd on windows, not just git
8089
process = subprocess.Popen([command] + args, cwd=cwd, env=env,
8190
stdout=subprocess.PIPE,
8291
stderr=(subprocess.PIPE if hide_stderr
83-
else None))
92+
else None), **popen_kwargs)
8493
break
8594
except OSError:
8695
e = sys.exc_info()[1]
@@ -228,10 +237,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
228237
version string, meaning we're inside a checked out source tree.
229238
"""
230239
GITS = ["git"]
231-
TAG_PREFIX_REGEX = "*"
232240
if sys.platform == "win32":
233241
GITS = ["git.cmd", "git.exe"]
234-
TAG_PREFIX_REGEX = r"\*"
242+
243+
# GIT_DIR can interfere with correct operation of Versioneer.
244+
# It may be intended to be passed to the Versioneer-versioned project,
245+
# but that should not change where we get our version from.
246+
env = os.environ.copy()
247+
env.pop("GIT_DIR", None)
248+
runner = functools.partial(runner, env=env)
235249

236250
_, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root,
237251
hide_stderr=True)
@@ -240,12 +254,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
240254
print("Directory %s not under git control" % root)
241255
raise NotThisMethod("'git rev-parse --git-dir' returned error")
242256

257+
MATCH_ARGS = ["--match", "%s*" % tag_prefix] if tag_prefix else []
258+
243259
# if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
244260
# if there isn't one, this yields HEX[-dirty] (no NUM)
245261
describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty",
246-
"--always", "--long",
247-
"--match",
248-
"%s%s" % (tag_prefix, TAG_PREFIX_REGEX)],
262+
"--always", "--long", *MATCH_ARGS],
249263
cwd=root)
250264
# --long was added in git-1.5.5
251265
if describe_out is None:

netfoundry/ctl.py

+37-13
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def main(cli):
102102

103103

104104
@cli.argument('-e', '--eval', help="source or eval output to configure shell environment with a login token", arg_only=True, action="store_true", default=False)
105-
@cli.subcommand('login to a management API')
105+
@cli.subcommand('login to NetFoundry with a user token or API account credentials')
106106
def login(cli):
107107
"""Login to an API and cache the expiring token."""
108108
# if logging in to a NF org (default)
@@ -174,15 +174,35 @@ def login(cli):
174174
else:
175175
cli.echo(json_dumps(summary_object, indent=4))
176176
else: # if eval
177+
nonf = """
178+
# helper function logs out from NetFoundry
179+
function nonf(){
180+
unset NETFOUNDRY_API_ACCOUNT NETFOUNDRY_API_TOKEN \
181+
NETFOUNDRY_CLIENT_ID NETFOUNDRY_PASSWORD NETFOUNDRY_OAUTH_URL \
182+
NETFOUNDRY_ORGANIZATION NETFOUNDRY_NETWORK NETFOUNDRY_NETWORK_GROUP \
183+
MOPENV MOPURL
184+
}
185+
"""
186+
noaws = """
187+
# helper function logs out from AWS
188+
function noaws(){
189+
unset AWS_SECURITY_TOKEN AWS_SESSION_TOKEN \
190+
AWS_ACCESS_KEY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY \
191+
AWS_REGION AWS_DEFAULT_REGION AWS_SHARED_CREDENTIALS_FILE
192+
}
193+
"""
177194
token_env = f"""
178-
# $ eval "$({cli.prog_name} --credentials=credentials.json login --eval)"
195+
# $ eval "$({cli.prog_name} --credentials={organization.credentials} login --eval)"
179196
export NETFOUNDRY_API_TOKEN="{organization.token}"
180197
export NETFOUNDRY_API_ACCOUNT="{organization.credentials if hasattr(organization, 'credentials') else ''}"
181198
export NETFOUNDRY_ORGANIZATION="{organization.id}"
182-
{'export NETFOUNDRY_NETWORK="'+network.id+'"' if network else ''}
183-
{'export NETFOUNDRY_NETWORK_GROUP="'+network_group.id+'"' if network_group else ''}
184-
{'export MOPENV="'+organization.environment+'"' if organization.environment else ''}
199+
{'export NETFOUNDRY_NETWORK="'+network.id+'"' if network else '# NETFOUNDRY_NETWORK'}
200+
{'export NETFOUNDRY_NETWORK_GROUP="'+network_group.id+'"' if network_group else '# NETFOUNDRY_NETWORK_GROUP'}
201+
export MOPENV="{organization.environment}"
202+
export MOPURL="{organization.audience}"
185203
eval "$(register-python-argcomplete {cli.prog_name})"
204+
{nonf}
205+
{noaws}
186206
"""
187207
if cli.config.general.color:
188208
highlighted = highlight(token_env, bash_lexer, Terminal256Formatter(style=cli.config.general.style))
@@ -191,7 +211,7 @@ def login(cli):
191211
cli.echo(token_env)
192212

193213

194-
@cli.subcommand('logout current profile from an organization')
214+
@cli.subcommand('logout your identity for the current current profile')
195215
def logout(cli):
196216
"""Logout by deleting the cached token."""
197217
spinner = get_spinner("working")
@@ -346,7 +366,7 @@ def edit(cli):
346366
@cli.argument('-k', '--keys', arg_only=True, action=StoreListKeys, help="list of keys as a,b,c to print only selected keys (columns)")
347367
@cli.argument('-a', '--as', dest='accept', arg_only=True, choices=['create'], help="request the as=create alternative form of the resource")
348368
@cli.argument('resource_type', arg_only=True, help='type of resource', metavar="RESOURCE_TYPE", choices=[choice for group in [[singular(type), RESOURCES[type].abbreviation] for type in RESOURCES.keys()] for choice in group])
349-
@cli.subcommand('get a single resource by query')
369+
@cli.subcommand('get a single resource by type and query')
350370
def get(cli, echo: bool = True, embed='all', spinner: object = None):
351371
"""
352372
Get a single resource as YAML or JSON.
@@ -358,7 +378,7 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
358378
cli.args.resource_type = singular(RESOURCE_ABBREV[cli.args.resource_type].name)
359379
if not cli.config.general.verbose and cli.args.output in ["yaml", "json"]: # don't change level if output=text
360380
cli.log.setLevel(logging.WARN) # don't emit INFO messages to stdout because they will break deserialization
361-
if cli.args.accept and not MUTABLE_NET_RESOURCES.get(cli.args.resource_type):
381+
if cli.args.accept and not MUTABLE_NET_RESOURCES.get(plural(cli.args.resource_type)):
362382
logging.warning("ignoring --as=create becuase it is applicable only to mutable resources in the network domain")
363383
cli.args['accept'] = None
364384
match = {}
@@ -530,7 +550,7 @@ def get(cli, echo: bool = True, embed='all', spinner: object = None):
530550
@cli.argument('-m', '--my-roles', arg_only=True, action='store_true', help="filter roles by caller identity")
531551
@cli.argument('-a', '--as', dest='accept', arg_only=True, choices=['create'], help="request the as=create alternative form of the resources")
532552
@cli.argument('resource_type', arg_only=True, help='type of resource', metavar="RESOURCE_TYPE", choices=[choice for group in [[type, RESOURCES[type].abbreviation] for type in RESOURCES.keys()] for choice in group])
533-
@cli.subcommand(description='find resources as lists')
553+
@cli.subcommand(description='find a collection of resources by type and query')
534554
def list(cli, spinner: object = None):
535555
"""Find resources as lists."""
536556
if not spinner:
@@ -662,7 +682,7 @@ def list(cli, spinner: object = None):
662682

663683
@cli.argument('query', arg_only=True, action=StoreDictKeyPair, nargs='?', help="query params as k=v,k=v comma-separated pairs")
664684
@cli.argument('resource_type', arg_only=True, help='type of resource', choices=[choice for group in [[singular(type), RESOURCES[type].abbreviation] for type in RESOURCES.keys()] for choice in group])
665-
@cli.subcommand('delete a resource in the network domain')
685+
@cli.subcommand('delete a single resource by type and query')
666686
def delete(cli):
667687
"""Delete a resource in the network domain."""
668688
spinner = get_spinner("working")
@@ -747,7 +767,8 @@ def delete(cli):
747767

748768

749769
@cli.argument("-p", "--prefix", default=f"{cli.prog_name}-demo", help="choose a network name prefix to identify all of your demos")
750-
@cli.argument("-j", "--jwt", action="store_boolean", default=True, help="save the one-time enroll token for each demo identity in the current directory")
770+
@cli.argument("-j", "--jwt", action="store_boolean", default=True, help="save the one-time enroll token for each demo identity in the current directory")
771+
@cli.argument("-e", "--echo-name", arg_only=True, action="store_true", default=False, help="only echo a friendly network name then exit")
751772
@cli.argument("-s", "--size", default="small", help=argparse.SUPPRESS) # troubleshoot scale-up instance size factor
752773
@cli.argument("-v", "--product-version", default="default", help="network product version: 'default', 'latest', or any active semver")
753774
@cli.argument("--provider", default="AWS", help="cloud provider for hosted edge routers", choices=DC_PROVIDERS)
@@ -761,11 +782,14 @@ def demo(cli):
761782
if cli.config.general.network:
762783
network_name = cli.config.general.network
763784
else:
764-
resources_dir = path.join(path.dirname(__file__), 'resources')
765-
friendly_words_filename = path.join(resources_dir, "friendly-words/generated/words.json")
785+
friendly_words_dir = path.join(path.dirname(__file__), 'friendly-words')
786+
friendly_words_filename = path.join(friendly_words_dir, "generated/words.json")
766787
with open(friendly_words_filename, 'r') as friendly_words_path:
767788
friendly_words = json_load(friendly_words_path)
768789
network_name = f"{cli.config.demo.prefix}-{choice(friendly_words['predicates'])}-{choice(friendly_words['objects'])}"
790+
if cli.args.echo_name:
791+
cli.echo(network_name)
792+
sysexit(0)
769793
demo_confirmed = False
770794
if cli.config.general.yes:
771795
demo_confirmed = True

pyproject.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# pyproject.toml
22
[build-system]
3-
requires = ["setuptools>=45", "wheel", "versioneer>=0.21"]
3+
requires = [
4+
"setuptools >= 61",
5+
"wheel >= 0.37",
6+
"versioneer >= 0.22"
7+
]
48

setup.cfg

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,54 @@
1+
[metadata]
2+
name = netfoundry
3+
project_urls =
4+
Documentation = https://developer.netfoundry.io/guides/python/
5+
Source = https://github.com/netfoundry/python-netfoundry/
6+
Tracker = https://github.com/netfoundry/python-netfoundry/issues
7+
8+
description = Interface to the NetFoundry network-as-code orchestration platform
9+
long_description = file: README.md
10+
long_description_content_type = text/markdown
11+
license = MIT
12+
author = Kenneth Bingham
13+
author_email = [email protected]
14+
maintainer = NetFoundry
15+
maintainer_email = [email protected]
16+
classifiers =
17+
Programming Language :: Python :: 3
18+
Operating System :: OS Independent
19+
20+
[options]
21+
python_requires = >=3.7
22+
zip_safe = False
23+
include_package_data = True
24+
packages = find:
25+
install_requires =
26+
inflect >= 5.3
27+
milc >= 1.6.6
28+
packaging >= 20.9
29+
platformdirs >= 2.4
30+
pygments >= 2.11
31+
pyjwt >= 2.3
32+
pyyaml >= 5.4
33+
requests >= 2.27
34+
tabulate >= 0.8
35+
setup_requires =
36+
setuptools_scm
37+
38+
[bdist_wheel]
39+
universal = 1
40+
41+
[options.package_data]
42+
netfoundry = friendly-words/generated/words.json
43+
44+
[options.entry_points]
45+
console_scripts =
46+
nfdemo = netfoundry.demo:main
47+
nfctl = netfoundry.ctl:cli
48+
149
[versioneer]
250
VCS = git
351
style = pep440-pre
452
versionfile_source = netfoundry/_version.py
553
versionfile_build = netfoundry/_version.py
654
tag_prefix = v
7-
#parentdir_prefix = myproject-

setup.py

+5-39
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,8 @@
22
import versioneer
33
import setuptools
44

5-
with open("README.md", "r") as fh:
6-
long_description = fh.read()
7-
8-
setuptools.setup(
9-
name='netfoundry',
10-
py_modules=['netfoundry'],
11-
version=versioneer.get_version(),
12-
cmdclass=versioneer.get_cmdclass(),
13-
url='https://developer.netfoundry.io/guides/python/',
14-
description='Interface to the NetFoundry network-as-code orchestration Platform',
15-
long_description=long_description,
16-
long_description_content_type="text/markdown",
17-
license='MIT',
18-
author='Kenneth Bingham',
19-
author_email='[email protected]',
20-
packages=setuptools.find_packages(),
21-
python_requires='>=3.7',
22-
classifiers=[
23-
"Programming Language :: Python :: 3",
24-
"Operating System :: OS Independent",
25-
],
26-
install_requires=[
27-
'requests >= 2.27',
28-
'pyjwt >= 2.3',
29-
'inflect >= 5.3',
30-
'milc >= 1.6.6',
31-
'pyyaml >= 5.4',
32-
'platformdirs >= 2.4',
33-
'tabulate >= 0.8',
34-
'packaging >= 20.9',
35-
'pygments >= 2.11'
36-
],
37-
entry_points={
38-
'console_scripts': [
39-
'nfdemo = netfoundry.demo:main',
40-
'nfctl = netfoundry.ctl:cli',
41-
]
42-
}
43-
)
5+
if __name__ == "__main__":
6+
setuptools.setup(
7+
version=versioneer.get_version(),
8+
cmdclass=versioneer.get_cmdclass(),
9+
)

0 commit comments

Comments
 (0)