Oh, Salt now works with JinjaTurtle :)
This commit is contained in:
parent
adfeb21d4b
commit
05b2875c17
4 changed files with 228 additions and 6 deletions
12
README.md
12
README.md
|
|
@ -292,16 +292,22 @@ If you intend to keep harvests/manifests long-term (especially in git), strongly
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## JinjaTurtle integration (both modes)
|
## JinjaTurtle integration
|
||||||
|
|
||||||
If [JinjaTurtle](https://git.mig5.net/mig5/jinjaturtle) is installed, `enroll` can generate Jinja2 templates for ini/json/xml/toml-style config.
|
If [JinjaTurtle](https://git.mig5.net/mig5/jinjaturtle) is installed, `enroll` can generate Jinja2 templates for ini/json/xml/toml-style config in renderers that consume Jinja templates.
|
||||||
|
|
||||||
|
For Ansible:
|
||||||
- Templates live in `roles/<role>/templates/...`
|
- Templates live in `roles/<role>/templates/...`
|
||||||
- Variables live in:
|
- Variables live in:
|
||||||
- single-site: `roles/<role>/defaults/main.yml`
|
- single-site: `roles/<role>/defaults/main.yml`
|
||||||
- multi-site: `inventory/host_vars/<fqdn>/<role>.yml`
|
- multi-site: `inventory/host_vars/<fqdn>/<role>.yml`
|
||||||
|
|
||||||
You can force it on with `--jinjaturtle` or disable with `--no-jinjaturtle`.
|
For Salt:
|
||||||
|
- Templates live in `states/roles/<role>/templates/...`
|
||||||
|
- `file.managed` uses `template: jinja` with per-file `context` values
|
||||||
|
- In `--fqdn` mode, template context values are written to pillar with the file metadata
|
||||||
|
|
||||||
|
Puppet output does not use JinjaTurtle templates. You can force template generation on with `--jinjaturtle` or disable it with `--no-jinjaturtle`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,7 @@ def manifest(
|
||||||
out,
|
out,
|
||||||
fqdn=fqdn,
|
fqdn=fqdn,
|
||||||
no_common_roles=no_common_roles,
|
no_common_roles=no_common_roles,
|
||||||
|
jinjaturtle=jinjaturtle,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
manifest_ansible_from_bundle_dir(
|
manifest_ansible_from_bundle_dir(
|
||||||
|
|
@ -252,6 +253,7 @@ def manifest(
|
||||||
str(tmp_out),
|
str(tmp_out),
|
||||||
fqdn=fqdn,
|
fqdn=fqdn,
|
||||||
no_common_roles=no_common_roles,
|
no_common_roles=no_common_roles,
|
||||||
|
jinjaturtle=jinjaturtle,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
manifest_ansible_from_bundle_dir(
|
manifest_ansible_from_bundle_dir(
|
||||||
|
|
|
||||||
154
enroll/salt.py
154
enroll/salt.py
|
|
@ -6,7 +6,7 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
@ -17,6 +17,12 @@ from .cm import (
|
||||||
role_order_key,
|
role_order_key,
|
||||||
section_label_for_packages,
|
section_label_for_packages,
|
||||||
)
|
)
|
||||||
|
from .jinjaturtle import (
|
||||||
|
can_jinjify_path,
|
||||||
|
find_jinjaturtle_cmd,
|
||||||
|
infer_other_formats,
|
||||||
|
run_jinjaturtle,
|
||||||
|
)
|
||||||
from .state import inventory_packages_from_state, roles_from_state
|
from .state import inventory_packages_from_state, roles_from_state
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -134,6 +140,9 @@ class SaltRole(CMModule):
|
||||||
artifact_role: str,
|
artifact_role: str,
|
||||||
role_files_dir: Path,
|
role_files_dir: Path,
|
||||||
file_prefix: Optional[str] = None,
|
file_prefix: Optional[str] = None,
|
||||||
|
jt_exe: Optional[str] = None,
|
||||||
|
jt_enabled: bool = False,
|
||||||
|
overwrite_templates: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
for d in self.managed_dirs_from_snapshot(snap):
|
for d in self.managed_dirs_from_snapshot(snap):
|
||||||
path = str(d.get("path") or "").strip()
|
path = str(d.get("path") or "").strip()
|
||||||
|
|
@ -151,6 +160,32 @@ class SaltRole(CMModule):
|
||||||
src_rel = str(mf.get("src_rel") or "").strip()
|
src_rel = str(mf.get("src_rel") or "").strip()
|
||||||
if not path or not src_rel:
|
if not path or not src_rel:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
template = _jinjify_managed_file(
|
||||||
|
bundle_dir,
|
||||||
|
artifact_role,
|
||||||
|
src_rel,
|
||||||
|
path,
|
||||||
|
role_files_dir.parent,
|
||||||
|
jt_exe=jt_exe,
|
||||||
|
jt_enabled=jt_enabled,
|
||||||
|
overwrite_templates=overwrite_templates,
|
||||||
|
)
|
||||||
|
if template is not None:
|
||||||
|
tmpl_rel, context = template
|
||||||
|
self.add_managed_file(
|
||||||
|
path,
|
||||||
|
user=mf.get("owner") or "root",
|
||||||
|
group=mf.get("group") or "root",
|
||||||
|
mode=mf.get("mode") or "0644",
|
||||||
|
source=_template_source_uri(self.module_name, tmpl_rel),
|
||||||
|
template="jinja",
|
||||||
|
context=context,
|
||||||
|
makedirs=True,
|
||||||
|
reason=mf.get("reason") or "managed_file",
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
role_rel = _copy_artifact(
|
role_rel = _copy_artifact(
|
||||||
bundle_dir,
|
bundle_dir,
|
||||||
artifact_role,
|
artifact_role,
|
||||||
|
|
@ -324,6 +359,69 @@ def _source_uri(module_name: str, role_rel: str) -> str:
|
||||||
return f"salt://roles/{module_name}/files/{role_rel}"
|
return f"salt://roles/{module_name}/files/{role_rel}"
|
||||||
|
|
||||||
|
|
||||||
|
def _template_source_uri(module_name: str, tmpl_rel: str) -> str:
|
||||||
|
return f"salt://roles/{module_name}/templates/{tmpl_rel}"
|
||||||
|
|
||||||
|
|
||||||
|
def _yaml_load_mapping(text: str) -> Dict[str, Any]:
|
||||||
|
try:
|
||||||
|
obj = yaml.safe_load(text)
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
return obj if isinstance(obj, dict) else {}
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_jinjaturtle_mode(jinjaturtle: str) -> Tuple[Optional[str], bool]:
|
||||||
|
jt_exe = find_jinjaturtle_cmd()
|
||||||
|
if jinjaturtle not in {"auto", "on", "off"}:
|
||||||
|
raise ValueError("jinjaturtle must be one of: auto, on, off")
|
||||||
|
if jinjaturtle == "on":
|
||||||
|
if not jt_exe:
|
||||||
|
raise RuntimeError("jinjaturtle requested but not found on PATH")
|
||||||
|
return jt_exe, True
|
||||||
|
if jinjaturtle == "auto":
|
||||||
|
return jt_exe, jt_exe is not None
|
||||||
|
return jt_exe, False
|
||||||
|
|
||||||
|
|
||||||
|
def _jinjify_managed_file(
|
||||||
|
bundle_dir: str,
|
||||||
|
artifact_role: str,
|
||||||
|
src_rel: str,
|
||||||
|
dest_path: str,
|
||||||
|
role_dir: Path,
|
||||||
|
*,
|
||||||
|
jt_exe: Optional[str],
|
||||||
|
jt_enabled: bool,
|
||||||
|
overwrite_templates: bool,
|
||||||
|
) -> Optional[Tuple[str, Dict[str, Any]]]:
|
||||||
|
if not (jt_enabled and jt_exe and can_jinjify_path(dest_path)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
artifact_path = Path(bundle_dir) / "artifacts" / artifact_role / src_rel
|
||||||
|
if not artifact_path.is_file():
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = run_jinjaturtle(
|
||||||
|
jt_exe,
|
||||||
|
str(artifact_path),
|
||||||
|
role_name=artifact_role,
|
||||||
|
force_format=infer_other_formats(dest_path),
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return None # nosec - best-effort template generation
|
||||||
|
|
||||||
|
context = _yaml_load_mapping(result.vars_text)
|
||||||
|
tmpl_rel = Path(src_rel).as_posix() + ".j2"
|
||||||
|
tmpl_dst = role_dir / "templates" / tmpl_rel
|
||||||
|
if overwrite_templates or not tmpl_dst.exists():
|
||||||
|
tmpl_dst.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
tmpl_dst.write_text(result.template_text, encoding="utf-8")
|
||||||
|
|
||||||
|
return tmpl_rel, context
|
||||||
|
|
||||||
|
|
||||||
def _node_file_prefix(fqdn: str) -> str:
|
def _node_file_prefix(fqdn: str) -> str:
|
||||||
name = re.sub(r"[^A-Za-z0-9_.-]+", "_", str(fqdn or "").strip())
|
name = re.sub(r"[^A-Za-z0-9_.-]+", "_", str(fqdn or "").strip())
|
||||||
name = name.strip("._-") or "node"
|
name = name.strip("._-") or "node"
|
||||||
|
|
@ -365,6 +463,8 @@ def _collect_salt_roles(
|
||||||
*,
|
*,
|
||||||
fqdn: Optional[str] = None,
|
fqdn: Optional[str] = None,
|
||||||
no_common_roles: bool = False,
|
no_common_roles: bool = False,
|
||||||
|
jt_exe: Optional[str] = None,
|
||||||
|
jt_enabled: bool = False,
|
||||||
) -> List[SaltRole]:
|
) -> List[SaltRole]:
|
||||||
roles = roles_from_state(state)
|
roles = roles_from_state(state)
|
||||||
inventory_packages = inventory_packages_from_state(state)
|
inventory_packages = inventory_packages_from_state(state)
|
||||||
|
|
@ -397,6 +497,9 @@ def _collect_salt_roles(
|
||||||
artifact_role=str(snap.get("role_name") or key),
|
artifact_role=str(snap.get("role_name") or key),
|
||||||
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
||||||
file_prefix=node_file_prefix,
|
file_prefix=node_file_prefix,
|
||||||
|
jt_exe=jt_exe,
|
||||||
|
jt_enabled=jt_enabled,
|
||||||
|
overwrite_templates=not bool(fqdn),
|
||||||
)
|
)
|
||||||
|
|
||||||
users_snap = roles.get("users") or {}
|
users_snap = roles.get("users") or {}
|
||||||
|
|
@ -412,6 +515,9 @@ def _collect_salt_roles(
|
||||||
artifact_role=str(users_snap.get("role_name") or "users"),
|
artifact_role=str(users_snap.get("role_name") or "users"),
|
||||||
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
||||||
file_prefix=node_file_prefix,
|
file_prefix=node_file_prefix,
|
||||||
|
jt_exe=jt_exe,
|
||||||
|
jt_enabled=jt_enabled,
|
||||||
|
overwrite_templates=not bool(fqdn),
|
||||||
)
|
)
|
||||||
|
|
||||||
for svc in roles.get("services", []) or []:
|
for svc in roles.get("services", []) or []:
|
||||||
|
|
@ -443,6 +549,9 @@ def _collect_salt_roles(
|
||||||
artifact_role=str(svc.get("role_name") or original_role_name),
|
artifact_role=str(svc.get("role_name") or original_role_name),
|
||||||
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
||||||
file_prefix=node_file_prefix,
|
file_prefix=node_file_prefix,
|
||||||
|
jt_exe=jt_exe,
|
||||||
|
jt_enabled=jt_enabled,
|
||||||
|
overwrite_templates=not bool(fqdn),
|
||||||
)
|
)
|
||||||
|
|
||||||
for pkg in roles.get("packages", []) or []:
|
for pkg in roles.get("packages", []) or []:
|
||||||
|
|
@ -467,6 +576,9 @@ def _collect_salt_roles(
|
||||||
artifact_role=str(pkg.get("role_name") or original_role_name),
|
artifact_role=str(pkg.get("role_name") or original_role_name),
|
||||||
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
role_files_dir=states_dir / "roles" / srole.module_name / "files",
|
||||||
file_prefix=node_file_prefix,
|
file_prefix=node_file_prefix,
|
||||||
|
jt_exe=jt_exe,
|
||||||
|
jt_enabled=jt_enabled,
|
||||||
|
overwrite_templates=not bool(fqdn),
|
||||||
)
|
)
|
||||||
|
|
||||||
container_images = roles.get("container_images") or {}
|
container_images = roles.get("container_images") or {}
|
||||||
|
|
@ -503,6 +615,22 @@ def _collect_salt_roles(
|
||||||
return [r for r in salt_roles if r.has_resources()]
|
return [r for r in salt_roles if r.has_resources()]
|
||||||
|
|
||||||
|
|
||||||
|
def _append_yaml_value(lines: List[str], key: str, value: Any, *, indent: int) -> None:
|
||||||
|
prefix = " " * indent
|
||||||
|
if isinstance(value, dict):
|
||||||
|
dumped = yaml.safe_dump(
|
||||||
|
value, sort_keys=True, default_flow_style=False
|
||||||
|
).rstrip()
|
||||||
|
if not dumped:
|
||||||
|
lines.append(f"{prefix}- {key}: {{}}")
|
||||||
|
return
|
||||||
|
lines.append(f"{prefix}- {key}:")
|
||||||
|
for line in dumped.splitlines():
|
||||||
|
lines.append(f"{prefix} {line}")
|
||||||
|
return
|
||||||
|
lines.append(f"{prefix}- {key}: {_yaml_quote(value)}")
|
||||||
|
|
||||||
|
|
||||||
def _render_static_role(srole: SaltRole) -> str:
|
def _render_static_role(srole: SaltRole) -> str:
|
||||||
lines: List[str] = ["# Generated by Enroll from harvest state.", ""]
|
lines: List[str] = ["# Generated by Enroll from harvest state.", ""]
|
||||||
|
|
||||||
|
|
@ -576,9 +704,13 @@ def _render_static_role(srole: SaltRole) -> str:
|
||||||
f" - group: {_yaml_quote(attrs.get('group') or 'root')}",
|
f" - group: {_yaml_quote(attrs.get('group') or 'root')}",
|
||||||
f" - mode: {_yaml_quote(str(attrs.get('mode') or '0644'))}",
|
f" - mode: {_yaml_quote(str(attrs.get('mode') or '0644'))}",
|
||||||
" - makedirs: true",
|
" - makedirs: true",
|
||||||
"",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
if attrs.get("template"):
|
||||||
|
lines.append(f" - template: {_yaml_quote(attrs.get('template'))}")
|
||||||
|
if attrs.get("context"):
|
||||||
|
_append_yaml_value(lines, "context", attrs.get("context"), indent=4)
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
for path, attrs in sorted(srole.links.items()):
|
for path, attrs in sorted(srole.links.items()):
|
||||||
lines.extend(
|
lines.extend(
|
||||||
|
|
@ -731,6 +863,10 @@ def _role_pillar_values(srole: SaltRole) -> Dict[str, Any]:
|
||||||
"group": attrs.get("group") or "root",
|
"group": attrs.get("group") or "root",
|
||||||
"mode": str(attrs.get("mode") or "0644"),
|
"mode": str(attrs.get("mode") or "0644"),
|
||||||
"makedirs": True,
|
"makedirs": True,
|
||||||
|
**(
|
||||||
|
{"template": attrs.get("template")} if attrs.get("template") else {}
|
||||||
|
),
|
||||||
|
**({"context": attrs.get("context")} if attrs.get("context") else {}),
|
||||||
}
|
}
|
||||||
for path, attrs in sorted(srole.files.items())
|
for path, attrs in sorted(srole.files.items())
|
||||||
}
|
}
|
||||||
|
|
@ -826,6 +962,12 @@ def _render_pillar_role(srole: SaltRole) -> str:
|
||||||
" - group: {{ attrs.get('group', 'root')|yaml_dquote }}",
|
" - group: {{ attrs.get('group', 'root')|yaml_dquote }}",
|
||||||
" - mode: {{ attrs.get('mode', '0644')|string|yaml_dquote }}",
|
" - mode: {{ attrs.get('mode', '0644')|string|yaml_dquote }}",
|
||||||
" - makedirs: {{ attrs.get('makedirs', True)|yaml_encode }}",
|
" - makedirs: {{ attrs.get('makedirs', True)|yaml_encode }}",
|
||||||
|
"{% if attrs.get('template') %}",
|
||||||
|
" - template: {{ attrs.get('template')|yaml_dquote }}",
|
||||||
|
"{% endif %}",
|
||||||
|
"{% if attrs.get('context') %}",
|
||||||
|
" - context: {{ attrs.get('context')|yaml_encode }}",
|
||||||
|
"{% endif %}",
|
||||||
"{% endfor %}",
|
"{% endfor %}",
|
||||||
"",
|
"",
|
||||||
"{% for path, attrs in role.get('links', {}).items() %}",
|
"{% for path, attrs in role.get('links', {}).items() %}",
|
||||||
|
|
@ -1069,7 +1211,7 @@ This Salt target reuses the existing harvest state without changing harvesting b
|
||||||
## Current limitations
|
## Current limitations
|
||||||
|
|
||||||
- Flatpak, Snap, and live firewall runtime snapshots are listed as notes when present rather than rendered as Salt states.
|
- Flatpak, Snap, and live firewall runtime snapshots are listed as notes when present rather than rendered as Salt states.
|
||||||
- JinjaTurtle templating is currently Ansible-oriented and is not applied to Salt output.
|
- JinjaTurtle templating is applied on a best-effort basis for file formats it recognises; unrecognised files are copied literally.
|
||||||
- Review generated resources before applying them broadly across unlike hosts.
|
- Review generated resources before applying them broadly across unlike hosts.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
@ -1088,11 +1230,13 @@ class SaltManifestRenderer:
|
||||||
*,
|
*,
|
||||||
fqdn: Optional[str] = None,
|
fqdn: Optional[str] = None,
|
||||||
no_common_roles: bool = False,
|
no_common_roles: bool = False,
|
||||||
|
jinjaturtle: str = "auto",
|
||||||
) -> None:
|
) -> None:
|
||||||
self.bundle_dir = bundle_dir
|
self.bundle_dir = bundle_dir
|
||||||
self.out_dir = out_dir
|
self.out_dir = out_dir
|
||||||
self.fqdn = fqdn
|
self.fqdn = fqdn
|
||||||
self.no_common_roles = no_common_roles
|
self.no_common_roles = no_common_roles
|
||||||
|
self.jt_exe, self.jt_enabled = _resolve_jinjaturtle_mode(jinjaturtle)
|
||||||
|
|
||||||
def render(self) -> None:
|
def render(self) -> None:
|
||||||
state = SaltRole.load_state(self.bundle_dir)
|
state = SaltRole.load_state(self.bundle_dir)
|
||||||
|
|
@ -1114,6 +1258,8 @@ class SaltManifestRenderer:
|
||||||
states_dir,
|
states_dir,
|
||||||
fqdn=self.fqdn,
|
fqdn=self.fqdn,
|
||||||
no_common_roles=self.no_common_roles,
|
no_common_roles=self.no_common_roles,
|
||||||
|
jt_exe=self.jt_exe,
|
||||||
|
jt_enabled=self.jt_enabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
for srole in salt_roles:
|
for srole in salt_roles:
|
||||||
|
|
@ -1153,10 +1299,12 @@ def manifest_from_bundle_dir(
|
||||||
*,
|
*,
|
||||||
fqdn: Optional[str] = None,
|
fqdn: Optional[str] = None,
|
||||||
no_common_roles: bool = False,
|
no_common_roles: bool = False,
|
||||||
|
jinjaturtle: str = "auto",
|
||||||
) -> None:
|
) -> None:
|
||||||
SaltManifestRenderer(
|
SaltManifestRenderer(
|
||||||
bundle_dir,
|
bundle_dir,
|
||||||
out_dir,
|
out_dir,
|
||||||
fqdn=fqdn,
|
fqdn=fqdn,
|
||||||
no_common_roles=no_common_roles,
|
no_common_roles=no_common_roles,
|
||||||
|
jinjaturtle=jinjaturtle,
|
||||||
).render()
|
).render()
|
||||||
|
|
|
||||||
|
|
@ -466,3 +466,69 @@ def test_manifest_salt_renders_container_images_in_single_and_fqdn_modes(
|
||||||
assert "{{.Id}}" not in pillar_text
|
assert "{{.Id}}" not in pillar_text
|
||||||
assert "sed -n" in pillar_text
|
assert "sed -n" in pillar_text
|
||||||
assert "podman pull" in pillar_text
|
assert "podman pull" in pillar_text
|
||||||
|
|
||||||
|
|
||||||
|
def test_manifest_salt_uses_jinjaturtle_templates(monkeypatch, tmp_path: Path):
|
||||||
|
from enroll import salt as salt_mod
|
||||||
|
from enroll.jinjaturtle import JinjifyResult
|
||||||
|
|
||||||
|
bundle = tmp_path / "bundle"
|
||||||
|
out = tmp_path / "salt"
|
||||||
|
state = _sample_state()
|
||||||
|
_write_sample_artifacts(bundle)
|
||||||
|
_write_state(bundle, state)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
salt_mod, "find_jinjaturtle_cmd", lambda: "/usr/bin/jinjaturtle"
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(salt_mod, "can_jinjify_path", lambda _path: True)
|
||||||
|
|
||||||
|
def fake_run_jinjaturtle(
|
||||||
|
jt_exe: str, src_path: str, *, role_name: str, force_format=None
|
||||||
|
):
|
||||||
|
assert jt_exe == "/usr/bin/jinjaturtle"
|
||||||
|
assert role_name == "foo"
|
||||||
|
assert src_path.endswith("artifacts/foo/etc/foo.conf")
|
||||||
|
return JinjifyResult(
|
||||||
|
template_text="setting = {{ foo_setting }}\n",
|
||||||
|
vars_text="foo_setting: true\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(salt_mod, "run_jinjaturtle", fake_run_jinjaturtle)
|
||||||
|
|
||||||
|
manifest.manifest(str(bundle), str(out), target="salt", jinjaturtle="on")
|
||||||
|
|
||||||
|
role_dir = out / "states" / "roles" / "net"
|
||||||
|
assert (role_dir / "templates" / "etc" / "foo.conf.j2").read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
) == "setting = {{ foo_setting }}\n"
|
||||||
|
assert not (role_dir / "files" / "etc" / "foo.conf").exists()
|
||||||
|
sls = (role_dir / "init.sls").read_text(encoding="utf-8")
|
||||||
|
assert 'source: "salt://roles/net/templates/etc/foo.conf.j2"' in sls
|
||||||
|
assert 'template: "jinja"' in sls
|
||||||
|
assert "foo_setting: true" in sls
|
||||||
|
|
||||||
|
fqdn_out = tmp_path / "salt-fqdn"
|
||||||
|
manifest.manifest(
|
||||||
|
str(bundle),
|
||||||
|
str(fqdn_out),
|
||||||
|
target="salt",
|
||||||
|
fqdn="node.example",
|
||||||
|
jinjaturtle="on",
|
||||||
|
)
|
||||||
|
|
||||||
|
fqdn_role_dir = fqdn_out / "states" / "roles" / "foo"
|
||||||
|
assert (fqdn_role_dir / "templates" / "etc" / "foo.conf.j2").exists()
|
||||||
|
assert not (
|
||||||
|
fqdn_role_dir / "files" / "nodes" / "node.example" / "etc" / "foo.conf"
|
||||||
|
).exists()
|
||||||
|
pillar_top = yaml.safe_load(
|
||||||
|
(fqdn_out / "pillar" / "top.sls").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
node_sls = pillar_top["base"]["node.example"][0]
|
||||||
|
pillar_path = fqdn_out / "pillar" / Path(*node_sls.split("."))
|
||||||
|
pillar = yaml.safe_load(pillar_path.with_suffix(".sls").read_text(encoding="utf-8"))
|
||||||
|
file_data = pillar["enroll"]["roles"]["foo"]["files"]["/etc/foo/foo.conf"]
|
||||||
|
assert file_data["source"] == "salt://roles/foo/templates/etc/foo.conf.j2"
|
||||||
|
assert file_data["template"] == "jinja"
|
||||||
|
assert file_data["context"] == {"foo_setting": True}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue