splight-lib 5.10.0__tar.gz → 5.10.1.dev1__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 (106) hide show
  1. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/PKG-INFO +1 -1
  2. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/pyproject.toml +1 -1
  3. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/database/classmap.py +4 -0
  4. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/database/remote_client.py +6 -2
  5. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/_internal.py +1 -0
  6. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/__init__.py +4 -0
  7. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/exceptions.py +9 -0
  8. splight_lib-5.10.1.dev1/splight_lib/models/hub_server.py +118 -0
  9. splight_lib-5.10.1.dev1/splight_lib/models/server.py +211 -0
  10. splight_lib-5.10.1.dev1/splight_lib/server/__init__.py +5 -0
  11. splight_lib-5.10.1.dev1/splight_lib/server/exceptions.py +3 -0
  12. splight_lib-5.10.1.dev1/splight_lib/server/server.py +16 -0
  13. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/solution/solution.py +1 -1
  14. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/LICENSE.txt +0 -0
  15. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/README.md +0 -0
  16. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/__init__.py +0 -0
  17. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/abstract/__init__.py +0 -0
  18. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/abstract/client.py +0 -0
  19. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/auth/__init__.py +0 -0
  20. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/auth/exceptions.py +0 -0
  21. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/auth/mac_auth.py +0 -0
  22. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/auth/token.py +0 -0
  23. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/__init__.py +0 -0
  24. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/database/__init__.py +0 -0
  25. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/database/abstract.py +0 -0
  26. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/database/builder.py +0 -0
  27. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/__init__.py +0 -0
  28. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/abstract.py +0 -0
  29. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/buffer.py +0 -0
  30. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/builder.py +0 -0
  31. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/constants.py +0 -0
  32. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/exceptions.py +0 -0
  33. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/datalake/remote_client.py +0 -0
  34. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/exceptions.py +0 -0
  35. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/file_handler.py +0 -0
  36. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/filter.py +0 -0
  37. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/hub/__init__.py +0 -0
  38. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/hub/abstract.py +0 -0
  39. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/hub/client.py +0 -0
  40. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/tests/test_database.py +0 -0
  41. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/client/tests/test_datalake.py +0 -0
  42. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/__init__.py +0 -0
  43. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/abstract.py +0 -0
  44. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/exceptions.py +0 -0
  45. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/spec.py +0 -0
  46. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/tests/test_abstract.py +0 -0
  47. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/component/tests/test_spec.py +0 -0
  48. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/conftest.py +0 -0
  49. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/constants.py +0 -0
  50. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/encryption.py +0 -0
  51. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/__init__.py +0 -0
  52. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/engine.py +0 -0
  53. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/exceptions.py +0 -0
  54. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/scheduling.py +0 -0
  55. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/task.py +0 -0
  56. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/tests/test_execution.py +0 -0
  57. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/tests/test_scheduling.py +0 -0
  58. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/execution/trigger.py +0 -0
  59. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/__init__.py +0 -0
  60. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/component.py +0 -0
  61. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/constants.py +0 -0
  62. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/logging.py +0 -0
  63. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/logging/tests/test_logging.py +0 -0
  64. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/actions.py +0 -0
  65. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/alert.py +0 -0
  66. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/asset.py +0 -0
  67. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/attribute.py +0 -0
  68. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/component.py +0 -0
  69. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/dashboard.py +0 -0
  70. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/data_address.py +0 -0
  71. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/database_base.py +0 -0
  72. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/datalake.py +0 -0
  73. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/datalake_base.py +0 -0
  74. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/file.py +0 -0
  75. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/function.py +0 -0
  76. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/generic.py +0 -0
  77. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/hub.py +0 -0
  78. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/hub_solution.py +0 -0
  79. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/metadata.py +0 -0
  80. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/native.py +0 -0
  81. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/secret.py +0 -0
  82. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/solution.py +0 -0
  83. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tag.py +0 -0
  84. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tests/models.json +0 -0
  85. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tests/test_component_object_instance.py +0 -0
  86. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tests/test_database_model.py +0 -0
  87. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tests/test_metadata.py +0 -0
  88. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/models/tests/test_models.py +0 -0
  89. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/restclient/__init__.py +0 -0
  90. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/restclient/client.py +0 -0
  91. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/restclient/exceptions.py +0 -0
  92. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/restclient/tests/test_restclient.py +0 -0
  93. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/restclient/types.py +0 -0
  94. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/settings.py +0 -0
  95. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/solution/__init__.py +0 -0
  96. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/solution/exceptions.py +0 -0
  97. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/stringcase.py +0 -0
  98. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/testing/__init__.py +0 -0
  99. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/tests/FakeProc.py +0 -0
  100. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/tests/asset_geometries.json +0 -0
  101. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/tests/test_api_contracts.py +0 -0
  102. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/tests/test_encryption.py +0 -0
  103. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/utils/__init__.py +0 -0
  104. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/utils/custom_model.py +0 -0
  105. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/utils/hub.py +0 -0
  106. {splight_lib-5.10.0 → splight_lib-5.10.1.dev1}/splight_lib/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: splight-lib
