fred-oss 0.54.0__tar.gz → 0.56.0__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 (130) hide show
  1. fred_oss-0.56.0/MANIFEST.in +3 -0
  2. {fred_oss-0.54.0/src/main/fred_oss.egg-info → fred_oss-0.56.0}/PKG-INFO +1 -1
  3. {fred_oss-0.54.0 → fred_oss-0.56.0}/setup.py +2 -0
  4. fred_oss-0.56.0/src/main/fred/cli/main.py +59 -0
  5. fred_oss-0.56.0/src/main/fred/dao/service/_minio/__init__.py +1 -0
  6. fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy/builder.py +16 -0
  7. fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy/catalog.py +28 -0
  8. fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy/loader.py +27 -0
  9. fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy/templates/public_ro.json +24 -0
  10. fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy/templates/public_rw.json +31 -0
  11. fred_oss-0.56.0/src/main/fred/dao/service/_minio/pool.py +55 -0
  12. fred_oss-0.54.0/src/main/fred/dao/service/_minio.py → fred_oss-0.56.0/src/main/fred/dao/service/_minio/service.py +13 -52
  13. fred_oss-0.56.0/src/main/fred/integrations/databricks/runtimes/16.4LTS.json +10 -0
  14. fred_oss-0.56.0/src/main/fred/rest/__init__.py +17 -0
  15. fred_oss-0.56.0/src/main/fred/rest/auth.py +23 -0
  16. fred_oss-0.56.0/src/main/fred/rest/config.py +32 -0
  17. fred_oss-0.56.0/src/main/fred/rest/router/catalog/default/__init__.py +10 -0
  18. fred_oss-0.56.0/src/main/fred/rest/router/catalog/default/_base.py +29 -0
  19. fred_oss-0.56.0/src/main/fred/rest/router/catalog/default/_example.py +31 -0
  20. fred_oss-0.56.0/src/main/fred/rest/router/catalog/default/catalog.py +20 -0
  21. fred_oss-0.56.0/src/main/fred/rest/router/catalog/interface.py +11 -0
  22. fred_oss-0.56.0/src/main/fred/rest/router/config.py +40 -0
  23. fred_oss-0.56.0/src/main/fred/rest/router/endpoint.py +94 -0
  24. fred_oss-0.56.0/src/main/fred/rest/router/interface.py +90 -0
  25. fred_oss-0.56.0/src/main/fred/rest/server.py +104 -0
  26. fred_oss-0.56.0/src/main/fred/rest/settings.py +46 -0
  27. fred_oss-0.56.0/src/main/fred/version +1 -0
  28. fred_oss-0.56.0/src/main/fred/worker/runner/plugins/__init__.py +0 -0
  29. fred_oss-0.56.0/src/main/fred/worker/runner/rest/__init__.py +0 -0
  30. fred_oss-0.56.0/src/main/fred/worker/runner/rest/routers/__init__.py +0 -0
  31. {fred_oss-0.54.0 → fred_oss-0.56.0/src/main/fred_oss.egg-info}/PKG-INFO +1 -1
  32. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred_oss.egg-info/SOURCES.txt +25 -1
  33. fred_oss-0.54.0/MANIFEST.in +0 -2
  34. fred_oss-0.54.0/src/main/fred/cli/main.py +0 -31
  35. fred_oss-0.54.0/src/main/fred/version +0 -1
  36. {fred_oss-0.54.0 → fred_oss-0.56.0}/NOTICE.txt +0 -0
  37. {fred_oss-0.54.0 → fred_oss-0.56.0}/README.md +0 -0
  38. {fred_oss-0.54.0 → fred_oss-0.56.0}/requirements.txt +0 -0
  39. {fred_oss-0.54.0 → fred_oss-0.56.0}/setup.cfg +0 -0
  40. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/cli/__init__.py +0 -0
  41. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/cli/__main__.py +0 -0
  42. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/cli/interface.py +0 -0
  43. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/__init__.py +0 -0
  44. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/__init__.py +0 -0
  45. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/_keyval.py +0 -0
  46. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/_pubsub.py +0 -0
  47. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/_queue.py +0 -0
  48. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/catalog.py +0 -0
  49. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/comp/interface.py +0 -0
  50. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/__init__.py +0 -0
  51. {fred_oss-0.54.0/src/main/fred/future/callback → fred_oss-0.56.0/src/main/fred/dao/service/_minio/policy}/__init__.py +0 -0
  52. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/_redis.py +0 -0
  53. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/_stdlib.py +0 -0
  54. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/catalog.py +0 -0
  55. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/interface.py +0 -0
  56. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/dao/service/utils.py +0 -0
  57. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/__init__.py +0 -0
  58. {fred_oss-0.54.0/src/main/fred/integrations/databricks/runtimes → fred_oss-0.56.0/src/main/fred/future/callback}/__init__.py +0 -0
  59. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/callback/_function.py +0 -0
  60. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/callback/catalog.py +0 -0
  61. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/callback/interface.py +0 -0
  62. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/impl.py +0 -0
  63. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/result.py +0 -0
  64. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/settings.py +0 -0
  65. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/future/utils.py +0 -0
  66. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/__init__.py +0 -0
  67. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/cli_ext.py +0 -0
  68. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/runtime.py +0 -0
  69. {fred_oss-0.54.0/src/main/fred/integrations/databricks/wrappers → fred_oss-0.56.0/src/main/fred/integrations/databricks/runtimes}/__init__.py +0 -0
  70. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/runtimes/scanner.py +0 -0
  71. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/runtimes/sync.py +0 -0
  72. {fred_oss-0.54.0/src/main/fred/utils → fred_oss-0.56.0/src/main/fred/integrations/databricks/wrappers}/__init__.py +0 -0
  73. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/databricks/wrappers/dbutils.py +0 -0
  74. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/runpod/__init__.py +0 -0
  75. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/runpod/cli_ext.py +0 -0
  76. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/integrations/runpod/helper.py +0 -0
  77. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/maturity.py +0 -0
  78. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/monad/__init__.py +0 -0
  79. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/monad/_either.py +0 -0
  80. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/monad/catalog.py +0 -0
  81. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/monad/interface.py +0 -0
  82. {fred_oss-0.54.0/src/main/fred/utils/imout → fred_oss-0.56.0/src/main/fred/rest/router}/__init__.py +0 -0
  83. {fred_oss-0.54.0/src/main/fred/worker/runner/model → fred_oss-0.56.0/src/main/fred/rest/router/catalog}/__init__.py +0 -0
  84. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/settings.py +0 -0
  85. {fred_oss-0.54.0/src/main/fred/worker/runner/plugins → fred_oss-0.56.0/src/main/fred/utils}/__init__.py +0 -0
  86. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/dateops.py +0 -0
  87. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imops.py +0 -0
  88. {fred_oss-0.54.0/src/main/fred/worker/runner/rest → fred_oss-0.56.0/src/main/fred/utils/imout}/__init__.py +0 -0
  89. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imout/_filesystem.py +0 -0
  90. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imout/_minio.py +0 -0
  91. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imout/_string.py +0 -0
  92. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imout/catalog.py +0 -0
  93. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/imout/interface.py +0 -0
  94. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/mlops/__init__.py +0 -0
  95. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/mlops/auto.py +0 -0
  96. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/utils/runtime.py +0 -0
  97. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/version.py +0 -0
  98. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/__init__.py +0 -0
  99. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/interface.py +0 -0
  100. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/__init__.py +0 -0
  101. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/backend.py +0 -0
  102. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/client.py +0 -0
  103. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/handler.py +0 -0
  104. {fred_oss-0.54.0/src/main/fred/worker/runner/rest/routers → fred_oss-0.56.0/src/main/fred/worker/runner/model}/__init__.py +0 -0
  105. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/_handler.py +0 -0
  106. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/_item.py +0 -0
  107. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/_request.py +0 -0
  108. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/_runner_spec.py +0 -0
  109. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/catalog.py +0 -0
  110. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/model/interface.py +0 -0
  111. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/plugins/_local.py +0 -0
  112. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/plugins/_runpod.py +0 -0
  113. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/plugins/catalog.py +0 -0
  114. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/plugins/interface.py +0 -0
  115. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/auth.py +0 -0
  116. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/cli_ext.py +0 -0
  117. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/routers/_runner.py +0 -0
  118. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/routers/catalog.py +0 -0
  119. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/routers/interface.py +0 -0
  120. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/server.py +0 -0
  121. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/rest/settings.py +0 -0
  122. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/settings.py +0 -0
  123. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/signal.py +0 -0
  124. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/status.py +0 -0
  125. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/runner/utils.py +0 -0
  126. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred/worker/settings.py +0 -0
  127. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred_oss.egg-info/dependency_links.txt +0 -0
  128. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred_oss.egg-info/entry_points.txt +0 -0
  129. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred_oss.egg-info/requires.txt +0 -0
  130. {fred_oss-0.54.0 → fred_oss-0.56.0}/src/main/fred_oss.egg-info/top_level.txt +0 -0
