python-doniclient 1.0.4__tar.gz → 1.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. python_doniclient-1.2.1/.github/dependabot.yml +7 -0
  2. python_doniclient-1.2.1/.github/workflows/ci.yml +31 -0
  3. python_doniclient-1.2.1/.github/workflows/publish.yml +45 -0
  4. python_doniclient-1.2.1/.stestr.conf +3 -0
  5. python_doniclient-1.2.1/.vscode/launch.json +29 -0
  6. python_doniclient-1.2.1/.vscode/settings.json +10 -0
  7. python_doniclient-1.2.1/AUTHORS +12 -0
  8. python_doniclient-1.2.1/CONTRIBUTING.md +14 -0
  9. python_doniclient-1.2.1/ChangeLog +191 -0
  10. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/PKG-INFO +4 -1
  11. python_doniclient-1.2.1/doniclient/tests/__init__.py +0 -0
  12. python_doniclient-1.2.1/doniclient/tests/osc/__init__.py +0 -0
  13. python_doniclient-1.2.1/doniclient/tests/osc/fakes.py +65 -0
  14. python_doniclient-1.2.1/doniclient/tests/osc/test_hardware.py +337 -0
  15. python_doniclient-1.2.1/doniclient/tests/v1/__init__.py +0 -0
  16. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/pyproject.toml +12 -5
  17. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/python_doniclient.egg-info/PKG-INFO +4 -1
  18. python_doniclient-1.2.1/python_doniclient.egg-info/SOURCES.txt +35 -0
  19. python_doniclient-1.2.1/python_doniclient.egg-info/not-zip-safe +1 -0
  20. python_doniclient-1.2.1/python_doniclient.egg-info/pbr.json +1 -0
  21. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/setup.cfg +3 -0
  22. python_doniclient-1.2.1/setup.py +3 -0
  23. python_doniclient-1.2.1/tox.ini +18 -0
  24. python_doniclient-1.0.4/python_doniclient.egg-info/SOURCES.txt +0 -16
  25. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/README.md +0 -0
  26. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/__init__.py +0 -0
  27. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/osc/__init__.py +0 -0
  28. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/osc/availability.py +0 -0
  29. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/osc/cli.py +0 -0
  30. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/osc/common.py +0 -0
  31. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/osc/plugin.py +0 -0
  32. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/v1/client.py +0 -0
  33. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/doniclient/v1/resource_fields.py +0 -0
  34. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/python_doniclient.egg-info/dependency_links.txt +0 -0
  35. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/python_doniclient.egg-info/entry_points.txt +0 -0
  36. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/python_doniclient.egg-info/requires.txt +0 -0
  37. {python_doniclient-1.0.4 → python_doniclient-1.2.1}/python_doniclient.egg-info/top_level.txt +0 -0
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ # Maintain dependencies for GitHub Actions
4
+ - package-ecosystem: "github-actions"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "monthly"
@@ -0,0 +1,31 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - 'chameleoncloud/*'
7
+ pull_request:
8
+ workflow_call:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ test:
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version:
19
+ - "3.9"
20
+ - "3.10"
21
+ - "3.11"
22
+ - "3.12"
23
+ name: Python ${{ matrix.python-version }}
24
+ runs-on: ubuntu-24.04
25
+ steps:
26
+ - uses: actions/checkout@v7
27
+ - uses: actions/setup-python@v6
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ - run: python -m pip install tox
31
+ - run: tox -e py
@@ -0,0 +1,45 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ uses: ./.github/workflows/ci.yml
13
+
14
+ build:
15
+ needs: test
16
+ runs-on: ubuntu-24.04
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ with:
20
+ # pbr takes the version from the release tag, so it needs tags
21
+ fetch-depth: 0
22
+ - uses: actions/setup-python@v6
23
+ with:
24
+ python-version: "3.12"
25
+ - run: python -m pip install build
26
+ - run: python -m build
27
+ - uses: actions/upload-artifact@v7
28
+ with:
29
+ name: python-package-distributions
30
+ path: dist/
31
+
32
+ publish:
33
+ needs: build
34
+ runs-on: ubuntu-24.04
35
+ environment:
36
+ name: pypi
37
+ url: https://pypi.org/p/python-doniclient
38
+ permissions:
39
+ id-token: write
40
+ steps:
41
+ - uses: actions/download-artifact@v8
42
+ with:
43
+ name: python-package-distributions
44
+ path: dist/
45
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,3 @@
1
+ [DEFAULT]
2
+ test_path=${TESTS_DIR:-./doniclient/tests}
3
+ top_dir=./
@@ -0,0 +1,29 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Debug Unit Test",
9
+ "type": "python",
10
+ "request": "launch",
11
+ "purpose": ["debug-test"],
12
+ "justMyCode": false,
13
+ },
14
+ {
15
+ "name": "Hardware List",
16
+ "type": "python",
17
+ "request": "launch",
18
+ "cwd": "${workspaceFolder}",
19
+ "program": ".venv/bin/openstack",
20
+ "args": [
21
+ "hardware",
22
+ "list",
23
+ "--long"
24
+ ],
25
+ "justMyCode": false,
26
+ "envFile": "${workspaceFolder}/debug.env",
27
+ },
28
+ ]
29
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "python.testing.unittestArgs": [
3
+ "-v",
4
+ "-s",
5
+ "./doniclient",
6
+ "-p",
7
+ "test*.py"
8
+ ],
9
+ "python.testing.unittestEnabled": true,
10
+ }
@@ -0,0 +1,12 @@
1
+ Anish Reddy <2anishreddy@gmail.com>
2
+ Anish Reddy Ravula <2anishreddy@gmail.com>
3
+ Jason <diurnalist@gmail.com>
4
+ Jason Anderson <796413+diurnalist@users.noreply.github.com>
5
+ Jason Anderson <jasonanderson@uchicago.edu>
6
+ Mark Powers <markpowers@uchicago.edu>
7
+ Michael Sherman <shermanm@uchicago.edu>
8
+ Mike <msherman64@gmail.com>
9
+ Mike <shermanm@uchicago.edu>
10
+ Soufiane Jounaid <38963565+JOUNAIDSoufiane@users.noreply.github.com>
11
+ dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
12
+ github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@@ -0,0 +1,14 @@
1
+ # Contributing
2
+
3
+ ## Testing
4
+
5
+ Run the tests using `tox -e py`
6
+
7
+
8
+ ## Publishing new versions
9
+
10
+ Releases are published to PyPI by the [publish workflow](.github/workflows/publish.yml), using PyPI trusted publishing. The version comes from the git tag (via pbr), so there is no version to edit before releasing.
11
+
12
+ To release, create a GitHub release with a new tag named `vX.Y.Z`, and set its target to the branch you are releasing from. Publishing the release runs the tests, builds the package and uploads it to PyPI.
13
+
14
+ Use tags like `v1.1.0rc1` for pre-releases. GitHub's pre-release checkbox doesn't change the version uploaded to PyPI.
@@ -0,0 +1,191 @@
1
+ CHANGES
2
+ =======
3
+
4
+ v1.2.1
5
+ ------
6
+
7
+ * version from git tags
8
+ * Wip/cleanup ci publish (#121)
9
+ * ci: publish stestr results as junit
10
+ * ci: test python 3.10 through 3.12
11
+ * ci: run unit tests in a python version matrix
12
+ * Bump actions/checkout from 6 to 7
13
+
14
+ v1.2.0
15
+ ------
16
+
17
+ * bump requirements and python for 2025.1
18
+
19
+ v1.1.0
20
+ ------
21
+
22
+ * bump requirements and python for 2024.1
23
+
24
+ v1.0.4
25
+ ------
26
+
27
+ * add publish workflow
28
+ * clean up CI noise
29
+ * feat: remove poetry, update deps and tox
30
+ * Soufianej pyyaml upgrade to fix python sources build error (#110)
31
+ * Unset feature (#105)
32
+ * refactor of prop\_flag\_group (#108)
33
+ * Update the readme with the command usage
34
+ * hardware list to show last\_error from each worker
35
+ * add "name\_or\_uuid" support to "sync" command
36
+ * fix ordering of worker-task columns (#103)
37
+ * Show and filter by worker\_state and type (#102)
38
+ * Set and delete using name of HW (#100)
39
+ * create set \`mgmt\_addr\` instead of \`management\_address\` in error
40
+ * fix unittest for hardware show
41
+ * [ci] fix configuration for local untitests
42
+ * fix pyyaml dependency issue
43
+ * Bump up version to 5.6.2 for xena constraints (#99)
44
+
45
+ v1.0.3
46
+ ------
47
+
48
+ * bump version for release
49
+ * ensure CI checks are useful (#87)
50
+ * allow setting local egress property for devices (#85)
51
+ * Add test cases for "hardware set"
52
+ * update formatter
53
+ * bump release version
54
+ * add --long flag to list all columns
55
+ * add vscode debug config
56
+ * Update python to 3.7 minimum, neeeded fpo xena
57
+ * upgrade dependencies for xena
58
+ * allow retrieval of infomation by name (#57)
59
+ * 0.5.2
60
+ * fix bug w/ patch command
61
+
62
+ v0.5.1
63
+ ------
64
+
65
+ * 0.5.1
66
+ * fixup hardware type parsing
67
+ * add contributor guide
68
+
69
+ v0.5.0
70
+ ------
71
+
72
+ * 0.5.0
73
+ * Add support for device hwtype
74
+ * bump version
75
+ * ensure 'set' takes a uuid
76
+ * Allow json input of arbitrary arguments, refactor cli (#49)
77
+ * rename package to python-doniclient (#48)
78
+ * hotfix release, syntax error in cli.py
79
+
80
+ v0.4.0
81
+ ------
82
+
83
+ * 0.4.0
84
+ * add support for setting deploy kernel and ramdisk
85
+ * allow import to continue on conflict
86
+ * fix properties path and delete logic for update
87
+
88
+ v0.3.0
89
+ ------
90
+
91
+ * 0.3.0
92
+ * Apply suggestions from code review
93
+ * Change workers column to use yaml formatter
94
+ * Fix parameter formatting
95
+ * Add workers to serializer if exists in data
96
+
97
+ v0.2.5
98
+ ------
99
+
100
+ * 0.2.5
101
+ * Invert openstack constraints
102
+
103
+ v0.2.4
104
+ ------
105
+
106
+ * 0.2.4
107
+ * Make hardware formatter generic
108
+ * Format properties field in a nicer way
109
+ * Add dependency on PyYAML
110
+ * Fix listing of own hardware
111
+
112
+ v0.2.3
113
+ ------
114
+
115
+ * Bugfix/ci (#12)
116
+
117
+ v0.2.2
118
+ ------
119
+
120
+ * add author and bump version
121
+ * add extra network info keys to interface command
122
+
123
+ v0.2.1
124
+ ------
125
+
126
+ * 0.2.1
127
+ * Fix bug with hardware create
128
+
129
+ v0.2.0
130
+ ------
131
+
132
+ * 0.2.0
133
+ * Add sub commands for managing availability windows
134
+ * Move \_format\_iface
135
+ * quickfix to add upper-constraint behavior
136
+ * add description
137
+
138
+ v0.1.4
139
+ ------
140
+
141
+ * 0.1.4
142
+ * Downgrade to Train release versions
143
+ * Bugfix/initial release (#6)
144
+ * make dependabot less chatty
145
+
146
+ v0.1.1
147
+ ------
148
+
149
+ * 0.1.1
150
+ * Use requirements from Train release
151
+
152
+ v0.1
153
+ ----
154
+
155
+ * update create helptext
156
+ * fix creation of availability windows
157
+ * add tz to parsed dates
158
+ * add more update parser robustness
159
+ * handle edge cases for update
160
+ * add date parsing to update method
161
+ * clean up help and parsing for windows
162
+ * add dateutil dependency
163
+ * add delete and sync, some refactoring
164
+ * add syc call
165
+ * add delete call
166
+ * improve handling of iface updates
167
+ * fix handling of top level variables
168
+ * add handling for interface list
169
+ * update calls succeed for subset of fields (#3)
170
+ * add bits for jsonpatch
171
+ * handle dry run
172
+ * create hardware works
173
+ * add create function
174
+ * removed osc\_lib.api due to url parsing issues
175
+ * list and export work, find has a weird http/s bug
176
+ * separate osc client and doni client
177
+ * change create name
178
+ * get single works
179
+ * use command.Lister for standard output formatting
180
+ * fix auth and implement list and export
181
+ * add unittest stubs for methods
182
+ * add openstackclient as extras dep
183
+ * add osc entrypoints
184
+ * rename files following ironicclient
185
+ * Add openstack client deps
186
+ * add lint and test settings
187
+ * Bump pytest from 5.4.3 to 6.2.2 (#1)
188
+ * add gh actions
189
+ * add dev dependencies
190
+ * inital commit
191
+ * Initial commit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-doniclient
3
- Version: 1.0.4
3
+ Version: 1.2.1
4
4
  Summary: This is a plugin for the openstack commandline client, to enable support for the Doni hardware inventory project
5
5
  Author-email: Chameleon Cloud <contact@chameleoncloud.org>
6
6
  License-Expression: Apache-2.0
@@ -11,6 +11,9 @@ Classifier: Intended Audience :: System Administrators
11
11
  Classifier: Operating System :: POSIX :: Linux
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
14
17
  Requires-Python: >=3.9
15
18
  Description-Content-Type: text/markdown
16
19
  Requires-Dist: osc-lib
File without changes
@@ -0,0 +1,65 @@
1
+ """Define fake objects for Doni CLI tests."""
2
+
3
+ import copy
4
+ import datetime
5
+ import uuid
6
+ from unittest import mock
7
+
8
+ from openstackclient.tests.unit import fakes, utils
9
+
10
+ hardware_uuid = uuid.uuid4().hex
11
+ hardware_name = "fake name"
12
+ hardware_project_id = uuid.uuid4().hex
13
+ hardware_created_at = datetime.datetime.utcnow().isoformat()
14
+ hardware_updated_at = datetime.datetime.utcnow().isoformat()
15
+ hardware_baremetal_type = "baremetal"
16
+
17
+
18
+ class FakeHardware(object):
19
+ @staticmethod
20
+ def create_one_hardware(attrs=None):
21
+ """Create a fake hw item."""
22
+ attrs = attrs or {}
23
+
24
+ hw_info = {
25
+ "created_at": hardware_created_at,
26
+ "hardware_type": hardware_baremetal_type,
27
+ "name": hardware_name,
28
+ "project_id": hardware_project_id,
29
+ "properties": {},
30
+ "updated_at": hardware_updated_at,
31
+ "uuid": hardware_uuid,
32
+ "workers": [],
33
+ }
34
+
35
+ hw_info.update(attrs)
36
+ # TODO: client currently returns Dicts, not Resource objects.
37
+ # hw_item = fakes.FakeResource(info=copy.deepcopy(hw_info), loaded=True)
38
+ return hw_info
39
+
40
+ def create_one_worker(worker_type="", worker_state=""):
41
+ worker = {
42
+ "state": worker_state,
43
+ "state_details": {},
44
+ "worker_type": worker_type,
45
+ }
46
+ return worker
47
+
48
+
49
+ class FakeHardwareClient(object):
50
+ def __init__(self, **kwargs) -> None:
51
+ self.hardware = mock.Mock()
52
+ self.hardware.resource_class = fakes.FakeResource(None, {})
53
+
54
+
55
+ class TestHardware(utils.TestCommand):
56
+ def setUp(self):
57
+ super(TestHardware, self).setUp()
58
+
59
+ self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN")
60
+ self.app.client_manager.inventory = mock.Mock()
61
+
62
+
63
+ class FakeHardwareResource(fakes.FakeResource):
64
+ def get_keys(self):
65
+ return {"property": "value"}
@@ -0,0 +1,337 @@
1
+ from doniclient.osc import cli as hardware_cli
2
+ from doniclient.tests.osc import fakes as hardware_fakes
3
+ from osc_lib import utils as oscutils
4
+ from osc_lib import exceptions
5
+ import unittest
6
+
7
+ FAKE_HARDWARE_UUID = hardware_fakes.hardware_uuid
8
+ FAKE_HARDWARE_NAME = hardware_fakes.hardware_name
9
+
10
+ UPDATE_PARAMS = [
11
+ (
12
+ "baremetal",
13
+ "--management_address",
14
+ "management_address",
15
+ "/properties/management_address",
16
+ "fake-mgmt_addr",
17
+ True,
18
+ ),
19
+ (
20
+ "device",
21
+ "--machine-name",
22
+ "machine_name",
23
+ "/properties/machine_name",
24
+ "jetson-nano",
25
+ False,
26
+ ),
27
+ (
28
+ "device",
29
+ "--contact-email",
30
+ "contact_email",
31
+ "/properties/contact_email",
32
+ "test@foo.bar",
33
+ True,
34
+ ),
35
+ (
36
+ "device",
37
+ "--local-egress",
38
+ "local_egress",
39
+ "/properties/local_egress",
40
+ "allow",
41
+ False,
42
+ ),
43
+ ]
44
+
45
+
46
+ class TestHardware(hardware_fakes.TestHardware):
47
+ def setUp(self):
48
+ super(TestHardware, self).setUp()
49
+
50
+ # Get a shortcut to the baremetal manager mock
51
+ self.hardware_mock = self.app.client_manager.inventory
52
+ self.hardware_mock.reset_mock()
53
+
54
+
55
+ class TestHardwareShow(TestHardware):
56
+ def setUp(self):
57
+ super().setUp()
58
+
59
+ self.hardware_mock.get.return_value = (
60
+ hardware_fakes.FakeHardware.create_one_hardware()
61
+ )
62
+
63
+ self.hardware_mock.get_by_uuid.return_value = (
64
+ hardware_fakes.FakeHardware.create_one_hardware()
65
+ )
66
+
67
+ self.cmd = hardware_cli.GetHardware(self.app, None)
68
+
69
+ def test_hardware_show(self):
70
+ arglist = [FAKE_HARDWARE_UUID]
71
+ verifylist = []
72
+
73
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
74
+
75
+ # DisplayCommandBase.take_action() returns two tuples
76
+ columns, data = self.cmd.take_action(parsed_args)
77
+
78
+ # Set expected values
79
+ args = [FAKE_HARDWARE_UUID]
80
+
81
+ self.hardware_mock.get.assert_called_with(*args)
82
+
83
+ collist = (
84
+ "created_at",
85
+ "hardware_type",
86
+ "name",
87
+ "project_id",
88
+ "properties",
89
+ "updated_at",
90
+ "uuid",
91
+ "workers",
92
+ )
93
+ self.assertEqual(collist, columns)
94
+
95
+ datalist = (
96
+ hardware_fakes.hardware_created_at,
97
+ hardware_fakes.hardware_baremetal_type,
98
+ hardware_fakes.hardware_name,
99
+ hardware_fakes.hardware_project_id,
100
+ {},
101
+ hardware_fakes.hardware_updated_at,
102
+ hardware_fakes.hardware_uuid,
103
+ [],
104
+ )
105
+ self.assertEqual(datalist, tuple(data))
106
+
107
+
108
+ class TestHardwareList(TestHardware):
109
+ def setUp(self):
110
+ super().setUp()
111
+
112
+ hw1 = hardware_fakes.FakeHardware.create_one_hardware()
113
+ hw1["workers"].append(
114
+ hardware_fakes.FakeHardware.create_one_worker(
115
+ worker_type="blazar", worker_state="PENDING"
116
+ )
117
+ )
118
+ hw1["workers"].append(
119
+ hardware_fakes.FakeHardware.create_one_worker(
120
+ worker_type="ironic", worker_state="STEADY"
121
+ )
122
+ )
123
+ hw2 = hardware_fakes.FakeHardware.create_one_hardware()
124
+ hw2["workers"].append(
125
+ hardware_fakes.FakeHardware.create_one_worker(
126
+ worker_type="ironic", worker_state="PENDING"
127
+ )
128
+ )
129
+ self.hardware_mock.list.return_value = list([hw1, hw2])
130
+ self.cmd = hardware_cli.ListHardware(self.app, None)
131
+
132
+ def test_hardware_list(self):
133
+ arglist = []
134
+ verifylist = []
135
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
136
+
137
+ # DisplayCommandBase.take_action() returns two tuples
138
+ columns, data = self.cmd.take_action(parsed_args)
139
+ self.assertEqual(len(data), 2)
140
+
141
+ expected_args = []
142
+ self.hardware_mock.list.assert_called_with(*expected_args)
143
+
144
+ def test_hardware_list_worker_state_filter(self):
145
+ arglist = ["--worker-state", "PENDING"]
146
+ verifylist = [("worker_state", "PENDING")]
147
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
148
+
149
+ # DisplayCommandBase.take_action() returns two tuples
150
+ columns, data = self.cmd.take_action(parsed_args)
151
+ self.assertEqual(len(data), 2)
152
+
153
+ expected_args = []
154
+ self.hardware_mock.list.assert_called_with(*expected_args)
155
+
156
+ def test_hardware_list_worker_type_filter(self):
157
+ # Test with worker type filter
158
+ arglist = ["--worker-type", "ironic"]
159
+ verifylist = [("worker_type", "ironic")]
160
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
161
+
162
+ columns, data = self.cmd.take_action(parsed_args)
163
+ self.assertEqual(len(data), 2)
164
+
165
+ expected_args = []
166
+ self.hardware_mock.list.assert_called_with(*expected_args)
167
+
168
+ def test_hardware_list_combined_filters(self):
169
+ # Test with both worker type and state filters
170
+ arglist = ["--worker-type", "blazar", "--worker-state", "STEADY"]
171
+ verifylist = [("worker_type", "blazar"), ("worker_state", "STEADY")]
172
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
173
+
174
+ columns, data = self.cmd.take_action(parsed_args)
175
+ self.assertEqual(len(data), 0)
176
+
177
+ expected_args = []
178
+ self.hardware_mock.list.assert_called_with(*expected_args)
179
+
180
+ arglist = ["--worker-type", "blazar", "--worker-state", "PENDING"]
181
+ verifylist = [("worker_type", "blazar"), ("worker_state", "PENDING")]
182
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
183
+
184
+ columns, data = self.cmd.take_action(parsed_args)
185
+ self.assertEqual(len(data), 1)
186
+
187
+ expected_args = []
188
+ self.hardware_mock.list.assert_called_with(*expected_args)
189
+
190
+
191
+ class TestHardwareCreate(TestHardware):
192
+ def setUp(self):
193
+ super().setUp()
194
+ self.cmd = hardware_cli.CreateHardware(self.app, None)
195
+
196
+
197
+ class TestHardwareDelete(TestHardware):
198
+ def setUp(self):
199
+ super().setUp()
200
+ self.cmd = hardware_cli.DeleteHardware(self.app, None)
201
+
202
+ def test_hardware_delete_w_same_name(self):
203
+ # When delete when more than two resources exist with same name
204
+ arglist = [FAKE_HARDWARE_NAME]
205
+ verifylist = []
206
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
207
+ # get will throw an Exception when used with name
208
+ self.hardware_mock.get.side_effect = Exception
209
+ self.hardware_mock.find.side_effect = Exception
210
+ # return two hardwares with same name
211
+ self.hardware_mock.list.return_value = [
212
+ hardware_fakes.FakeHardware.create_one_hardware(),
213
+ hardware_fakes.FakeHardware.create_one_hardware(),
214
+ ]
215
+ try:
216
+ self.cmd.take_action(parsed_args)
217
+ except exceptions.CommandError as e:
218
+ self.assertEqual(
219
+ e.args[0],
220
+ f"More than one resource exists with the name or ID '{FAKE_HARDWARE_NAME}'.",
221
+ )
222
+
223
+ def test_hardware_delete_w_name(self):
224
+ arglist = [FAKE_HARDWARE_NAME]
225
+ verifylist = []
226
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
227
+ # get will throw an Exception when used with name
228
+ self.hardware_mock.get.side_effect = Exception
229
+ self.hardware_mock.find.side_effect = Exception
230
+ # return two hardwares with same name
231
+ self.hardware_mock.list.return_value = [
232
+ hardware_fakes.FakeHardware.create_one_hardware()
233
+ ]
234
+ self.cmd.take_action(parsed_args)
235
+
236
+ def test_hardware_delete_w_uuid(self):
237
+ arglist = [FAKE_HARDWARE_UUID]
238
+ verifylist = []
239
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
240
+ self.hardware_mock.get.return_value = (
241
+ hardware_fakes.FakeHardware.create_one_hardware()
242
+ )
243
+ self.cmd.take_action(parsed_args)
244
+ self.hardware_mock.delete.assert_called_with(FAKE_HARDWARE_UUID)
245
+
246
+
247
+ class TestHardwareSetMeta(type):
248
+ """Metaclass to generate list of test cases."""
249
+
250
+ def __new__(mcs, name, bases, dict):
251
+ def gen_test(hw_type, arg, prop, path, value, use_name=False):
252
+ def test(self):
253
+ name_or_id = FAKE_HARDWARE_UUID
254
+ self.hardware_mock.get.return_value = (
255
+ hardware_fakes.FakeHardware.create_one_hardware()
256
+ )
257
+ self.hardware_mock.update.return_value = (
258
+ hardware_fakes.FakeHardware.create_one_hardware()
259
+ )
260
+ if use_name:
261
+ name_or_id = FAKE_HARDWARE_NAME
262
+ self.hardware_mock.get.side_effect = Exception
263
+ self.hardware_mock.find.side_effect = Exception
264
+ self.hardware_mock.list.return_value = [
265
+ hardware_fakes.FakeHardware.create_one_hardware()
266
+ ]
267
+ arglist = [
268
+ name_or_id,
269
+ "--hardware_type",
270
+ hw_type,
271
+ arg,
272
+ value,
273
+ ]
274
+ parsed_args = self.check_parser(self.cmd, arglist, [])
275
+ assert parsed_args.properties == {prop: value}
276
+
277
+ self.cmd.take_action(parsed_args)
278
+ # test if the get is called with name
279
+ self.hardware_mock.get.assert_called_with(name_or_id)
280
+ if 'Unset' in name:
281
+ self.hardware_mock.update.assert_called_with(
282
+ FAKE_HARDWARE_UUID, [{"op": "remove", "path": path, "value": value}]
283
+ )
284
+ else:
285
+ self.hardware_mock.update.assert_called_with(
286
+ FAKE_HARDWARE_UUID, [{"op": "add", "path": path, "value": value}]
287
+ )
288
+
289
+ return test
290
+
291
+ for hw_type, arg, prop, path, value, use_name in UPDATE_PARAMS:
292
+ test_name = "test_device_update_%s" % prop
293
+ dict[test_name] = gen_test(
294
+ hw_type, arg, prop, path, value, use_name=use_name
295
+ )
296
+ return type.__new__(mcs, name, bases, dict)
297
+
298
+
299
+ class TestHardwareSet(TestHardware, metaclass=TestHardwareSetMeta):
300
+ def setUp(self):
301
+ super().setUp()
302
+ self.cmd = hardware_cli.UpdateHardware(self.app, None)
303
+
304
+
305
+ class TestHardwareUnset(TestHardware, metaclass=TestHardwareSetMeta):
306
+ def setUp(self):
307
+ super().setUp()
308
+ self.cmd = hardware_cli.UnsetHardware(self.app, None)
309
+
310
+
311
+ class TestHardwareSync(TestHardware):
312
+ def setUp(self):
313
+ super().setUp()
314
+ self.cmd = hardware_cli.SyncHardware(self.app, None)
315
+
316
+ def test_hardware_sync_w_uuid(self):
317
+ arglist = [FAKE_HARDWARE_UUID]
318
+ verifylist = []
319
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
320
+ self.hardware_mock.get.return_value = (
321
+ hardware_fakes.FakeHardware.create_one_hardware()
322
+ )
323
+ self.cmd.take_action(parsed_args)
324
+ self.hardware_mock.sync.assert_called_with(FAKE_HARDWARE_UUID)
325
+
326
+ def test_hardware_sync_w_name(self):
327
+ arglist = [FAKE_HARDWARE_NAME]
328
+ verifylist = []
329
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
330
+ self.hardware_mock.get.side_effect = Exception
331
+ self.hardware_mock.find.side_effect = Exception
332
+ # return two hardwares with same name
333
+ self.hardware_mock.list.return_value = [
334
+ hardware_fakes.FakeHardware.create_one_hardware()
335
+ ]
336
+ self.cmd.take_action(parsed_args)
337
+ self.hardware_mock.sync.assert_called_with(FAKE_HARDWARE_UUID)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-doniclient"
3
- version = "1.0.4"
3
+ dynamic = ["version"]
4
4
  description = "This is a plugin for the openstack commandline client, to enable support for the Doni hardware inventory project"
5
5
  authors = [{ name = "Chameleon Cloud", email = "contact@chameleoncloud.org" }]
6
6
  requires-python = ">=3.9"
@@ -13,6 +13,9 @@ classifiers = [
13
13
  "Operating System :: POSIX :: Linux",
14
14
  "Programming Language :: Python :: 3",
15
15
  "Programming Language :: Python :: 3.9",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
16
19
 
17
20
  ]
18
21
  dependencies = [
@@ -44,16 +47,20 @@ hardware_availability_remove = "doniclient.osc.availability:RemoveHardwareAvaila
44
47
 
45
48
 
46
49
  [dependency-groups]
47
- dev = [
50
+ test = [
48
51
  "oslotest",
49
52
  "python-openstackclient",
50
- "ruff",
51
53
  "stestr",
52
54
  ]
53
55
 
54
56
  [build-system]
55
- requires = ["setuptools>=64"]
56
- build-backend = "setuptools.build_meta"
57
+ requires = ["pbr>=7.1.0"]
58
+ build-backend = "pbr.build"
59
+
60
+ [tool.setuptools]
61
+ # pbr lists every git-tracked file as package data; without this,
62
+ # doniclient/tests ships in the wheel despite the exclude below
63
+ include-package-data = false
57
64
 
58
65
  [tool.setuptools.packages.find]
59
66
  include = ["doniclient*"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-doniclient
3
- Version: 1.0.4
3
+ Version: 1.2.1
4
4
  Summary: This is a plugin for the openstack commandline client, to enable support for the Doni hardware inventory project
5
5
  Author-email: Chameleon Cloud <contact@chameleoncloud.org>
6
6
  License-Expression: Apache-2.0
@@ -11,6 +11,9 @@ Classifier: Intended Audience :: System Administrators
11
11
  Classifier: Operating System :: POSIX :: Linux
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
14
17
  Requires-Python: >=3.9
15
18
  Description-Content-Type: text/markdown
16
19
  Requires-Dist: osc-lib
@@ -0,0 +1,35 @@
1
+ .stestr.conf
2
+ AUTHORS
3
+ CONTRIBUTING.md
4
+ ChangeLog
5
+ README.md
6
+ pyproject.toml
7
+ setup.cfg
8
+ setup.py
9
+ tox.ini
10
+ .github/dependabot.yml
11
+ .github/workflows/ci.yml
12
+ .github/workflows/publish.yml
13
+ .vscode/launch.json
14
+ .vscode/settings.json
15
+ doniclient/__init__.py
16
+ doniclient/osc/__init__.py
17
+ doniclient/osc/availability.py
18
+ doniclient/osc/cli.py
19
+ doniclient/osc/common.py
20
+ doniclient/osc/plugin.py
21
+ doniclient/tests/__init__.py
22
+ doniclient/tests/osc/__init__.py
23
+ doniclient/tests/osc/fakes.py
24
+ doniclient/tests/osc/test_hardware.py
25
+ doniclient/tests/v1/__init__.py
26
+ doniclient/v1/client.py
27
+ doniclient/v1/resource_fields.py
28
+ python_doniclient.egg-info/PKG-INFO
29
+ python_doniclient.egg-info/SOURCES.txt
30
+ python_doniclient.egg-info/dependency_links.txt
31
+ python_doniclient.egg-info/entry_points.txt
32
+ python_doniclient.egg-info/not-zip-safe
33
+ python_doniclient.egg-info/pbr.json
34
+ python_doniclient.egg-info/requires.txt
35
+ python_doniclient.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ {"git_version": "d76a4be", "is_release": false}
@@ -1,3 +1,6 @@
1
+ [metadata]
2
+ name = python-doniclient
3
+
1
4
  [egg_info]
2
5
  tag_build =
3
6
  tag_date = 0
@@ -0,0 +1,3 @@
1
+ import setuptools
2
+
3
+ setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True)
@@ -0,0 +1,18 @@
1
+ [tox]
2
+ minversion = 4.28.0
3
+ envlist = py3
4
+
5
+ [testenv]
6
+ constraints =
7
+ {env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.1}
8
+ dependency_groups =
9
+ test
10
+ commands =
11
+ stestr run {posargs}
12
+
13
+ [testenv:pep8]
14
+ skip_install = true
15
+ deps =
16
+ ruff
17
+ commands =
18
+ ruff check {posargs}
@@ -1,16 +0,0 @@
1
- README.md
2
- pyproject.toml
3
- doniclient/__init__.py
4
- doniclient/osc/__init__.py
5
- doniclient/osc/availability.py
6
- doniclient/osc/cli.py
7
- doniclient/osc/common.py
8
- doniclient/osc/plugin.py
9
- doniclient/v1/client.py
10
- doniclient/v1/resource_fields.py
11
- python_doniclient.egg-info/PKG-INFO
12
- python_doniclient.egg-info/SOURCES.txt
13
- python_doniclient.egg-info/dependency_links.txt
14
- python_doniclient.egg-info/entry_points.txt
15
- python_doniclient.egg-info/requires.txt
16
- python_doniclient.egg-info/top_level.txt