3
- Version: 5.10.0
3
+ Version: 5.10.1.dev1
4
4
  Summary: Splight Library
5
5
  Author: Splight Dev
6
6
  Author-email: dev@splight-ae.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "splight-lib"
3
- version = "5.10.0"
3
+ version = "5.10.1.dev1"
4
4
  description = "Splight Library"
5
5
  authors = ["Splight Dev <dev@splight-ae.com>"]
6
6
  readme = "README.md"
@@ -23,9 +23,12 @@ MODEL_NAME_MAP = {
23
23
  "secret": f"{ENGINE_PREFIX}/secrets/",
24
24
  "setpoint": f"{ENGINE_PREFIX}/setpoints/",
25
25
  "solution": f"{ENGINE_PREFIX}/solution/solutions/",
26
+ "server": f"{ENGINE_PREFIX}/server/servers/",
26
27
  "tab": f"{ENGINE_PREFIX}/dashboard/tabs/",
27
28
  "hubsolution": f"{HUB_PREFIX}/solution/solutions/",
28
29
  "hubsolutionversion": f"{HUB_PREFIX}/solution/versions/",
30
+ "hubserver": f"{HUB_PREFIX}/server/servers/",
31
+ "hubserverversion": f"{HUB_PREFIX}/server/versions/",
29
32
  }
30
33
 
