Skip to content

Commit b81c84a

Browse files
feat: Add workspace field to httpconfiguration (#64)
1 parent 427e978 commit b81c84a

File tree

5 files changed

+185
-9
lines changed

5 files changed

+185
-9
lines changed

nisystemlink/clients/core/_http_configuration.py

+9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def __init__(
2222
username: Optional[str] = None,
2323
password: Optional[str] = None,
2424
cert_path: Optional[pathlib.Path] = None,
25+
workspace: Optional[str] = None,
2526
) -> None:
2627
"""Initialize a configuration.
2728
@@ -38,6 +39,7 @@ def __init__(
3839
username: The name of the user to use when authorization is required.
3940
password: The user's password to use when authorization is required.
4041
cert_path: Local path to an SSL certificate file.
42+
workspace: ID of workspace to use for client operations.
4143
4244
Raises:
4345
ValueError: if ``server_uri`` is missing scheme or host information.
@@ -69,6 +71,8 @@ def __init__(
6971

7072
self._timeout_ms = self.DEFAULT_TIMEOUT_MILLISECONDS
7173

74+
self._workspace = workspace
75+
7276
@property
7377
def timeout_milliseconds(self) -> int: # noqa: D401
7478
"""The number of milliseconds before a request times out with an error.
@@ -126,3 +130,8 @@ def password(self) -> Optional[str]: # noqa: D401
126130
def cert_path(self) -> Optional[pathlib.Path]:
127131
"""Local path to an SSL certificate file."""
128132
return self._cert_path
133+
134+
@property
135+
def workspace(self) -> Optional[str]: # noqa: D401
136+
"""ID of workspace to use for Client operations."""
137+
return self._workspace

nisystemlink/clients/core/_http_configuration_manager.py

+38-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import typing
88
from typing import Dict, Optional
99

10+
import yaml
1011
from nisystemlink.clients import core
1112
from nisystemlink.clients.core._internal._http_configuration_file import (
1213
HttpConfigurationFile,
@@ -26,6 +27,9 @@ class HttpConfigurationManager:
2627
_HTTP_JUPYTER_CONFIGURATION_ID = "SYSTEMLINK_VIRTUAL_JUPYTER"
2728
"""Virtual ID of SystemLink Server's configuration for Jupyter Notebook execution on SLE."""
2829

30+
_SALT_GRAINS_WORKSPACE_KEY = "systemlink_workspace"
31+
"""Key of Workspace ID stored in the salt grains config file."""
32+
2933
_configs = None
3034
_virtual_configs = None
3135

@@ -146,6 +150,8 @@ def _read_configurations(cls) -> Dict[str, core.HttpConfiguration]:
146150
"Error while accessing HTTP configurations directory: " + str(e)
147151
)
148152

153+
workspace = cls._read_system_workspace()
154+
149155
for json_file in json_files:
150156
try:
151157
config_file = cls._read_configuration_file(json_file)
@@ -167,7 +173,10 @@ def _read_configurations(cls) -> Dict[str, core.HttpConfiguration]:
167173
if not cert_path.exists():
168174
cert_path = None
169175
configurations[config_file.id] = core.HttpConfiguration(
170-
config_file.uri, config_file.api_key, cert_path=cert_path
176+
config_file.uri,
177+
config_file.api_key,
178+
cert_path=cert_path,
179+
workspace=workspace,
171180
)
172181
except PermissionError:
173182
pass
@@ -215,6 +224,33 @@ def _http_configurations_directory(cls) -> pathlib.Path:
215224
"""Get the platform-specific path to the HTTP Configurations directory.
216225
217226
Returns:
218-
The path of the HTTP Configurations directory.
227+
pathlib.Path: The path of the HTTP Configurations directory.
219228
"""
220229
return PathConstants.application_data_directory / "HttpConfigurations"
230+
231+
@classmethod
232+
def _salt_grains_path(cls) -> pathlib.Path:
233+
"""Get the SALT grains config file path.
234+
235+
Returns:
236+
pathlib.Path: The path of SALT grains config file
237+
"""
238+
return PathConstants.salt_data_directory / "conf" / "grains"
239+
240+
@classmethod
241+
def _read_system_workspace(cls) -> Optional[str]:
242+
"""Get the workspace of the connected remote system.
243+
244+
Reads workspace from `grains` file of SystemLink Client.
245+
246+
Returns:
247+
str: Workspace Id of the remote system.
248+
"""
249+
salt_grain_file_path = cls._salt_grains_path()
250+
251+
if salt_grain_file_path.exists():
252+
with open(salt_grain_file_path, "r", encoding="utf-8") as fp:
253+
grain_data: Dict = yaml.safe_load(fp)
254+
return grain_data.get(cls._SALT_GRAINS_WORKSPACE_KEY)
255+
256+
return None

nisystemlink/clients/core/_internal/_path_constants.py

+61-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class PathConstants(metaclass=ClasspropertySupport):
2323

2424
_application_data_directory = None # type: Optional[pathlib.Path]
2525

26+
_salt_data_directory = None # type: Optional[pathlib.Path]
27+
2628
def __init_subclass__(cls) -> None:
2729
raise TypeError("type 'PathConstants' is not an acceptable base type")
2830

@@ -47,29 +49,83 @@ def application_data_directory(self) -> pathlib.Path: # noqa: D401
4749
)
4850
return typing.cast(pathlib.Path, self._application_data_directory)
4951

