sysbot 0.2.2__tar.gz → 0.2.3__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 (82) hide show
  1. {sysbot-0.2.2 → sysbot-0.2.3}/PKG-INFO +1 -2
  2. {sysbot-0.2.2 → sysbot-0.2.3}/setup.py +0 -1
  3. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/_version.py +3 -3
  4. sysbot-0.2.3/sysbot/modules/container/__init__.py +7 -0
  5. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/dnf.py +21 -5
  6. sysbot-0.2.3/sysbot/modules/virtualization/__init__.py +7 -0
  7. sysbot-0.2.3/sysbot/modules/virtualization/harvester.py +381 -0
  8. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/engine.py +107 -2
  9. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot.egg-info/PKG-INFO +1 -2
  10. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot.egg-info/SOURCES.txt +10 -7
  11. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot.egg-info/requires.txt +0 -1
  12. {sysbot-0.2.2 → sysbot-0.2.3}/.github/workflows/docs.yml +0 -0
  13. {sysbot-0.2.2 → sysbot-0.2.3}/.github/workflows/pypi-publish.yml +0 -0
  14. {sysbot-0.2.2 → sysbot-0.2.3}/.gitignore +0 -0
  15. {sysbot-0.2.2 → sysbot-0.2.3}/CONTRIBUTING.md +0 -0
  16. {sysbot-0.2.2 → sysbot-0.2.3}/LICENSE +0 -0
  17. {sysbot-0.2.2 → sysbot-0.2.3}/MANIFEST.in +0 -0
  18. {sysbot-0.2.2 → sysbot-0.2.3}/README.md +0 -0
  19. {sysbot-0.2.2 → sysbot-0.2.3}/pyproject.toml +0 -0
  20. {sysbot-0.2.2 → sysbot-0.2.3}/setup.cfg +0 -0
  21. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/README.md +0 -0
  22. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/Sysbot.py +0 -0
  23. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/__init__.py +0 -0
  24. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/__init__.py +0 -0
  25. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/http.py +0 -0
  26. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/local.py +0 -0
  27. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/socket.py +0 -0
  28. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/ssh.py +0 -0
  29. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/connectors/winrm.py +0 -0
  30. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/__init__.py +0 -0
  31. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/bmc/__init__.py +0 -0
  32. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/bmc/idrac.py +0 -0
  33. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/bmc/ilo.py +0 -0
  34. {sysbot-0.2.2/sysbot/modules/linux → sysbot-0.2.3/sysbot/modules/container}/kubernetes.py +0 -0
  35. {sysbot-0.2.2/sysbot/modules/linux → sysbot-0.2.3/sysbot/modules/container}/podman.py +0 -0
  36. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/__init__.py +0 -0
  37. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/file.py +0 -0
  38. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/firewalld.py +0 -0
  39. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/ip.py +0 -0
  40. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/iptables.py +0 -0
  41. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/process.py +0 -0
  42. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/rpm.py +0 -0
  43. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/selinux.py +0 -0
  44. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/sysinfo.py +0 -0
  45. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/systemd.py +0 -0
  46. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/linux/users.py +0 -0
  47. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/monitoring/__init__.py +0 -0
  48. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/monitoring/grafana.py +0 -0
  49. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/network/__init__.py +0 -0
  50. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/network/cisco/__init__.py +0 -0
  51. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/network/cisco/catalyst.py +0 -0
  52. {sysbot-0.2.2/sysbot/modules/linux → sysbot-0.2.3/sysbot/modules/virtualization}/libvirt.py +0 -0
  53. {sysbot-0.2.2/sysbot/modules → sysbot-0.2.3/sysbot/modules/virtualization}/vmware/__init__.py +0 -0
  54. {sysbot-0.2.2/sysbot/modules → sysbot-0.2.3/sysbot/modules/virtualization}/vmware/nsx.py +0 -0
  55. {sysbot-0.2.2/sysbot/modules → sysbot-0.2.3/sysbot/modules/virtualization}/vmware/sddcmanager.py +0 -0
  56. {sysbot-0.2.2/sysbot/modules → sysbot-0.2.3/sysbot/modules/virtualization}/vmware/vsphere.py +0 -0
  57. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/__init__.py +0 -0
  58. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/adcs.py +0 -0
  59. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/adds.py +0 -0
  60. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/dnsserver.py +0 -0
  61. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/file.py +0 -0
  62. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/firewall.py +0 -0
  63. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/ip.py +0 -0
  64. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/sysinfo.py +0 -0
  65. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/users.py +0 -0
  66. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/veeam.py +0 -0
  67. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/modules/windows/wsus.py +0 -0
  68. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/plugins/__init__.py +0 -0
  69. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/plugins/ansible.py +0 -0
  70. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/plugins/data.py +0 -0
  71. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/plugins/vault.py +0 -0
  72. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/__init__.py +0 -0
  73. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/helper.py +0 -0
  74. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/__init__.py +0 -0
  75. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/listener/__init__.py +0 -0
  76. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/listener/mongodb.py +0 -0
  77. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/listener/mysql.py +0 -0
  78. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/listener/postgresql.py +0 -0
  79. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/listener/sqlite.py +0 -0
  80. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot/utils/robot/polarion.py +0 -0
  81. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot.egg-info/dependency_links.txt +0 -0
  82. {sysbot-0.2.2 → sysbot-0.2.3}/sysbot.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysbot
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: System test automation library with support for SSH, WinRM, HTTP, databases, and Robot Framework integration
5
5
  Home-page: https://github.com/JoReci2/sysbot