31
34
  CUSTOM_PATHS_MAP = {
@@ -33,4 +36,5 @@ CUSTOM_PATHS_MAP = {
33
36
  "get-asset-attribute": "{prefix}/assets/{asset}/get-attribute/",
34
37
  "decrypt-secret": "{prefix}/secrets/decrypt/",
35
38
  "routine-status": "{prefix}/component/routines/{routine}/update_status/",
39
+ "server-status": "{prefix}/server/servers/{server}/update-status/",
36
40
  }
@@ -211,9 +211,13 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
211
211
  ------
212
212
  InvalidModelName thrown when the model name is not correct.
213
213
  """
214
- if resource_name.lower() not in ["file", "hubsolutionversion"]:
214
+ if resource_name.lower() not in [
215
+ "file",
216
+ "hubsolutionversion",
217
+ "hubserverversion",
218
+ ]:
215
219
  raise InvalidModel(
216
- "Only files and hub solution can be downloaded."
220
+ "Only files, hub solution and hub servers can be downloaded."
217
221
  )
218
222
  api_path = self._get_api_path(resource_name)
219
223
  resource_id = instance.get("id")
@@ -24,6 +24,7 @@ class LogTags(UppercaseStrEnum):
24
24
  DATABASE = auto()
25
25
  DATALAKE = auto()
26
26
  CACHE = auto()
27
+ SERVER = auto()
27
28
 
28
29
 
29
30
  # don't used now
@@ -22,10 +22,12 @@ from splight_lib.models.datalake import DataRequest, PipelineStep, Trace
22
22
  from splight_lib.models.file import File
23
23
  from splight_lib.models.function import Function, FunctionItem, QueryFilter
24
24
  from splight_lib.models.hub import HubComponent
25
+ from splight_lib.models.hub_server import HubServer
25
26
  from splight_lib.models.hub_solution import HubSolution
26
27
  from splight_lib.models.metadata import Metadata
27
28
  from splight_lib.models.native import Boolean, Number, String
28
29
  from splight_lib.models.secret import Secret
30
+ from splight_lib.models.server import Server
29
31
  from splight_lib.models.solution import Solution
30
32
  from splight_lib.models.tag import Tag
31
33
 
@@ -52,12 +54,14 @@ __all__ = [
52
54
  FunctionItem,
53
55
  HubSolution,
54
56
  HubComponent,
57
+ HubServer,
55
58
  QueryFilter,
56
59
  Metadata,
57
60
  Number,
58
61
  PipelineStep,
59
62
  RoutineEvaluation,
60
63
  Secret,
64
+ Server,
61
65
  SetPoint,
62
66
  Solution,
63
67
  String,
@@ -66,6 +66,15 @@ class InvalidArgument(Exception):
66
66
  pass
67
67
 
68
68
 
69
+ class InvalidServerConfigType(Exception):
70
+ def __init__(self, name: str, type_: str):
71
+ msg = (
72
+ f"Config parameter {name} has an invalid type {type_}. The only "
73
+ "valid types are native and 'File'"
74
+ )
75
+ super().__init__(msg)
76
+
77
+
69
78
  class TraceAlreadyExistsError(Exception):
70
79
  def __init__(self, ref_id: str):
71
80
  msg = f"Trace with ref_id {ref_id} already exists"
@@ -0,0 +1,118 @@
1
+ import os
2
+ from glob import glob
3
+ from tempfile import NamedTemporaryFile
4
+ from typing import Dict, List, Optional
5
+
6
+ import py7zr
7
+ from pydantic import BaseModel, Field
8
+
9
+ from splight_lib.constants import DESCRIPTION_MAX_LENGTH
10
+ from splight_lib.models.database_base import (
11
+ FilePath,
12
+ PrivacyPolicy,
13
+ SplightDatabaseBaseModel,
14
+ )
15
+ from splight_lib.models.component import InputParameter
16
+ from splight_lib.utils.hub import (
17
+ COMPRESSION_TYPE,
18
+ README_FILE_1,
19
+ get_ignore_pathspec,
20
+ get_spec,
21
+ )
22
+
23
+
24
+ class Port(BaseModel):
25
+ name: Optional[str]
26
+ protocol: str = "tcp"
27
+ internal_port: int
28
+ exposed_port: int
29
+
30
+
31
+ class HubServer(SplightDatabaseBaseModel):
32
+ id: Optional[str] = None
33
+ name: str
34
+ version: str
35
+ description: Optional[str] = Field(
36
+ default=None, max_length=DESCRIPTION_MAX_LENGTH
37
+ )
38
+ tags: Optional[List[str]] = Field(default=[])
39
+ privacy_policy: PrivacyPolicy = PrivacyPolicy.PUBLIC
40
+
41
+ config: List[InputParameter] = []
42
+ ports: List[Port] = []
43
+ environment: List[Dict[str, str]] = []
44
+
45
+ @classmethod
46
+ def upload(cls, path: FilePath, image_file: str) -> "HubServer":
47
+ db_client = cls._SplightDatabaseBaseModel__get_database_client()
48
+ image_path = os.path.join(path, image_file)
49
+ spec = get_spec(path)
50
+ name = spec.get("name")
51
+ version = spec.get("version")
52
+
53
+ raw_hub_server = db_client.get(
54
+ resource_name=cls.__name__,
55
+ name=name,
56
+ version=version,
57
+ )
58
+ server = cls.model_validate(spec)
59
+ if raw_hub_server:
60
+ old_hub_server = cls.model_validate(raw_hub_server[0])
61
+ server.id = old_hub_server.id
62
+
63
+ server.save()
64
+
65
+ file_name = f"{name}-{version}.{COMPRESSION_TYPE}"
66
+ ignore_pathspec = get_ignore_pathspec(path)
67
+ versioned_path = f"{name}-{version}"
68
+ # TODO: Add required files validations
69
+ readme_path = os.path.join(path, README_FILE_1)
70
+ if not os.path.exists(readme_path):
71
+ raise FileNotFoundError(f"README.md file not found: {readme_path}")
72
+ with py7zr.SevenZipFile(file_name, "w") as archive:
73
+ all_files = glob(f"{path}/**", recursive=True)
74
+ for filepath in all_files:
75
+ if ignore_pathspec and ignore_pathspec.match_file(filepath):
76
+ continue
77
+ if os.path.isdir(filepath):
78
+ continue
79
+ if image_file in filepath:
80
+ continue
81
+ rel_filename = os.path.relpath(filepath, path)
82
+ new_filepath = os.path.join(versioned_path, rel_filename)
83
+ archive.write(filepath, new_filepath)
84
+
85
+ data = server.model_dump()
86
+ try:
87
+ db_client.upload(
88
+ "hubserverversion",
89
+ instance=data,
90
+ file_path=file_name,
91
+ type_="source",
92
+ )
93
+ db_client.upload(
94
+ "hubserverversion",
95
+ instance=data,
96
+ file_path=readme_path,
97
+ type_="readme",
98
+ )
99
+ db_client.upload(
100
+ "hubserverversion",
101
+ instance=data,
102
+ file_path=image_path,
103
+ type_="image",
104
+ )
105
+ except Exception as exc:
106
+ raise exc
107
+ finally:
108
+ if os.path.exists(file_name):
109
+ os.remove(file_name)
110
+ return server
111
+
112
+ def download(self) -> NamedTemporaryFile:
113
+ db_client = self._SplightDatabaseBaseModel__get_database_client()
114
+ return db_client.download(
115
+ resource_name="hubserverversion",
116
+ instance=self.model_dump(),
117
+ type_="source",
118
+ )
@@ -0,0 +1,211 @@
1
+ import re
2
+ import warnings
3
+ from collections import namedtuple
4
+ from datetime import datetime
5
+ from enum import auto
6
+ from typing import Any, NamedTuple, Optional
7
+
8
+ from pydantic import AnyUrl, BaseModel, Field, computed_field
9
+ from strenum import LowercaseStrEnum, PascalCaseStrEnum
10
+
11
+ from splight_lib.models.database_base import SplightDatabaseBaseModel
12
+ from splight_lib.models.exceptions import (
13
+ InvalidArgument,
14
+ InvalidServerConfigType,
15
+ )
16
+ from splight_lib.models.file import File
17
+ from splight_lib.models.hub_server import HubServer
18
+ from splight_lib.models.secret import Secret
19
+
20
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
21
+
22
+ NATIVE_TYPES = {
23
+ "int": int,
24
+ "bool": bool,
25
+ "str": str,
26
+ "float": float,
27
+ "datetime": datetime,
28
+ "url": AnyUrl,
29
+ }
30
+
31
+ DATABASE_TYPES = {
32
+ "File": File,
33
+ }
34
+
35
+ DB_MODEL_TYPE_MAPPING = {
36
+ **NATIVE_TYPES,
37
+ **DATABASE_TYPES,
38
+ }
39
+
40
+
41
+ def get_field_value(field: dict):
42
+ field_multiple = field.get("multiple", False)
43
+ field_type = field.get("type")
44
+ field_value = field.get("value")
45
+
46
+ if not field_value:
47
+ return [] if field_multiple else None
48
+
49
+ if field_type in NATIVE_TYPES:
50
+ value = (
51
+ field_value
52
+ if not isinstance(field_value, str)
53
+ else parse_variable_string(field_value)
54
+ )
55
+ elif field_type in DATABASE_TYPES:
56
+ model_class = DATABASE_TYPES[field_type]
57
+ value = (
58
+ model_class.retrieve(field_value)
59
+ if not field_multiple
60
+ else [model_class.retrieve(item) for item in field_value]
61
+ )
62
+ return value
63
+
64
+
65
+ def get_model_class(config: BaseModel, name: str) -> NamedTuple:
66
+ config_class = namedtuple(name, [x.name for x in config])
67
+ return config_class
68
+
69
+
70
+ def load_server_config(
71
+ config: list[dict], config_class: NamedTuple
72
+ ) -> NamedTuple:
73
+ config_dict = {}
74
+ for item in config:
75
+ if item["type"] not in DB_MODEL_TYPE_MAPPING:
76
+ raise InvalidServerConfigType(item["name"], item["type"])
77
+ config_dict.update({item["name"]: get_field_value(item)})
78
+ config = config_class(**config_dict)
79
+ return config
80
+
81
+
82
+ def load_server_ports(
83
+ ports: list[dict], model_class: NamedTuple
84
+ ) -> namedtuple:
85
+ ports_dict = {}
86
+ for port in ports:
87
+ if isinstance(port["internal_port"], int) and not (
88
+ 0 <= port["internal_port"] <= 65535
89
+ ):
90
+ raise ValueError(
91
+ f"Internal port {port['internal_port']} is out of valid range (0-65535)"
92
+ )
93
+ if isinstance(port["exposed_port"], int) and not (
94
+ 0 <= port["exposed_port"] <= 65535
95
+ ):
96
+ raise ValueError(
97
+ f"External port {port['exposed_port']} is out of valid range (0-65535)"
98
+ )
99
+ if port["protocol"] not in ["tcp", "udp"]:
100
+ raise ValueError(
101
+ f"Protocol {port['protocol']} is not valid. Must be 'tcp' or 'udp'"
102
+ )
103
+ ports_dict.update({port["name"]: port})
104
+ resources = model_class(**ports_dict)
105
+ return resources
106
+
107
+
108
+ class ServerStatus(PascalCaseStrEnum):
109
+ RUNNING = auto()
110
+ FAILED = auto()
111
+ SUCCEEDED = auto()
112
+ PENDING = auto()
113
+ START_REQUESTED = auto()
114
+ STOP_REQUESTED = auto()
115
+ STOPPED = auto()
116
+ UNKNOWN = auto()
117
+
118
+
119
+ class PrivacyPolicy(LowercaseStrEnum):
120
+ PUBLIC = auto()
121
+ PRIVATE = auto()
122
+
123
+
124
+ class Port(BaseModel):
125
+ name: Optional[str]
126
+ internal_port: int
127
+ exposed_port: int
128
+
129
+
130
+ class Server(SplightDatabaseBaseModel):
131
+ id: Optional[str] = None
132
+ name: Optional[str] = None
133
+ version: str
134
+ hub_server: HubServer
135
+ raw_config: list[dict] = Field(alias="config")
136
+ raw_ports: list[dict] = Field(alias="ports")
137
+ raw_env_vars: list[dict] = Field(alias="env_vars")
138
+
139
+ def model_dump(self, *args, **kwargs):
140
+ kwargs.update({"by_alias": True})
141
+ return super().model_dump(*args, **kwargs)
142
+
143
+ def model_dump_json(self, *args, **kwargs):
144
+ kwargs.update({"by_alias": True})
145
+ return super().model_dump_json(*args, **kwargs)
146
+
147
+ @computed_field(alias="parsed_config")
148
+ @property
149
+ def config(self) -> NamedTuple:
150
+ model_class = get_model_class(self.hub_server.config, "Config")
151
+ config = load_server_config(self.raw_config, model_class)
152
+ return config
153
+
154
+ @computed_field(alias="parsed_ports")
155
+ @property
156
+ def ports(self) -> NamedTuple:
157
+ model_class = get_model_class(self.hub_server.ports, "Ports")
158
+ ports = load_server_ports(self.raw_ports, model_class)
159
+ return ports
160
+
161
+ def update_config(self, **kwargs: dict):
162
+ valid_params = [x["name"] for x in self.raw_config]
163
+ for key, value in kwargs.items():
164
+ if key not in valid_params:
165
+ raise InvalidArgument(
166
+ (
167
+ f"Got invalid parameter {key}. Valid config parameter "
168
+ f"are {valid_params}"
169
+ )
170
+ )
171
+ for item in self.raw_config:
172
+ if item["name"] == key:
173
+ item["value"] = value
174
+ break
175
+
176
+ def update_ports(self, **kwargs: dict):
177
+ valid_params = [x["name"] for x in self.raw_ports]
178
+ for key, value in kwargs.items():
179
+ if key not in valid_params:
180
+ raise InvalidArgument(
181
+ (
182
+ f"Got invalid parameter {key}. Valid port "
183
+ f"parameter are {valid_params}"
184
+ )
185
+ )
186
+ for item in self.raw_ports:
187
+ if item["name"] == key:
188
+ item["value"] = value
189
+ break
190
+
191
+ def update_status(self, status: ServerStatus):
192
+ _ = self._db_client.operate(
193
+ resource_name="server-status",
194
+ instance={
195
+ "server": self.id,
196
+ "deployment_status": status,
197
+ },
198
+ )
199
+
200
+
201
+ def parse_variable_string(raw_value: Optional[str]) -> Any:
202
+ if raw_value is None:
203
+ return ""
204
+ pattern = re.compile(r"^\$\{\{(\w+)\.(\w+)\}\}$")
205
+ match = pattern.search(raw_value)
206
+ if not match:
207
+ return raw_value
208
+ _, secret_name = match.groups()
209
+ # TODO: handle errors (not found or not allowed)
210
+ secret = Secret.decrypt(name=secret_name)
211
+ return secret.value
@@ -0,0 +1,5 @@
1
+ from splight_lib.server.server import ServerLoader
2
+
3
+ __all__ = [
4
+ ServerLoader,
5
+ ]
@@ -0,0 +1,3 @@
1
+ class MissingInstanceEnvVar(Exception):
2
+ def __init__(self, env_var: str):
3
+ super().__init__(f"Missing environment variable: {env_var}")
@@ -0,0 +1,16 @@
1
+ import json
2
+ import os
3
+
4
+ from splight_lib.models import Server
5
+ from splight_lib.server.exceptions import MissingInstanceEnvVar
6
+
7
+ ENV_VAR = "SPLIGHT_SERVER_ID"
8
+
9
+
10
+ class ServerLoader:
11
+ @classmethod
12
+ def from_env(cls) -> Server:
13
+ if not (instance_id := os.environ.get(ENV_VAR)):
14
+ raise MissingInstanceEnvVar(ENV_VAR)
15
+ server = Server.retrieve(instance_id)
16
+ return server
@@ -15,7 +15,7 @@ class SolutionLoader:
15
15
  def from_env(cls) -> Solution:
16
16
  if not (str_instance := os.environ.get(ENV_VAR)):
17
17
  raise MissingInstanceEnvVar(ENV_VAR)
18
- str_instance = os.environ.get("INSTANCE_AS_STR", "")
18
+ str_instance = os.environ.get(ENV_VAR, "")
19
19
  instance = json.loads(str_instance)
20
20
  if not (instance_id := instance.get("id")):
21
21
  raise MissingInstanceId()