cs-image-system-contract 0.1.4__py3-none-any.whl
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.
- cs_image_system/contract/__init__.py +32 -0
- cs_image_system/contract/assets.py +230 -0
- cs_image_system/contract/constants.py +208 -0
- cs_image_system/contract/core.py +262 -0
- cs_image_system/contract/executables.py +55 -0
- cs_image_system/contract/field_kinds.py +96 -0
- cs_image_system/contract/fields.py +101 -0
- cs_image_system/contract/group.py +117 -0
- cs_image_system/contract/hcl.py +74 -0
- cs_image_system/contract/image.py +61 -0
- cs_image_system/contract/instance.py +23 -0
- cs_image_system/contract/lifecycle.py +71 -0
- cs_image_system/contract/lifecycles.py +86 -0
- cs_image_system/contract/metadata.py +54 -0
- cs_image_system/contract/model_config.py +23 -0
- cs_image_system/contract/modification.py +36 -0
- cs_image_system/contract/names.py +33 -0
- cs_image_system/contract/operating_system.py +104 -0
- cs_image_system/contract/runtime.py +155 -0
- cs_image_system/contract/state.py +136 -0
- cs_image_system/contract/storage.py +49 -0
- cs_image_system/contract/testing.py +175 -0
- cs_image_system/contract/user.py +59 -0
- cs_image_system/py.typed +0 -0
- cs_image_system_contract-0.1.4.dist-info/METADATA +244 -0
- cs_image_system_contract-0.1.4.dist-info/RECORD +28 -0
- cs_image_system_contract-0.1.4.dist-info/WHEEL +4 -0
- cs_image_system_contract-0.1.4.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Mykel Alvis <mykelalvis@infrastructurebuilder.org>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""The plugin contract (stage 30).
|
|
6
|
+
|
|
7
|
+
A plugin is written against this package and nothing else: the protocols a
|
|
8
|
+
model and a builder satisfy, the constants and field helpers a model is
|
|
9
|
+
declared with, the lifecycle phases a hook keys on, and the data carriers a
|
|
10
|
+
hook returns (assets, command lists, a state backend's registration). The
|
|
11
|
+
core (``cs_image_system.base``) implements the contract with its base
|
|
12
|
+
classes, which are the convenient implementation and not the contract
|
|
13
|
+
itself; a class that satisfies the protocols structurally is a first-class
|
|
14
|
+
plugin.
|
|
15
|
+
|
|
16
|
+
One module per kind of builder, over a shared core:
|
|
17
|
+
|
|
18
|
+
- :mod:`.core` -- what every model and every builder is to the system;
|
|
19
|
+
- :mod:`.runtime`, :mod:`.operating_system`, :mod:`.storage`, :mod:`.image`,
|
|
20
|
+
:mod:`.instance`, :mod:`.modification`, :mod:`.group`, :mod:`.user`,
|
|
21
|
+
:mod:`.state` -- the model and builder protocols of each kind;
|
|
22
|
+
- :mod:`.constants`, :mod:`.model_config`, :mod:`.fields`,
|
|
23
|
+
:mod:`.field_kinds`, :mod:`.lifecycle`, :mod:`.lifecycles`,
|
|
24
|
+
:mod:`.assets`, :mod:`.executables`, :mod:`.metadata`, :mod:`.names`,
|
|
25
|
+
:mod:`.hcl` -- what a plugin declares, constructs and returns;
|
|
26
|
+
- :mod:`.testing` -- ``assert_conforms``, the signature-level check the
|
|
27
|
+
core's tests run over every base class and every built-in plugin.
|
|
28
|
+
|
|
29
|
+
The contract imports nothing from the core: a test holds the direction.
|
|
30
|
+
The kind modules import :mod:`.core` and only the kinds they declare they
|
|
31
|
+
read.
|
|
32
|
+
"""
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Mykel Alvis <mykelalvis@infrastructurebuilder.org>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""What a ``generate_items_*`` hook returns: assets, each a destination path
|
|
6
|
+
and a value, gathered in an :class:`AssetSet`. In the contract since stage
|
|
7
|
+
30 (``cs_image_system.base.basic.asset`` re-exports both); writing an asset
|
|
8
|
+
set takes the generation path as an argument, so nothing here reaches the
|
|
9
|
+
run context."""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
import tempfile
|
|
15
|
+
from typing import Any, overload
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Asset:
|
|
24
|
+
"""Represents an asset to be included in the image build. This is a tuple of
|
|
25
|
+
(source_path, destination_path) where source_path is the path to the asset on
|
|
26
|
+
the local filesystem and destination_path is the path where the asset should
|
|
27
|
+
be placed in the image. The source_path must exist and be a file or directory.
|
|
28
|
+
The destination_path is relative to the root of the image and should not start
|
|
29
|
+
with a leading slash. This class provides validation and utility methods for
|
|
30
|
+
working with assets, including ensuring that source paths exist and are valid,
|
|
31
|
+
and that destination paths are well-formed. It also provides a method to
|
|
32
|
+
generate a dictionary representation of the asset for use in configuration files
|
|
33
|
+
or other contexts where a structured representation is needed. This class is
|
|
34
|
+
designed to be used in conjunction with builders that need to include additional files or directories in the image, allowing for a clear and consistent way to specify and manage these assets throughout the build process.
|
|
35
|
+
|
|
36
|
+
Note that the path should usually be relative, and on remote assets is rooted off the primary
|
|
37
|
+
fileystem location ( i.e. / )
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self,
|
|
41
|
+
asset_tuple: tuple[Path, Any],
|
|
42
|
+
absolute: bool = False,
|
|
43
|
+
remote: bool = False) -> None:
|
|
44
|
+
destination_path, val = asset_tuple
|
|
45
|
+
self._tuple = asset_tuple
|
|
46
|
+
self._binary = isinstance(val, bytes)
|
|
47
|
+
self._remote = remote or destination_path.is_absolute()
|
|
48
|
+
if destination_path.is_absolute() and not absolute:
|
|
49
|
+
log.warning(f"Destination path '{destination_path}' should probably not be absolute.")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def path(self) -> Path:
|
|
53
|
+
return self._tuple[0]
|
|
54
|
+
@property
|
|
55
|
+
def value(self) -> Any:
|
|
56
|
+
return self._tuple[1]
|
|
57
|
+
@property
|
|
58
|
+
def str_value(self) -> str|None:
|
|
59
|
+
return self.value if not self._binary else None
|
|
60
|
+
@property
|
|
61
|
+
def binary_value(self) -> bytes|None:
|
|
62
|
+
return self.value if self._binary else None
|
|
63
|
+
@property
|
|
64
|
+
def is_remote(self) -> bool:
|
|
65
|
+
return self._remote
|
|
66
|
+
@property
|
|
67
|
+
def is_binary(self) -> bool:
|
|
68
|
+
return self._binary
|
|
69
|
+
@property
|
|
70
|
+
def str_tuple(self) -> tuple[Path, str] | None:
|
|
71
|
+
return self._tuple if not self._binary else None
|
|
72
|
+
@property
|
|
73
|
+
def binary_tuple(self) -> tuple[Path, bytes] | None:
|
|
74
|
+
return self._tuple if self._binary else None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class AssetSet(list[Asset]):
|
|
78
|
+
"""A set of assets to be included in the image build. This class provides
|
|
79
|
+
utility methods for working with sets of assets, including validation and
|
|
80
|
+
generation of structured representations for use in configuration files or
|
|
81
|
+
other contexts where a structured representation is needed. This class is
|
|
82
|
+
designed to be used in conjunction with builders that need to include multiple
|
|
83
|
+
files or directories in the image, allowing for a clear and consistent way to
|
|
84
|
+
specify and manage these assets throughout the build process.
|
|
85
|
+
|
|
86
|
+
This returns a mapping of the remote assets to temp files containing those
|
|
87
|
+
assets. This allows the builder to work with remote assets as if they were local files,
|
|
88
|
+
while still ensuring that the remote assets are properly included in the image build.
|
|
89
|
+
"""
|
|
90
|
+
def __init__(self, default_path: Path | None = None) -> None:
|
|
91
|
+
super().__init__()
|
|
92
|
+
self.default_path = default_path
|
|
93
|
+
|
|
94
|
+
def with_default_path(self, default_path: Path) -> "AssetSet":
|
|
95
|
+
"""Returns a new AssetSet with the given default path. This allows for a more fluent interface when adding assets that share a common destination path."""
|
|
96
|
+
if self.default_path is not None and self.default_path != default_path:
|
|
97
|
+
raise ValueError(f"Cannot set default path to '{default_path}' because "
|
|
98
|
+
f"it is already set to '{self.default_path}'.")
|
|
99
|
+
self.default_path = default_path
|
|
100
|
+
return self
|
|
101
|
+
|
|
102
|
+
# 1. Overload names must match the implementation
|
|
103
|
+
@overload
|
|
104
|
+
def add(self, item: Path, value: Any) -> None: ...
|
|
105
|
+
|
|
106
|
+
@overload
|
|
107
|
+
def add(self, item: Any) -> None: ...
|
|
108
|
+
|
|
109
|
+
# 2. The implementation names now match 'item'
|
|
110
|
+
def add(self, item: Path | Any, value: Any = None) -> None:
|
|
111
|
+
if isinstance(item, Path):
|
|
112
|
+
path = item
|
|
113
|
+
val = value
|
|
114
|
+
else:
|
|
115
|
+
if self.default_path is None:
|
|
116
|
+
raise ValueError("Cannot add value without a default_path set.")
|
|
117
|
+
path = self.default_path
|
|
118
|
+
val = item
|
|
119
|
+
# if val.endswith("\n"):
|
|
120
|
+
# log.warning(f"Value for asset at path '{path}' ends with a newline. This may cause issues when writing the asset to a file.")
|
|
121
|
+
if not val:
|
|
122
|
+
if val is None:
|
|
123
|
+
log.warning(f"Value for asset at path '{path}' is None.")
|
|
124
|
+
return
|
|
125
|
+
if isinstance(val, list):
|
|
126
|
+
for v in val:
|
|
127
|
+
if not isinstance(v, (str)):
|
|
128
|
+
raise ValueError(f"List values for asset at path '{path}' must be strings, got {type(v)}")
|
|
129
|
+
self._appendx(path, v)
|
|
130
|
+
else:
|
|
131
|
+
self._appendx(path, val)
|
|
132
|
+
|
|
133
|
+
def _appendx(self, item: Path, value: str ) -> None:
|
|
134
|
+
self.append(Asset((item, value.strip("\n"))))
|
|
135
|
+
|
|
136
|
+
@overload
|
|
137
|
+
def add_list(self, item: Path, value: Any) -> None: ...
|
|
138
|
+
|
|
139
|
+
@overload
|
|
140
|
+
def add_list(self, item: Any) -> None: ...
|
|
141
|
+
|
|
142
|
+
def add_list(self, item: Path, value: list[Any] | None = None) -> None:
|
|
143
|
+
if isinstance(item, Path):
|
|
144
|
+
path = item
|
|
145
|
+
val = value
|
|
146
|
+
else:
|
|
147
|
+
if self.default_path is None:
|
|
148
|
+
raise ValueError("Cannot add value without a default_path set.")
|
|
149
|
+
path = self.default_path
|
|
150
|
+
val = item
|
|
151
|
+
if not val:
|
|
152
|
+
if val is None:
|
|
153
|
+
log.warning(f"Value for asset list at path '{path}' is None.")
|
|
154
|
+
return
|
|
155
|
+
if not isinstance(val, list):
|
|
156
|
+
raise ValueError(f"Value must be a list, got {type(val)}")
|
|
157
|
+
for v in val:
|
|
158
|
+
self.add(path, v)
|
|
159
|
+
|
|
160
|
+
def extend(self, assets: Iterable[Asset]) -> None:
|
|
161
|
+
for asset in assets:
|
|
162
|
+
self.append(asset)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def sort_and_write(self,
|
|
166
|
+
gen_path: Path,
|
|
167
|
+
temp_loc: Path = Path("./temp_assets"),
|
|
168
|
+
skip_remote: bool = False,
|
|
169
|
+
skip_writes: bool = False) -> dict[Path, Path]:
|
|
170
|
+
"""Write every asset under ``gen_path`` (stage 30: the caller names the
|
|
171
|
+
generation path; until then an omitted path was read from the run
|
|
172
|
+
context, the one reach into the core this module had). Local assets
|
|
173
|
+
land at ``gen_path / asset.path``, remote ones in temporary files
|
|
174
|
+
under ``gen_path / temp_loc``; the mapping returned is remote path to
|
|
175
|
+
temporary file."""
|
|
176
|
+
|
|
177
|
+
remote_write_mapping: dict[Path, Path] = {}
|
|
178
|
+
write_str_map: dict[Path, list[str]] = {}
|
|
179
|
+
write_bin_map: dict[Path, list[bytes]] = {}
|
|
180
|
+
write_remote_str_map: dict[Path, list[str]] = {}
|
|
181
|
+
write_remote_bin_map: dict[Path, list[bytes]] = {}
|
|
182
|
+
wrote_paths: set[Path] = set()
|
|
183
|
+
for asset in self:
|
|
184
|
+
if not asset.is_remote or (asset.is_remote and not skip_remote):
|
|
185
|
+
if asset.is_remote:
|
|
186
|
+
d = write_remote_str_map if not asset.is_binary else write_remote_bin_map
|
|
187
|
+
else:
|
|
188
|
+
d = write_str_map if not asset.is_binary else write_bin_map
|
|
189
|
+
d.setdefault(asset.path, []).append(asset.value)
|
|
190
|
+
if not skip_writes:
|
|
191
|
+
for path, str_values in write_str_map.items():
|
|
192
|
+
_gp = gen_path / path
|
|
193
|
+
_gp.parent.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
mode = 'w' if _gp.exists() else 'a'
|
|
195
|
+
with _gp.open(mode) as f:
|
|
196
|
+
wrote_paths.add(_gp)
|
|
197
|
+
f.write("\n".join(str_values))
|
|
198
|
+
for path, bin_values in write_bin_map.items():
|
|
199
|
+
_gp = gen_path / path
|
|
200
|
+
_gp.parent.mkdir(parents=True, exist_ok=True)
|
|
201
|
+
mode = 'wb' if _gp.exists() else 'ab'
|
|
202
|
+
with _gp.open(mode) as f:
|
|
203
|
+
wrote_paths.add(_gp)
|
|
204
|
+
for bv in bin_values:
|
|
205
|
+
f.write(bv)
|
|
206
|
+
if not skip_remote:
|
|
207
|
+
_temploc = gen_path / temp_loc
|
|
208
|
+
os.makedirs(_temploc, exist_ok=True)
|
|
209
|
+
for path, str_values in write_remote_str_map.items():
|
|
210
|
+
with tempfile.NamedTemporaryFile(dir=_temploc,
|
|
211
|
+
mode='w+t',
|
|
212
|
+
suffix = path.suffix,
|
|
213
|
+
delete=False) as tmp_file:
|
|
214
|
+
tmp_file.write("\n".join(str_values))
|
|
215
|
+
tmp_file.flush()
|
|
216
|
+
wrote_paths.add(Path(tmp_file.name).absolute())
|
|
217
|
+
remote_write_mapping[path] = Path(tmp_file.name).absolute()
|
|
218
|
+
for path, bin_values in write_remote_bin_map.items():
|
|
219
|
+
with tempfile.NamedTemporaryFile(dir=_temploc,
|
|
220
|
+
mode='w+b',
|
|
221
|
+
suffix = path.suffix,
|
|
222
|
+
delete=False) as tmp_file:
|
|
223
|
+
for bv in bin_values:
|
|
224
|
+
tmp_file.write(bv)
|
|
225
|
+
tmp_file.flush()
|
|
226
|
+
wrote_paths.add(Path(tmp_file.name).absolute())
|
|
227
|
+
remote_write_mapping[path] = Path(tmp_file.name).absolute()
|
|
228
|
+
if wrote_paths: log.debug(f"Wrote assets to the following paths: {wrote_paths}")
|
|
229
|
+
|
|
230
|
+
return remote_write_mapping
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Mykel Alvis <mykelalvis@infrastructurebuilder.org>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""The constants a plugin declares its models with (stage 30: moved here
|
|
6
|
+
from ``cs_image_system.base.constants``, which re-exports them): the
|
|
7
|
+
sentinels that mean "not set", the classification enum ``VCT``, the field
|
|
8
|
+
metadata keys the field helpers stamp, the entry-point groups, the
|
|
9
|
+
collection names and the file names a run writes."""
|
|
10
|
+
|
|
11
|
+
from enum import Enum, StrEnum
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
NAME = "name"
|
|
15
|
+
TYPE = "type"
|
|
16
|
+
VERBOSE: str = "verbose"
|
|
17
|
+
DEFAULT_CONFIG_FILE: str = "./image-actions.yml"
|
|
18
|
+
DEFAULT: str = "default"
|
|
19
|
+
ALL: str = "ALL" # ALL CAPS 'ALL' is a magic value that means "all groups, everywhere". Use with caution. This is basically saying "I don't care about groups, anyone can use it"
|
|
20
|
+
SELF = "self"
|
|
21
|
+
NONE = "none"
|
|
22
|
+
# The words that mean "not set" wherever a value is read, so nothing may be NAMED
|
|
23
|
+
# after one of them (stage 76). A field that gives one of them a meaning of its own
|
|
24
|
+
# (the update policy's `none`, `--only none`) tests for it by name, never through
|
|
25
|
+
# this list.
|
|
26
|
+
OOPS_DEFAULTS: list[str | None] = [DEFAULT, None, "", SELF, NONE]
|
|
27
|
+
SOURCE_MODEL: str = "SourceModel"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
RUNTIME_PROVIDER_TYPE: str = "runtime"
|
|
31
|
+
CLOUD_PROVIDER_TYPE: str = "cloud_provider"
|
|
32
|
+
CONTAINER_PROVIDER_TYPE: str = "container_provider"
|
|
33
|
+
STATE_BACKEND_TYPE: str = "state_backend"
|
|
34
|
+
S3_TYPE: str = "s3"
|
|
35
|
+
STATE_BACKEND_FIELD: str = "state_configuration"
|
|
36
|
+
|
|
37
|
+
CONFIGURED_OS: str = "configured_os_builders"
|
|
38
|
+
CONFIGURED_IMAGE: str = "configured_image_builders"
|
|
39
|
+
CONFIGURED_MOD: str = "configured_mod_builders"
|
|
40
|
+
CONFIGURED_INSTANCE: str = "configured_instance_builders"
|
|
41
|
+
CONFIGURED_RUNTIME: str = "configured_runtime_providers"
|
|
42
|
+
CONFIGURED_STORAGE: str = "configured_storage_providers"
|
|
43
|
+
CONFIGURED_GROUP: str = "configured_group_builders"
|
|
44
|
+
CONFIGURED_USER: str = "configured_user_builders"
|
|
45
|
+
ALL_SORTED_BUILDERS: str = "all_sorted_builders"
|
|
46
|
+
STATE_SETUPS: str = "state_setups"
|
|
47
|
+
DEFAULT_IMAGES_PER_RUNTIME_BUILDER: str = "default_images_per_rtb"
|
|
48
|
+
|
|
49
|
+
EXECUTABLES: str = "executables"
|
|
50
|
+
FORCE: str = "force"
|
|
51
|
+
ONLY_PROVIDERS: str = "only_providers"
|
|
52
|
+
WORKING_PATH: str = "working_path"
|
|
53
|
+
GLOBAL_CONFIG: str = "config"
|
|
54
|
+
LIFECYCLE: str = "lifecycle"
|
|
55
|
+
CONFIG_FILE: str = "config_file"
|
|
56
|
+
GENERATION_PATH: str = "generation_path"
|
|
57
|
+
BASE_IMAGES = "base_images"
|
|
58
|
+
IMAGES = "images"
|
|
59
|
+
STORAGES = "storages"
|
|
60
|
+
GROUPS = "groups"
|
|
61
|
+
ROOT_GROUP = "root_group"
|
|
62
|
+
USERS = "users"
|
|
63
|
+
INSTANCES = "instances"
|
|
64
|
+
DEFAULT_GITIGNORE_ENTRIES = [
|
|
65
|
+
"# DO NOT EDIT THIS FILE.",
|
|
66
|
+
"# This .gitignore file is auto-generated by cs-image-action.",
|
|
67
|
+
"# It includes default entries to ignore SOME generated files ",
|
|
68
|
+
"# and directories. ",
|
|
69
|
+
"target/",
|
|
70
|
+
".terraform/",
|
|
71
|
+
"terraform.tfstate",
|
|
72
|
+
"terraform.tfstate.backup",
|
|
73
|
+
"!.terraform.lock.hcl",
|
|
74
|
+
# hygiene XII item 24 (the walk's F52): the identity runner's list of sanctioned
|
|
75
|
+
# membership removals belongs beside the plan, in the private mirror; wherever a
|
|
76
|
+
# copy lands under generated/, it is never staged (it names a person)
|
|
77
|
+
"csis-sanctioned-removals.txt",
|
|
78
|
+
]
|
|
79
|
+
# stage 49: the private mirror, beside generated/ under the configuration root.
|
|
80
|
+
# It holds the plaintext of every value the emission carries as ciphertext, so
|
|
81
|
+
# it is never committed: ignored here, refused by path, skipped by the scanner.
|
|
82
|
+
PRIVATE_DIRNAME = "_private"
|
|
83
|
+
# stage 43: the run-local files a run writes at the top of generated/ and never
|
|
84
|
+
# commits -- the emitted root .gitignore names them, the run's commit excludes
|
|
85
|
+
# them and drops them from the index where an older tree tracked them (the
|
|
86
|
+
# strict state query rewrites the report outside any run, so a tracked copy
|
|
87
|
+
# dirtied the checkout after every preflight)
|
|
88
|
+
RUN_SUMMARY_FILENAME = "run-summary.json"
|
|
89
|
+
STATE_REPORT_FILENAME = "state-report.json"
|
|
90
|
+
PACKER_MANIFEST_FILENAME: str = "manifest.json" # packer's post-processor output, read for the build's artifact id
|
|
91
|
+
# Run-local (stage 43, 48.6): what a run writes for itself and never commits -- the summary,
|
|
92
|
+
# the state report and packer's manifest (its artifact ids are recorded in lineage; the
|
|
93
|
+
# file itself landed in the record once and is noise there). Ignored under generated/.
|
|
94
|
+
RUN_LOCAL_FILENAMES: tuple[str, ...] = (RUN_SUMMARY_FILENAME, STATE_REPORT_FILENAME, PACKER_MANIFEST_FILENAME)
|
|
95
|
+
SAVED_LOAD_DICT = "_saved_dict_from_load"
|
|
96
|
+
ANY_AT_ALL = "ANY_AT_ALL"
|
|
97
|
+
|
|
98
|
+
INVALID_CONFIG_KEYS = [ "self", "this", "same", "runtime",
|
|
99
|
+
"os", "default", "defaults", "any",
|
|
100
|
+
"anything", "none", "null", "" ,
|
|
101
|
+
"timestamp", "date", "datetime",
|
|
102
|
+
"config", "configuration",]
|
|
103
|
+
|
|
104
|
+
IS_DEFERRED_LIST_GENERATED = "is_deferred_list_generated"
|
|
105
|
+
DEFERRED_BUILDER_VCT = "deferred_builder_vct"
|
|
106
|
+
DEFERRED_ITEM_VCT = "deferred_item_vct"
|
|
107
|
+
FK_ALSO_SET_ON_UPDATE = "fk_also_set_on_update"
|
|
108
|
+
IS_DEFERRED_LIST_FK = "is_deferred_list_fk"
|
|
109
|
+
IS_FK = "is_fk"
|
|
110
|
+
FK_TARGET = "fk_target"
|
|
111
|
+
IS_REPLACE = "is_replace"
|
|
112
|
+
REPLACE_VALUE = "replace_value"
|
|
113
|
+
# Open discriminator: names a field's late-binding "kind" (see field_kinds.py).
|
|
114
|
+
# Derived from the legacy boolean flags above when absent; plugins may set it
|
|
115
|
+
# explicitly to register a brand-new kind + handler.
|
|
116
|
+
FIELD_KIND = "field_kind"
|
|
117
|
+
|
|
118
|
+
NO_MODEL_ID = "__NoParentModel__"
|
|
119
|
+
UNSET_MODEL_ID = "__UNSETMODELID__"
|
|
120
|
+
class VCT(StrEnum):
|
|
121
|
+
"""Enum for valid classification types."""
|
|
122
|
+
UNCLASSIFIED = "__NMC__"
|
|
123
|
+
RUNTIME_BUILDER_MODEL = "runtime_builder_model"
|
|
124
|
+
RUNTIME_BUILDER = "runtime_builder"
|
|
125
|
+
CLOUD_BUILDER_MODEL = "cloud_builder_model"
|
|
126
|
+
CLOUD_BUILDER = "cloud_builder"
|
|
127
|
+
CONTAINER_BUILDER_MODEL = "container_builder_model"
|
|
128
|
+
CONTAINER_BUILDER = "container_builder"
|
|
129
|
+
USER_BUILDER_MODEL = "user_builder_model"
|
|
130
|
+
USER_BUILDER = "user_builder"
|
|
131
|
+
GROUP_BUILDER_MODEL = "group_builder_model"
|
|
132
|
+
GROUP_BUILDER = "group_builder"
|
|
133
|
+
OS_BUILDER_MODEL = "os_builder_model"
|
|
134
|
+
OS_BUILDER = "os_builder"
|
|
135
|
+
OS_IMAGE_BUILDER_SUBCONFIG = "os_image_builder_subconfig"
|
|
136
|
+
OS_IMAGE_BUILDER_SUBCONFIG_MODEL = "os_image_builder_subconfig_model"
|
|
137
|
+
IMAGE_BUILDER_MODEL = "image_builder_model"
|
|
138
|
+
IMAGE_BUILDER = "image_builder"
|
|
139
|
+
IMAGE_IMAGE_BUILDER_SUBCONFIG_MODEL = "image_image_builder_subconfig_model"
|
|
140
|
+
STORAGE_MAPPING_ITEM_MODEL = "storage_mapping_item_model"
|
|
141
|
+
MOD_BUILDER_MODEL = "mod_builder_model"
|
|
142
|
+
MOD_BUILDER = "mod_builder"
|
|
143
|
+
MOD_BUILDER_ITEM_MODEL = "mod_builder_item_model"
|
|
144
|
+
INSTANCE_BUILDER = "instance_builder"
|
|
145
|
+
INSTANCE_BUILDER_MODEL = "instance_builder_model"
|
|
146
|
+
STORAGE_BUILDER = "storage_builder"
|
|
147
|
+
STORAGE_BUILDER_MODEL = "storage_builder_model"
|
|
148
|
+
STATE_BACKEND = "state_backend"
|
|
149
|
+
STATE_BACKEND_MODEL = "state_backend_model"
|
|
150
|
+
EXECUTABLE_MODEL = "executable_model"
|
|
151
|
+
VERSION_CHECKER = "version_checker"
|
|
152
|
+
BASE_IMAGE_MODEL = "base_image_model"
|
|
153
|
+
IMAGE_MODEL = "image_model"
|
|
154
|
+
INSTANCE_MODEL = "instance_model"
|
|
155
|
+
GROUP_MODEL = "group_model"
|
|
156
|
+
USER_MODEL = "user_model"
|
|
157
|
+
STORAGE_MODEL = "storage_model"
|
|
158
|
+
MOD_MODEL = "mod_model"
|
|
159
|
+
SOURCE_MODEL_MODEL = "source_model_model"
|
|
160
|
+
RESOLVED_IMAGE_MODEL = "resolved_image_model"
|
|
161
|
+
PROVIDER_SPECIFIC_IMAGE = "provider_specific_image"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
PLUGIN_TYPES: list[tuple[str, str]] = [
|
|
165
|
+
("base", "base_plugins"),
|
|
166
|
+
("runtime", "runtime_builders"),
|
|
167
|
+
("state", "state_backends"),
|
|
168
|
+
("modification", "mod_builders"),
|
|
169
|
+
("storage", "storage_builders"),
|
|
170
|
+
("group", "group_builders"),
|
|
171
|
+
("user", "user_builders"),
|
|
172
|
+
("image", "image_builders"),
|
|
173
|
+
("os", "os_builders"),
|
|
174
|
+
("instance", "instance_builders"),
|
|
175
|
+
("other", "other_builders"),
|
|
176
|
+
# ("executables", "executables")
|
|
177
|
+
]
|
|
178
|
+
class OSFamilies(StrEnum):
|
|
179
|
+
"""
|
|
180
|
+
Enum for OS family classification.
|
|
181
|
+
These are the valid keys for os-family designations
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
RHEL = "rhel"
|
|
186
|
+
UBUNTU = "ubuntu"
|
|
187
|
+
DEBIAN = "debian"
|
|
188
|
+
FEDORA = "fedora"
|
|
189
|
+
OPENSUSE = "opensuse"
|
|
190
|
+
SUSE = "suse"
|
|
191
|
+
ROCKYLINUX = "rocky-linux"
|
|
192
|
+
ALMALINUX = "alma-linux"
|
|
193
|
+
CENTOS = "centos"
|
|
194
|
+
CENTOS_STREAM = "centos-stream"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class ComplianceState(Enum):
|
|
198
|
+
"""Enum for compliance state classification."""
|
|
199
|
+
|
|
200
|
+
IGNORED = "ignored"
|
|
201
|
+
ACCEPTABLE = "acceptable"
|
|
202
|
+
UNACCEPTABLE = "unacceptable"
|
|
203
|
+
|
|
204
|
+
# The system's own command, as the emitted runner scripts and the in-process
|
|
205
|
+
# callbacks name it (stage 64 / hygiene VII item 2: a committed script names
|
|
206
|
+
# the bare command, which must be on PATH; a step the running process spawns
|
|
207
|
+
# itself resolves to the running interpreter's own module instead).
|
|
208
|
+
SYSTEM_CLI: str = "cs-image-system"
|