@@ -0,0 +1,3 @@
1
+ include requirements.txt
2
+ include src/main/fred/version
3
+ include src/main/fred/dao/service/_minio/policy/templates/*.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-oss
3
- Version: 0.54.0
3
+ Version: 0.56.0
4
4
  Summary: FREDOSS
5
5
  Home-page: https://fred.fahera.mx
6
6
  Author: Fahera Research, Education, and Development
@@ -35,6 +35,8 @@ setup(
35
35
  package_data={
36
36
  "": [
37
37
  version_filepath,
38
+ "**/*.json",
39
+ "**/*.yaml",
38
40
  ]
39
41
  },
40
42
  entry_points={
@@ -0,0 +1,59 @@
1
+ from typing import Optional
2
+
3
+ from fred.version import version
4
+ from fred.settings import logger_manager
5
+ from fred.cli.interface import AbstractCLI
6
+
7
+
8
+ logger = logger_manager.get_logger(name=__name__)
9
+
10
+
11
+ class CLIExtensionGroups:
12
+ """CLI Extensions providing access to various integrations by following a lazy loading pattern."""
13
+
14
+ @property
15
+ def databricks(self):
16
+ from fred.integrations.databricks.cli_ext import DatabricksExt
17
+ return DatabricksExt()
18
+
19
+ @property
20
+ def runpod(self):
21
+ from fred.integrations.runpod.cli_ext import RunPodExt
22
+ return RunPodExt()
23
+
24
+ @property
25
+ def runner_server(self):
26
+ from fred.worker.runner.rest.cli_ext import RunnerServerExt
27
+ return RunnerServerExt()
28
+
29
+
30
+ class CLI(AbstractCLI, CLIExtensionGroups):
31
+
32
+ def version(self) -> str:
33
+ return version.value
34
+
35
+ def serve(
36
+ self,
37
+ classname: Optional[str] = None,
38
+ classpath: Optional[str] = None,
39
+ include_routers: Optional[list[str]] = None,
40
+ exclude_routers: Optional[list[str]] = None,
41
+ fastapi_configs: Optional[dict] = None,
42
+ server_configs: Optional[dict] = None,
43
+ ):
44
+ from fred.rest.server import FredServer
45
+
46
+ include_routers = include_routers or []
47
+ exclude_routers = exclude_routers or []
48
+ fastapi_configs = fastapi_configs or {}
49
+ server_configs = server_configs or {}
50
+
51
+ logger.info("Starting the Fred-REST Server...")
52
+ server = FredServer.auto(
53
+ include_routers=include_routers,
54
+ exclude_routers=exclude_routers,
55
+ router_classname=classname,
56
+ router_classpath=classpath,
57
+ **fastapi_configs,
58
+ )
59
+ server.start(**server_configs)
@@ -0,0 +1 @@
1
+ from .service import MinioService
@@ -0,0 +1,16 @@
1
+ import enum
2
+
3
+
4
+ class MinioPolicyBuilderActionBucket(enum.StrEnum):
5
+ ALL = "s3:*"
6
+ LIST = "s3:ListBucket"
7
+ LOCATION = "s3:GetBucketLocation"
8
+ DELETE = "s3:DeleteBucket"
9
+ CREATE = "s3:CreateBucket"
10
+
11
+
12
+ class MinioPolicyBuilderActionObject(enum.StrEnum):
13
+ GET = "s3:GetObject"
14
+ PUT = "s3:PutObject"
15
+ DELETE = "s3:DeleteObject"
16
+ ALL = "s3:*"
@@ -0,0 +1,28 @@
1
+ import enum
2
+ from typing import Optional
3
+
4
+ from fred.dao.service._minio.policy.loader import MinioPolicyLoader
5
+
6
+
7
+ class MinioPolicyCatalog(enum.Enum):
8
+ BUCKET_PUBLIC_RO = MinioPolicyLoader(
9
+ title="[Bucket Policy] Public Read-Only",
10
+ filename="public_ro.json",
11
+ requires=[
12
+ "bucket_name",
13
+ ],
14
+ )
15
+ BUCKET_PUBLIC_RW = MinioPolicyLoader(
16
+ title="[Bucket Policy] Public Read-Write",
17
+ filename="public_rw.json",
18
+ requires=[
19
+ "bucket_name",
20
+ ],
21
+ )
22
+
23
+ def load(self, path: Optional[str] = None, **params) -> dict:
24
+ return self.value.load(path=path, **params)
25
+
26
+ def content(self, path: Optional[str] = None, **params) -> str:
27
+ import json
28
+ return json.dumps(self.load(path=path, **params))
@@ -0,0 +1,27 @@
1
+ import os
2
+ import json
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional
5
+ def load_policy(filename: str, path: Optional[str] = None, **kwargs) -> dict:
6
+ path = path or os.path.join(os.path.dirname(__file__), "templates")
7
+ filepath = os.path.join(path, filename)
8
+ # Read the policy file as a string
9
+ with open(filepath, "r", encoding="utf-8") as file:
10
+ policy_str = file.read()
11
+ # Replace placeholders in the policy with actual values from kwargs
12
+ for param_key, param_val in kwargs.items():
13
+ param_ref = "${{param_key}}".replace("param_key", param_key)
14
+ policy_str = policy_str.replace(param_ref, param_val)
15
+ return json.loads(policy_str)
16
+
17
+
18
+ @dataclass(frozen=True, slots=True)
19
+ class MinioPolicyLoader:
20
+ title: str
21
+ filename: str
22
+ requires: list[str] = field(default_factory=list)
23
+
24
+ def load(self, path: Optional[str] = None, **kwargs) -> dict:
25
+ if (missing := set(self.requires) - set(kwargs.keys())):
26
+ raise ValueError(f"Missing required parameters for policy '{self.filename}': {missing}")
27
+ return load_policy(filename=self.filename, path=path, **kwargs)
@@ -0,0 +1,24 @@
1
+ {
2
+ "Version": "2012-10-17",
3
+ "Statement": [
4
+ {
5
+ "Effect": "Allow",
6
+ "Principal": {
7
+ "AWS": "*"
8
+ },
9
+ "Action": [
10
+ "s3:GetBucketLocation",
11
+ "s3:ListBucket"
12
+ ],
13
+ "Resource": "arn:aws:s3:::${{bucket_name}}"
14
+ },
15
+ {
16
+ "Effect": "Allow",
17
+ "Principal": {
18
+ "AWS": "*"
19
+ },
20
+ "Action": "s3:GetObject",
21
+ "Resource": "arn:aws:s3:::${{bucket_name}}/*"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "Version": "2012-10-17",
3
+ "Statement": [
4
+ {
5
+ "Effect": "Allow",
6
+ "Principal": {
7
+ "AWS": "*"
8
+ },
9
+ "Action": [
10
+ "s3:GetBucketLocation",
11
+ "s3:ListBucket",
12
+ "s3:ListBucketMultipartUploads"
13
+ ],
14
+ "Resource": "arn:aws:s3:::${{bucket_name}}"
15
+ },
16
+ {
17
+ "Effect": "Allow",
18
+ "Principal": {
19
+ "AWS": "*"
20
+ },
21
+ "Action": [
22
+ "s3:GetObject",
23
+ "s3:PutObject",
24
+ "s3:DeleteObject",
25
+ "s3:ListMultipartUploadParts",
26
+ "s3:AbortMultipartUpload"
27
+ ],
28
+ "Resource": "arn:aws:s3:::${{bucket_name}}/*"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,55 @@
1
+ from urllib3 import PoolManager, Retry
2
+ from urllib3.util import Timeout
3
+
4
+ from fred.settings import get_environ_variable, logger_manager
5
+ from fred.dao.service.interface import ServiceConnectionPoolInterface
6
+
7
+ logger = logger_manager.get_logger(name=__name__)
8
+
9
+
10
+ class MinioConnectionPool(ServiceConnectionPoolInterface[PoolManager]):
11
+
12
+ @classmethod
13
+ def _create_pool(cls, disable_cert: bool = False, **kwargs) -> PoolManager:
14
+ """Create a urllib3 PoolManager with the given configurations.
15
+
16
+ TODO: Consider using the inverse of 'require_cert' as the default to ensure we do have cert-check automatically.
17
+ For now, we keep it as is to avoid breaking changes.
18
+
19
+ Args:
20
+ require_cert (bool): Whether to require SSL certificate verification.
21
+ **kwargs: Additional keyword arguments to pass to the PoolManager constructor.
22
+ Returns:
23
+ PoolManager: A configured PoolManager instance.
24
+ """
25
+ num_pools = kwargs.pop("num_pools", 10)
26
+ maxsize = kwargs.pop("maxsize", 10)
27
+ # Default timeout of 5 minutes
28
+ timeout_seconds = kwargs.pop("timeout", 300)
29
+ timeout = Timeout(
30
+ connect=timeout_seconds,
31
+ read=timeout_seconds,
32
+ )
33
+ # Default retries of 5 with exponential backoff
34
+ retry = Retry(
35
+ total=kwargs.pop("retries", 5),
36
+ backoff_factor=kwargs.pop("backoff_factor", 0.25),
37
+ status_forcelist=[500, 502, 503, 504],
38
+ )
39
+ # Configure certificate requirements for SSL connections
40
+ cert_reqs = "CERT_NONE"
41
+ ca_certs = None
42
+ if not disable_cert:
43
+ import certifi
44
+ cert_reqs = "CERT_REQUIRED"
45
+ ca_certs = get_environ_variable("SSL_CERT_FILE") or certifi.where()
46
+ # Finally, create and return the PoolManager instance
47
+ return PoolManager(
48
+ num_pools=num_pools,
49
+ maxsize=maxsize,
50
+ timeout=timeout,
51
+ retries=retry,
52
+ cert_reqs=cert_reqs,
53
+ ca_certs=ca_certs,
54
+ **kwargs
55
+ )
@@ -1,62 +1,14 @@
1
1
  from minio import Minio
2
- from urllib3 import PoolManager, Retry
3
- from urllib3.util import Timeout
4
2
 
5
- from fred.settings import get_environ_variable, logger_manager
3
+ from fred.settings import logger_manager
4
+ from fred.dao.service.interface import ServiceInterface
6
5
  from fred.dao.service.utils import get_minio_from_payload
7
- from fred.dao.service.interface import ServiceInterface, ServiceConnectionPoolInterface
6
+ from fred.dao.service._minio.pool import MinioConnectionPool
7
+ from fred.dao.service._minio.policy.catalog import MinioPolicyCatalog
8
8
 
9
9
  logger = logger_manager.get_logger(name=__name__)
10
10
 
11
11
 
12
- class MinioConnectionPool(ServiceConnectionPoolInterface[PoolManager]):
13
-
14
- @classmethod
15
- def _create_pool(cls, disable_cert: bool = False, **kwargs) -> PoolManager:
16
- """Create a urllib3 PoolManager with the given configurations.
17
-
18
- TODO: Consider using the inverse of 'require_cert' as the default to ensure we do have cert-check automatically.
19
- For now, we keep it as is to avoid breaking changes.
20
-
21
- Args:
22
- require_cert (bool): Whether to require SSL certificate verification.
23
- **kwargs: Additional keyword arguments to pass to the PoolManager constructor.
24
- Returns:
25
- PoolManager: A configured PoolManager instance.
26
- """
27
- num_pools = kwargs.pop("num_pools", 10)
28
- maxsize = kwargs.pop("maxsize", 10)
29
- # Default timeout of 5 minutes
30
- timeout_seconds = kwargs.pop("timeout", 300)
31
- timeout = Timeout(
32
- connect=timeout_seconds,
33
- read=timeout_seconds,
34
- )
35
- # Default retries of 5 with exponential backoff
36
- retry = Retry(
37
- total=kwargs.pop("retries", 5),
38
- backoff_factor=kwargs.pop("backoff_factor", 0.25),
39
- status_forcelist=[500, 502, 503, 504],
40
- )
41
- # Configure certificate requirements for SSL connections
42
- cert_reqs = "CERT_NONE"
43
- ca_certs = None
44
- if not disable_cert:
45
- import certifi
46
- cert_reqs = "CERT_REQUIRED"
47
- ca_certs = get_environ_variable("SSL_CERT_FILE") or certifi.where()
48
- # Finally, create and return the PoolManager instance
49
- return PoolManager(
50
- num_pools=num_pools,
51
- maxsize=maxsize,
52
- timeout=timeout,
53
- retries=retry,
54
- cert_reqs=cert_reqs,
55
- ca_certs=ca_certs,
56
- **kwargs
57
- )
58
-
59
-
60
12
  class MinioService(ServiceInterface[Minio]):
61
13
  instance: Minio
62
14
  metadata: dict = {}
@@ -120,3 +72,12 @@ class MinioService(ServiceInterface[Minio]):
120
72
  except S3Error:
121
73
  logger.debug(f"Object {object_name} in bucket {bucket_name} does not exist.")
122
74
  return False
75
+
76
+ def make_bucket_public(self, bucket_name: str, readonly: bool = False):
77
+ """Make a bucket public with either read-only or read-write access."""
78
+ policy = MinioPolicyCatalog.BUCKET_PUBLIC_RO \
79
+ if readonly else MinioPolicyCatalog.BUCKET_PUBLIC_RW
80
+ self.client.set_bucket_policy(
81
+ bucket_name=bucket_name,
82
+ policy=policy.content(bucket_name=bucket_name)
83
+ )
@@ -0,0 +1,10 @@
1
+ {
2
+ "python_version": "3.12.3",
3
+ "databricks_runtime": "16.4 LTS",
4
+ "libraries": [
5
+ {
6
+ "name": "pydantic",
7
+ "version": "2.8.2"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,17 @@
1
+ """
2
+ [Fred-REST] Fred's Simple Extensible REST-API Server
3
+ ========================================================
4
+ This module provides a simple and extensible REST-API server implementation using FastAPI.
5
+ It includes configurations for authentication, router management, and server startup.
6
+ """
7
+ from fred.maturity import Maturity, MaturityLevel
8
+
9
+
10
+ module_maturity = Maturity(
11
+ level=MaturityLevel.ALPHA,
12
+ reference=__name__,
13
+ message=(
14
+ "Fred-REST implementation is in early development "
15
+ "and therefore currently with incomplete and unstable features."
16
+ )
17
+ )
@@ -0,0 +1,23 @@
1
+ from fastapi import Security, HTTPException, status
2
+ from fastapi.security import APIKeyHeader
3
+
4
+ from fred.rest.settings import FRD_RESTAPI_TOKEN
5
+
6
+
7
+ async def verify_key(
8
+ api_key_header: str = Security(
9
+ APIKeyHeader(
10
+ name="X-API-Key",
11
+ auto_error=False
12
+ )
13
+ ),
14
+ ):
15
+ """
16
+ Verify the provided API key against the expected token.
17
+ Raises an HTTPException if the key is invalid or missing.
18
+ """
19
+ if api_key_header != FRD_RESTAPI_TOKEN:
20
+ raise HTTPException(
21
+ status_code=status.HTTP_401_UNAUTHORIZED,
22
+ detail="Invalid or missing API Key",
23
+ )
@@ -0,0 +1,32 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from fred.rest.router.catalog.interface import RouterCatalogInterface
5
+ from fred.rest.settings import (
6
+ FRD_RESTAPI_ROUTERCATALOG_CLASSPATH,
7
+ FRD_RESTAPI_ROUTERCATALOG_CLASSNAME,
8
+ )
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class ServerRouterCatalogConfig:
12
+ classname: str
13
+ classpath: str
14
+
15
+ @classmethod
16
+ def auto(cls, classname: Optional[str] = None, classpath: Optional[str] = None) -> "ServerRouterCatalogConfig":
17
+ return cls(
18
+ classname=classname or FRD_RESTAPI_ROUTERCATALOG_CLASSNAME,
19
+ classpath=classpath or FRD_RESTAPI_ROUTERCATALOG_CLASSPATH,
20
+ )
21
+
22
+ @property
23
+ def catalog(self) -> type[RouterCatalogInterface]:
24
+ import importlib
25
+
26
+ module = importlib.import_module(self.classpath)
27
+ catalog_class = getattr(module, self.classname, None)
28
+ if catalog_class is None:
29
+ raise ImportError(f"Could not find class '{self.classname}' in module '{self.classpath}'")
30
+ if not issubclass(catalog_class, RouterCatalogInterface):
31
+ raise TypeError(f"Class '{self.classname}' is not a subclass of RouterCatalogInterface")
32
+ return catalog_class
@@ -0,0 +1,10 @@
1
+ from fred.rest.router.catalog.default.catalog import RouterCatalog
2
+ from fred.settings import logger_manager
3
+
4
+ logger = logger_manager.get_logger(name=__name__)
5
+
6
+
7
+ logger.warning(
8
+ "You are using the default router catalog intended for demonstration purposes only. "
9
+ "For production use, please implement a custom router catalog."
10
+ )
@@ -0,0 +1,29 @@
1
+ from fred.rest.router.interface import RouterInterfaceMixin
2
+ from fred.rest.router.endpoint import RouterEndpointAnnotation
3
+
4
+
5
+ class RouterBaseMixin(RouterInterfaceMixin):
6
+
7
+ @RouterEndpointAnnotation.set(
8
+ path="/",
9
+ methods=["GET"],
10
+ summary="Base endpoint",
11
+ description="A simple base endpoint to check service availability."
12
+ )
13
+ def base(self, include_telemetry: bool = False, **kwargs) -> dict:
14
+ if include_telemetry:
15
+ from fred.utils.runtime import RuntimeProfilingSnapshot
16
+ kwargs["telemetry"] = RuntimeProfilingSnapshot.auto().to_dict()
17
+ return {
18
+ "ok": True,
19
+ **kwargs
20
+ }
21
+
22
+ @RouterEndpointAnnotation.set(
23
+ path="/passthrough",
24
+ methods=["POST"],
25
+ summary="Passthrough POST endpoint",
26
+ description="An endpoint that returns all received parameters.",
27
+ )
28
+ def passthrough(self, **kwargs) -> dict:
29
+ return kwargs
@@ -0,0 +1,31 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from fred.rest.router.interface import RouterInterfaceMixin
5
+ from fred.rest.router.endpoint import RouterEndpointAnnotation
6
+
7
+
8
+ class RouterExampleMixin(RouterInterfaceMixin):
9
+
10
+ @RouterEndpointAnnotation.set(
11
+ path="/ping",
12
+ methods=["GET"],
13
+ summary="Ping endpoint",
14
+ description="A simple ping endpoint to check service availability.",
15
+ )
16
+ def ping(self, pong: Optional[str] = None, **kwargs) -> dict:
17
+ from fred.utils.dateops import datetime_utcnow
18
+
19
+ return {
20
+ "ping_time": datetime_utcnow().isoformat(),
21
+ "ping_response": pong or "pong",
22
+ }
23
+
24
+ @RouterEndpointAnnotation.set(
25
+ path="/passthrough",
26
+ methods=["GET"],
27
+ summary="Passthrough GET endpoint",
28
+ description="An endpoint that returns all received parameters.",
29
+ )
30
+ def passthrough(self, **kwargs) -> dict:
31
+ return kwargs
@@ -0,0 +1,20 @@
1
+ import enum
2
+
3
+ from fred.rest.router.config import RouterConfig
4
+ from fred.rest.router.catalog.default._base import RouterBaseMixin
5
+ from fred.rest.router.catalog.default._example import RouterExampleMixin
6
+
7
+ from fred.rest.router.catalog.interface import RouterCatalogInterface
8
+
9
+
10
+ class RouterCatalog(RouterCatalogInterface, enum.Enum):
11
+ BASE = RouterConfig.auto(prefix="")(apply=RouterBaseMixin)
12
+ EXAMPLE = RouterConfig.auto(prefix="/example")(apply=RouterExampleMixin)
13
+
14
+ def get_kwargs(self) -> dict:
15
+ match self:
16
+ case RouterCatalog.EXAMPLE:
17
+ # Disable the backend for the example router
18
+ return {"disregard_backend": True}
19
+ case _:
20
+ return {}
@@ -0,0 +1,11 @@
1
+ from fred.rest.router.interface import RouterInterface
2
+
3
+
4
+ class RouterCatalogInterface:
5
+
6
+ def auto(self, **kwargs) -> RouterInterface:
7
+ return self.value.reference.auto(**kwargs)
8
+
9
+ def get_kwargs(self) -> dict:
10
+ # This method can be overridden to provide specific kwargs for router initialization
11
+ return {}
@@ -0,0 +1,40 @@
1
+ from dataclasses import dataclass
2
+
3
+ from fred.rest.router.interface import RouterInterface, RouterInterfaceMixin
4
+
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class RouterConfig:
8
+ prefix: str
9
+ other: dict
10
+
11
+ @classmethod
12
+ def auto(cls, prefix: str = "", **kwargs) -> "RouterConfig":
13
+ return cls(
14
+ prefix=prefix,
15
+ other=kwargs,
16
+ )
17
+
18
+ def get_applied_configs(self, router_class: type[RouterInterface]) -> "AppliedRouterConfig":
19
+ return AppliedRouterConfig(
20
+ reference=router_class,
21
+ config=self,
22
+ )
23
+
24
+ def __call__(self, apply: type[RouterInterfaceMixin]) -> "AppliedRouterConfig":
25
+ router_classname = f"Router{apply.__name__}"
26
+ return self.get_applied_configs(
27
+ router_class=type(router_classname, (RouterInterface, apply, ), {})
28
+ )
29
+
30
+ def get_configs(self) -> dict:
31
+ return {
32
+ "prefix": self.prefix,
33
+ **self.other,
34
+ }
35
+
36
+
37
+ @dataclass(frozen=True, slots=True)
38
+ class AppliedRouterConfig:
39
+ reference: type[RouterInterface]
40
+ config: RouterConfig