50-
@classmethod
51-
def _windows_application_data_directory(cls) -> pathlib.Path:
52-
"""Get the NI Application Data directory on Windows.
52+
@ClasspropertySupport.classproperty
53+
def salt_data_directory(self) -> pathlib.Path: # noqa: D401
54+
"""Get the platform-specific path to the salt minion Data directory.
5355
5456
Returns:
55-
The NI Application Data directory on Windows.
57+
The platform-specific path to the salt minion Data directory.
58+
"""
59+
if self._salt_data_directory is None:
60+
if os.name == "nt":
61+
PathConstants._salt_data_directory = self._windows_salt_data_directory()
62+
63+
return typing.cast(pathlib.Path, self._salt_data_directory)
64+
65+
@classmethod
66+
def _windows_programdata_directory(cls) -> pathlib.Path:
67+
"""Get the path of Windows PROGRAMDATA directory.
5668
5769
Raises:
5870
RuntimeError: if this method is called on a non-Windows system.
5971
RuntimeError: if the ProgramData folder cannot be found.
72+
73+
Returns:
74+
pathlib.Path: Windows PROGRAMDATA directory path.
6075
"""
6176
if os.name != "nt":
6277
raise RuntimeError("This function is for Windows only")
6378

79+
programdata_dir = None
80+
6481
try:
6582
from . import _winpaths
6683

6784
programdata_dir = pathlib.Path(
6885
_winpaths.get_path(_winpaths.FOLDERID.ProgramData)
6986
)
7087
except Exception:
71-
programdata_dir = pathlib.Path("C:/ProgramData")
88+
env_programdata_dir = os.getenv("PROGRAMDATA")
89+
90+
if env_programdata_dir:
91+
programdata_dir = pathlib.Path(env_programdata_dir)
92+
93+
if programdata_dir is not None and programdata_dir.exists():
94+
return programdata_dir
95+
96+
# Last fallback option, assume that it is in C:/
97+
programdata_dir = pathlib.Path("C:/ProgramData")
98+
7299
if not programdata_dir.exists():
73100
raise RuntimeError("Cannot find ProgramData folder")
74101

102+
return programdata_dir
103+
104+
@classmethod
105+
def _windows_application_data_directory(cls) -> pathlib.Path:
106+
"""Get the NI Application Data directory on Windows.
107+
108+
Returns:
109+
pathlib.Path: The NI Application Data directory on Windows.
110+
111+
Raises:
112+
RuntimeError: if this method is called on a non-Windows system.
113+
RuntimeError: if the ProgramData folder cannot be found.
114+
"""
115+
programdata_dir = cls._windows_programdata_directory()
116+
75117
return programdata_dir / cls.COMPANY_NAME / cls.PRODUCT_NAME
118+
119+
@classmethod
120+
def _windows_salt_data_directory(cls) -> pathlib.Path:
121+
"""Get the salt minion Data directory on Windows.
122+
123+
Returns:
124+
pathlib.Path: The salt minion Data directory on Windows.
125+
126+
Raises:
127+
RuntimeError: if this method is called on a non-Windows system.
128+
RuntimeError: if the ProgramData folder cannot be found.
129+
"""
130+
programdata_dir = cls._windows_programdata_directory()
131+
return programdata_dir / cls.COMPANY_NAME / "salt"

poetry.lock

+75-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ httpx = "^0.23.0"
3737
requests = "^2.28.1"
3838
uplink = "^0.9.7"
3939
pydantic = "^1.10.2"
40+
pyyaml = "^6.0.1"
4041

4142
[tool.poetry.group.dev.dependencies]
4243
black = ">=22.10,<25.0"
@@ -49,6 +50,7 @@ flake8-docstrings = "^1.6.0"
4950
poethepoet = "^0.16.4"
5051
types-requests = "^2.28.11.4"
5152
responses = "^0.22.0"
53+
types-pyyaml = "^6.0.12"
5254

5355
[tool.poe.tasks]
5456
test = "pytest tests -m \"(not slow) and (not cloud) and (not enterprise)\""

0 commit comments

Comments
 (0)