6
6
  Author: Thibault SCIRE
@@ -33,7 +33,6 @@ Description-Content-Type: text/markdown
33
33
  License-File: LICENSE
34
34
  Requires-Dist: robotframework
35
35
  Requires-Dist: paramiko
36
- Requires-Dist: sshtunnel
37
36
  Requires-Dist: netmiko
38
37
  Requires-Dist: redfish
39
38
  Requires-Dist: pywinrm
@@ -26,7 +26,6 @@ setup(
26
26
  install_requires=[
27
27
  "robotframework",
28
28
  "paramiko",
29
- "sshtunnel",
30
29
  "netmiko",
31
30
  "redfish",
32
31
  "pywinrm",
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.2'
32
- __version_tuple__ = version_tuple = (0, 2, 2)
31
+ __version__ = version = '0.2.3'
32
+ __version_tuple__ = version_tuple = (0, 2, 3)
33
33
 
34
- __commit_id__ = commit_id = 'g98ca5fe32'
34
+ __commit_id__ = commit_id = 'gaa9194bbf'
@@ -0,0 +1,7 @@
1
+ """
2
+ Container Modules Package
3
+
4
+ This package provides modules for container platform management, including
5
+ Kubernetes orchestration and Podman container operations, enabling automation
6
+ of containerized workloads and their infrastructure.
7
+ """
@@ -6,7 +6,6 @@ RHEL/Fedora-based Linux systems, including repository management and package
6
6
  operations.
7
7
  """
8
8
  from sysbot.utils.engine import ComponentBase
9
- import json
10
9
  import configparser
11
10
  from io import StringIO
12
11
 
@@ -14,7 +13,7 @@ from io import StringIO
14
13
  class Dnf(ComponentBase):
15
14
  """DNF package manager operations class for RHEL/Fedora-based systems."""
16
15
 
17
- def repolist(self, alias: str, **kwargs) -> dict:
16
+ def repolist(self, alias: str, **kwargs) -> list:
18
17
  """
19
18
  Get list of DNF repositories.
20
19
 
@@ -23,10 +22,27 @@ class Dnf(ComponentBase):
23
22
  **kwargs: Additional command execution options.
24
23
 
25
24
  Returns:
26
- Dictionary containing repository information in JSON format.
25
+ List of dictionaries containing repository information,
26
+ each with 'id' and 'name' keys.
27
27
  """
28
- output = self.execute_command(alias, "dnf repolist --json", **kwargs)
29
- return json.loads(output)
28
+ output = self.execute_command(alias, "dnf repolist", **kwargs)
29
+ repos = []
30
+ # Locate the header line (e.g. "repo id repo name") and parse
31
+ # only the lines that follow it, skipping any metadata lines printed
32
+ # before the table (e.g. "Last metadata expiration check: …").
33
+ header_found = False
34
+ for line in output.splitlines():
35
+ if not header_found:
36
+ if line.lstrip().lower().startswith("repo id"):
37
+ header_found = True
38
+ continue
39
+ line = line.strip()
40
+ if not line:
41
+ continue
42
+ parts = line.split(None, 1)
43
+ if parts:
44
+ repos.append({"id": parts[0], "name": parts[1].strip() if len(parts) > 1 else ""})
45
+ return repos
30
46
 
31
47
  def repofile(self, alias: str, file: str, **kwargs) -> dict:
32
48
  """
@@ -0,0 +1,7 @@
1
+ """
2
+ Virtualization Modules Package
3
+
4
+ This package provides modules for virtualization platform management,
5
+ covering VMware virtualization platforms, libvirt-based virtualization,
6
+ and related virtualization technologies.
7
+ """
@@ -0,0 +1,381 @@
1
+ """
2
+ Harvester Module
3
+
4
+ This module provides methods for interacting with Rancher Harvester HCI (Hyper-Converged Infrastructure)
5
+ via REST API. It supports operations such as virtual machine management, image management,
6
+ volume management, and cluster information retrieval.
7
+
8
+ Note: This module uses the HTTP connector with API Key or Basic authentication.
9
+ Sessions should be opened with protocol="http" and product="apikey" or "basicauth".
10
+ """
11
+
12
+ import json
13
+ from sysbot.utils.engine import ComponentBase
14
+
15
+
16
+ class Harvester(ComponentBase):
17
+ """
18
+ Harvester module for hyper-converged infrastructure management.
19
+
20
+ This class provides methods to interact with Rancher Harvester systems using REST API
21
+ via the HTTP connector with API Key or Basic authentication.
22
+ All methods require an alias to identify the established HTTP session.
23
+
24
+ Example:
25
+ Basic usage with API key authentication::
26
+
27
+ import sysbot
28
+
29
+ bot = sysbot.Sysbot(['modules.virtualization.harvester'])
30
+
31
+ # Open session with API key
32
+ bot.open_session(
33
+ "harvester",
34
+ "http",
35
+ "apikey",
36
+ "harvester.example.com",
37
+ 443,
38
+ apikey="your-api-key-here"
39
+ )
40
+
41
+ # Get cluster version
42
+ version = bot.modules.virtualization.harvester.get_version("harvester")
43
+
44
+ # List virtual machines
45
+ vms = bot.modules.virtualization.harvester.list_virtual_machines("harvester")
46
+
47
+ # Get specific VM
48
+ vm = bot.modules.virtualization.harvester.get_virtual_machine("harvester", "my-vm")
49
+
50
+ bot.close_session("harvester")
51
+ """
52
+
53
+ def _parse_response(self, response):
54
+ """
55
+ Parse HTTP response and decode JSON.
56
+
57
+ Args:
58
+ response: The raw HTTP response bytes.
59
+
60
+ Returns:
61
+ Parsed JSON object (dict or list).
62
+ """
63
+ return json.loads(response.decode())
64
+
65
+ def get_version(self, alias: str, **kwargs) -> dict:
66
+ """
67
+ Get Harvester version information.
68
+
69
+ Args:
70
+ alias (str): The session alias for the Harvester connection.
71
+
72
+ Returns:
73
+ dict: Version information.
74
+ """
75
+ response = self.execute_command(alias, "/v1/harvesterhci.io.settings/server-version", options={"method": "GET"}, **kwargs)
76
+ return self._parse_response(response)
77
+
78
+ def list_virtual_machines(self, alias: str, namespace: str = "default", **kwargs) -> dict:
79
+ """
80
+ List all virtual machines in a namespace.
81
+
82
+ Args:
83
+ alias (str): The session alias for the Harvester connection.
84
+ namespace (str): Kubernetes namespace (default: "default").
85
+
86
+ Returns:
87
+ dict: List of virtual machines.
88
+ """
89
+ response = self.execute_command(
90
+ alias,
91
+ f"/apis/kubevirt.io/v1/namespaces/{namespace}/virtualmachines",
92
+ options={"method": "GET"},
93
+ **kwargs
94
+ )
95
+ return self._parse_response(response)
96
+
97
+ def get_virtual_machine(self, alias: str, name: str, namespace: str = "default", **kwargs) -> dict:
98
+ """
99
+ Get details of a specific virtual machine.
100
+
101
+ Args:
102
+ alias (str): The session alias for the Harvester connection.
103
+ name (str): Virtual machine name.
104
+ namespace (str): Kubernetes namespace (default: "default").
105
+
106
+ Returns:
107
+ dict: Virtual machine details.
108
+ """
109
+ response = self.execute_command(
110
+ alias,
111
+ f"/apis/kubevirt.io/v1/namespaces/{namespace}/virtualmachines/{name}",
112
+ options={"method": "GET"},
113
+ **kwargs
114
+ )
115
+ return self._parse_response(response)
116
+
117
+ def list_vm_instances(self, alias: str, namespace: str = "default", **kwargs) -> dict:
118
+ """
119
+ List all virtual machine instances in a namespace.
120
+
121
+ Args:
122
+ alias (str): The session alias for the Harvester connection.
123
+ namespace (str): Kubernetes namespace (default: "default").
124
+
125
+ Returns:
126
+ dict: List of virtual machine instances.
127
+ """
128
+ response = self.execute_command(
129
+ alias,
130
+ f"/apis/kubevirt.io/v1/namespaces/{namespace}/virtualmachineinstances",
131
+ options={"method": "GET"},
132
+ **kwargs
133
+ )
134
+ return self._parse_response(response)
135
+
136
+ def get_vm_instance(self, alias: str, name: str, namespace: str = "default", **kwargs) -> dict:
137
+ """
138
+ Get details of a specific virtual machine instance.
139
+
140
+ Args:
141
+ alias (str): The session alias for the Harvester connection.
142
+ name (str): Virtual machine instance name.
143
+ namespace (str): Kubernetes namespace (default: "default").
144
+
145
+ Returns:
146
+ dict: Virtual machine instance details.
147
+ """
148
+ response = self.execute_command(
149
+ alias,
150
+ f"/apis/kubevirt.io/v1/namespaces/{namespace}/virtualmachineinstances/{name}",
151
+ options={"method": "GET"},
152
+ **kwargs
153
+ )
154
+ return self._parse_response(response)
155
+
156
+ def list_images(self, alias: str, namespace: str = "default", **kwargs) -> dict:
157
+ """
158
+ List all VM images in a namespace.
159
+
160
+ Args:
161
+ alias (str): The session alias for the Harvester connection.
162
+ namespace (str): Kubernetes namespace (default: "default").
163
+
164
+ Returns:
165
+ dict: List of VM images.
166
+ """
167
+ response = self.execute_command(
168
+ alias,
169
+ f"/apis/harvesterhci.io/v1beta1/namespaces/{namespace}/virtualmachineimages",
170
+ options={"method": "GET"},
171
+ **kwargs
172
+ )
173
+ return self._parse_response(response)
174
+
175
+ def get_image(self, alias: str, name: str, namespace: str = "default", **kwargs) -> dict:
176
+ """
177
+ Get details of a specific VM image.
178
+
179
+ Args:
180
+ alias (str): The session alias for the Harvester connection.
181
+ name (str): Image name.
182
+ namespace (str): Kubernetes namespace (default: "default").
183
+
184
+ Returns:
185
+ dict: Image details.
186
+ """
187
+ response = self.execute_command(
188
+ alias,
189
+ f"/apis/harvesterhci.io/v1beta1/namespaces/{namespace}/virtualmachineimages/{name}",
190
+ options={"method": "GET"},
191
+ **kwargs
192
+ )
193
+ return self._parse_response(response)
194
+
195
+ def list_volume_claims(self, alias: str, namespace: str = "default", **kwargs) -> dict:
196
+ """
197
+ List all persistent volume claims in a namespace.
198
+
199
+ Args:
200
+ alias (str): The session alias for the Harvester connection.
201
+ namespace (str): Kubernetes namespace (default: "default").
202
+
203
+ Returns:
204
+ dict: List of persistent volume claims.
205
+ """
206
+ response = self.execute_command(
207
+ alias,
208
+ f"/api/v1/namespaces/{namespace}/persistentvolumeclaims",
209
+ options={"method": "GET"},
210
+ **kwargs
211
+ )
212
+ return self._parse_response(response)
213
+
214
+ def get_volume_claim(self, alias: str, name: str, namespace: str = "default", **kwargs) -> dict:
215
+ """
216
+ Get details of a specific persistent volume claim.
217
+
218
+ Args:
219
+ alias (str): The session alias for the Harvester connection.
220
+ name (str): Volume claim name.
221
+ namespace (str): Kubernetes namespace (default: "default").
222
+
223
+ Returns:
224
+ dict: Volume claim details.
225
+ """
226
+ response = self.execute_command(
227
+ alias,
228
+ f"/api/v1/namespaces/{namespace}/persistentvolumeclaims/{name}",
229
+ options={"method": "GET"},
230
+ **kwargs
231
+ )
232
+ return self._parse_response(response)
233
+
234
+ def list_networks(self, alias: str, namespace: str = "default", **kwargs) -> dict:
235
+ """
236
+ List all networks in a namespace.
237
+
238
+ Args:
239
+ alias (str): The session alias for the Harvester connection.
240
+ namespace (str): Kubernetes namespace (default: "default").
241
+
242
+ Returns:
243
+ dict: List of networks.
244
+ """
245
+ response = self.execute_command(
246
+ alias,
247
+ f"/apis/k8s.cni.cncf.io/v1/namespaces/{namespace}/network-attachment-definitions",
248
+ options={"method": "GET"},
249
+ **kwargs
250
+ )
251
+ return self._parse_response(response)
252
+
253
+ def get_network(self, alias: str, name: str, namespace: str = "default", **kwargs) -> dict:
254
+ """
255
+ Get details of a specific network.
256
+
257
+ Args:
258
+ alias (str): The session alias for the Harvester connection.
259
+ name (str): Network name.
260
+ namespace (str): Kubernetes namespace (default: "default").
261
+
262
+ Returns:
263
+ dict: Network details.
264
+ """
265
+ response = self.execute_command(
266
+ alias,
267
+ f"/apis/k8s.cni.cncf.io/v1/namespaces/{namespace}/network-attachment-definitions/{name}",
268
+ options={"method": "GET"},
269
+ **kwargs
270
+ )
271
+ return self._parse_response(response)
272
+
273
+ def list_nodes(self, alias: str, **kwargs) -> dict:
274
+ """
275
+ List all cluster nodes.
276
+
277
+ Args:
278
+ alias (str): The session alias for the Harvester connection.
279
+
280
+ Returns:
281
+ dict: List of cluster nodes.
282
+ """
283
+ response = self.execute_command(
284
+ alias,
285
+ "/api/v1/nodes",
286
+ options={"method": "GET"},
287
+ **kwargs
288
+ )
289
+ return self._parse_response(response)
290
+
291
+ def get_node(self, alias: str, name: str, **kwargs) -> dict:
292
+ """
293
+ Get details of a specific cluster node.
294
+
295
+ Args:
296
+ alias (str): The session alias for the Harvester connection.
297
+ name (str): Node name.
298
+
299
+ Returns:
300
+ dict: Node details.
301
+ """
302
+ response = self.execute_command(
303
+ alias,
304
+ f"/api/v1/nodes/{name}",
305
+ options={"method": "GET"},
306
+ **kwargs
307
+ )
308
+ return self._parse_response(response)
309
+
310
+ def list_namespaces(self, alias: str, **kwargs) -> dict:
311
+ """
312
+ List all namespaces in the cluster.
313
+
314
+ Args:
315
+ alias (str): The session alias for the Harvester connection.
316
+
317
+ Returns:
318
+ dict: List of namespaces.
319
+ """
320
+ response = self.execute_command(
321
+ alias,
322
+ "/api/v1/namespaces",
323
+ options={"method": "GET"},
324
+ **kwargs
325
+ )
326
+ return self._parse_response(response)
327
+
328
+ def get_cluster_info(self, alias: str, **kwargs) -> dict:
329
+ """
330
+ Get cluster information.
331
+
332
+ Args:
333
+ alias (str): The session alias for the Harvester connection.
334
+
335
+ Returns:
336
+ dict: Cluster information.
337
+ """
338
+ response = self.execute_command(
339
+ alias,
340
+ "/api/v1",
341
+ options={"method": "GET"},
342
+ **kwargs
343
+ )
344
+ return self._parse_response(response)
345
+
346
+ def list_settings(self, alias: str, **kwargs) -> dict:
347
+ """
348
+ List all Harvester settings.
349
+
350
+ Args:
351
+ alias (str): The session alias for the Harvester connection.
352
+
353
+ Returns:
354
+ dict: List of Harvester settings.
355
+ """
356
+ response = self.execute_command(
357
+ alias,
358
+ "/v1/harvesterhci.io.settings",
359
+ options={"method": "GET"},
360
+ **kwargs
361
+ )
362
+ return self._parse_response(response)
363
+
364
+ def get_setting(self, alias: str, name: str, **kwargs) -> dict:
365
+ """
366
+ Get a specific Harvester setting.
367
+
368
+ Args:
369
+ alias (str): The session alias for the Harvester connection.
370
+ name (str): Setting name.
371
+
372
+ Returns:
373
+ dict: Setting details.
374
+ """
375
+ response = self.execute_command(
376
+ alias,
377
+ f"/v1/harvesterhci.io.settings/{name}",
378
+ options={"method": "GET"},
379
+ **kwargs
380
+ )
381
+ return self._parse_response(response)
@@ -26,13 +26,118 @@ import base64
26
26
  import os
27
27
  import json
28
28
  import importlib
29
- from sshtunnel import SSHTunnelForwarder
29
+ import select
30
+ import socket
31
+ import threading
32
+ import paramiko
30
33
  from abc import ABC, abstractmethod
31
34
  from pathlib import Path
32
35
  from typing import Any, Dict, Optional, Union, List
33
36
  from cryptography.fernet import Fernet
34
37
 
35
38
 
39
+ class SSHTunnel:
40
+ """
41
+ A lightweight SSH tunnel implementation using paramiko, replacing the
42
+ unmaintained sshtunnel library which is incompatible with paramiko >= 3.x
43
+ (paramiko removed DSSKey in version 3.0).
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ ssh_address_or_host,
49
+ remote_bind_address,
50
+ ssh_username=None,
51
+ ssh_password=None,
52
+ ):
53
+ self._ssh_host, self._ssh_port = ssh_address_or_host
54
+ self._remote_host, self._remote_port = remote_bind_address
55
+ self._ssh_username = ssh_username
56
+ self._ssh_password = ssh_password
57
+ self._transport = None
58
+ self._server_socket = None
59
+ self._local_bind_port = None
60
+ self._stop_event = threading.Event()
61
+ self._accept_thread = None
62
+
63
+ @property
64
+ def local_bind_port(self):
65
+ return self._local_bind_port
66
+
67
+ def start(self):
68
+ self._transport = paramiko.Transport((self._ssh_host, self._ssh_port))
69
+ self._transport.connect(
70
+ username=self._ssh_username, password=self._ssh_password
71
+ )
72
+
73
+ self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
74
+ self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
75
+ self._server_socket.bind(("127.0.0.1", 0))
76
+ self._local_bind_port = self._server_socket.getsockname()[1]
77
+ self._server_socket.listen(5)
78
+
79
+ self._accept_thread = threading.Thread(
80
+ target=self._accept_loop, daemon=True
81
+ )
82
+ self._accept_thread.start()
83
+
84
+ def _accept_loop(self):
85
+ while not self._stop_event.is_set():
86
+ self._server_socket.settimeout(1.0)
87
+ try:
88
+ client_sock, addr = self._server_socket.accept()
89
+ except socket.timeout:
90
+ continue
91
+ except OSError:
92
+ break
93
+ try:
94
+ channel = self._transport.open_channel(
95
+ "direct-tcpip",
96
+ (self._remote_host, self._remote_port),
97
+ addr,
98
+ )
99
+ except paramiko.SSHException:
100
+ client_sock.close()
101
+ continue
102
+ t = threading.Thread(
103
+ target=self._forward_data,
104
+ args=(client_sock, channel),
105
+ daemon=True,
106
+ )
107
+ t.start()
108
+
109
+ def _forward_data(self, client_sock, channel):
110
+ try:
111
+ while not self._stop_event.is_set():
112
+ r, _, _ = select.select([client_sock, channel], [], [], 1.0)
113
+ if client_sock in r:
114
+ data = client_sock.recv(4096)
115
+ if not data:
116
+ break
117
+ channel.sendall(data)
118
+ if channel in r:
119
+ data = channel.recv(4096)
120
+ if not data:
121
+ break
122
+ client_sock.sendall(data)
123
+ finally:
124
+ client_sock.close()
125
+ channel.close()
126
+
127
+ def stop(self):
128
+ self._stop_event.set()
129
+ if self._server_socket:
130
+ try:
131
+ self._server_socket.close()
132
+ except OSError:
133
+ pass
134
+ if self._transport:
135
+ try:
136
+ self._transport.close()
137
+ except paramiko.SSHException:
138
+ pass
139
+
140
+
36
141
  class ConnectorInterface(ABC):
37
142
  def __init__(self):
38
143
  self._cache = None
@@ -205,7 +310,7 @@ class TunnelingManager:
205
310
  int(tunnel_config[index + 1]["port"]),
206
311
  )
207
312
  )
208
- tunnel = SSHTunnelForwarder(
313
+ tunnel = SSHTunnel(
209
314
  ssh_address_or_host=ssh_address_or_host,
210
315
  remote_bind_address=remote_bind_address,
211
316
  ssh_username=config["username"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysbot
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: System test automation library with support for SSH, WinRM, HTTP, databases, and Robot Framework integration
5
5
  Home-page: https://github.com/JoReci2/sysbot
6
6
  Author: Thibault SCIRE
@@ -33,7 +33,6 @@ Description-Content-Type: text/markdown
33
33
  License-File: LICENSE
34
34
  Requires-Dist: robotframework
35
35
  Requires-Dist: paramiko
36
- Requires-Dist: sshtunnel
37
36
  Requires-Dist: netmiko
38
37
  Requires-Dist: redfish
39
38
  Requires-Dist: pywinrm
@@ -26,15 +26,15 @@ sysbot/modules/__init__.py
26
26
  sysbot/modules/bmc/__init__.py
27
27
  sysbot/modules/bmc/idrac.py
28
28
  sysbot/modules/bmc/ilo.py
29
+ sysbot/modules/container/__init__.py
30
+ sysbot/modules/container/kubernetes.py
31
+ sysbot/modules/container/podman.py
29
32
  sysbot/modules/linux/__init__.py
30
33
  sysbot/modules/linux/dnf.py
31
34
  sysbot/modules/linux/file.py
32
35
  sysbot/modules/linux/firewalld.py
33
36
  sysbot/modules/linux/ip.py
34
37
  sysbot/modules/linux/iptables.py
35
- sysbot/modules/linux/kubernetes.py
36
- sysbot/modules/linux/libvirt.py
37
- sysbot/modules/linux/podman.py
38
38
  sysbot/modules/linux/process.py
39
39
  sysbot/modules/linux/rpm.py
40
40
  sysbot/modules/linux/selinux.py
@@ -46,10 +46,13 @@ sysbot/modules/monitoring/grafana.py
46
46
  sysbot/modules/network/__init__.py
47
47
  sysbot/modules/network/cisco/__init__.py
48
48
  sysbot/modules/network/cisco/catalyst.py
49
- sysbot/modules/vmware/__init__.py
50
- sysbot/modules/vmware/nsx.py
51
- sysbot/modules/vmware/sddcmanager.py
52
- sysbot/modules/vmware/vsphere.py
49
+ sysbot/modules/virtualization/__init__.py
50
+ sysbot/modules/virtualization/harvester.py
51
+ sysbot/modules/virtualization/libvirt.py
52
+ sysbot/modules/virtualization/vmware/__init__.py
53
+ sysbot/modules/virtualization/vmware/nsx.py
54
+ sysbot/modules/virtualization/vmware/sddcmanager.py
55
+ sysbot/modules/virtualization/vmware/vsphere.py
53
56
  sysbot/modules/windows/__init__.py
54
57
  sysbot/modules/windows/adcs.py
55
58
  sysbot/modules/windows/adds.py
@@ -1,6 +1,5 @@
1
1
  robotframework
2
2
  paramiko
3
- sshtunnel
4
3
  netmiko
5
4
  redfish
6
5
  pywinrm
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes