reintroduce Salt
This commit is contained in:
parent
0d111caf62
commit
adfeb21d4b
4 changed files with 67 additions and 19 deletions
|
|
@ -5,9 +5,10 @@
|
||||||
* Detect active sysctl parameters and write them to a `/etc/sysctl.d/99-enroll.conf` file
|
* Detect active sysctl parameters and write them to a `/etc/sysctl.d/99-enroll.conf` file
|
||||||
* Use `no_log` on systemd unit interrogations to suppress potential sensitive output when applying Ansible
|
* Use `no_log` on systemd unit interrogations to suppress potential sensitive output when applying Ansible
|
||||||
* Support manifesting Puppet code, as well as Ansible!
|
* Support manifesting Puppet code, as well as Ansible!
|
||||||
|
* Support manifesting Salt code, as well as Ansible and Puppet!
|
||||||
* A lot of under-the-bonnet refactoring to make it easier to extend to cover other config managers (that don't suck) in future.
|
* A lot of under-the-bonnet refactoring to make it easier to extend to cover other config managers (that don't suck) in future.
|
||||||
* Support for detecting Docker images
|
* Support for detecting Docker images. You will need to install puppetlabs-docker module if you're using the Puppet manifester.
|
||||||
* Add support for detecting flatpaks and snaps (manifests Ansible code only, not Puppet at this time)
|
* Add support for detecting flatpaks and snaps (manifests Ansible code only, not Puppet or Salt at this time)
|
||||||
|
|
||||||
# 0.6.0
|
# 0.6.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,13 @@ cd /tmp/enroll-salt
|
||||||
sudo salt-call --local --file-root ./states --pillar-root ./pillar --id host.example.com state.apply test=True
|
sudo salt-call --local --file-root ./states --pillar-root ./pillar --id host.example.com state.apply test=True
|
||||||
```
|
```
|
||||||
|
|
||||||
Re-running Salt `--fqdn` output into the same directory adds or replaces that minion's top/pillar data without deleting other generated minions. Docker images with registry digests are rendered with Salt's native `docker_image.present` state. Podman images with registry digests are rendered as guarded `podman pull` / `podman tag` command states. Images without `RepoDigest` are recorded in harvest state and notes, but are not converted into exact pull states. Flatpak, Snap, and live firewall runtime snapshots are listed as notes in the generated Salt README rather than converted into Salt states.
|
Re-running Salt `--fqdn` output into the same directory adds or replaces that minion's top/pillar data without deleting other generated minions.
|
||||||
|
|
||||||
|
Docker and Podman images with registry digests are rendered as guarded `cmd.run` states that use the local `docker`/`podman` CLI directly (`pull`, `image inspect`, and `tag`).
|
||||||
|
|
||||||
|
This is because Salt Stack, in 3008, does not have proper Docker extensions that actually work. Wow.
|
||||||
|
|
||||||
|
Certain other things, like in Puppet, are not 'manifested' into Salt states unlike Ansible, at this time: these are Flatpak, Snap, and live firewall rules.
|
||||||
|
|
||||||
### Manifest with `--sops`
|
### Manifest with `--sops`
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,9 @@ class SaltRole(CMModule):
|
||||||
for alias in item["tag_aliases"]:
|
for alias in item["tag_aliases"]:
|
||||||
alias_ref = str(alias.get("ref") or "")
|
alias_ref = str(alias.get("ref") or "")
|
||||||
alias["tag_cmd"] = _container_tag_cmd(engine, pull_ref, alias_ref)
|
alias["tag_cmd"] = _container_tag_cmd(engine, pull_ref, alias_ref)
|
||||||
alias["tag_unless"] = _container_exists_cmd(engine, alias_ref)
|
alias["tag_unless"] = _container_tag_matches_cmd(
|
||||||
|
engine, pull_ref, alias_ref
|
||||||
|
)
|
||||||
self.container_images.append(item)
|
self.container_images.append(item)
|
||||||
for note in snap.get("notes", []) or []:
|
for note in snap.get("notes", []) or []:
|
||||||
self.notes.append(str(note))
|
self.notes.append(str(note))
|
||||||
|
|
@ -239,6 +241,34 @@ def _container_exists_cmd(engine: str, ref: str) -> str:
|
||||||
return f"docker image inspect {_shell_quote(ref)} >/dev/null 2>&1"
|
return f"docker image inspect {_shell_quote(ref)} >/dev/null 2>&1"
|
||||||
|
|
||||||
|
|
||||||
|
def _container_image_id_expr(engine: str, ref: str) -> str:
|
||||||
|
"""Return a shell expression that extracts an inspected image ID.
|
||||||
|
|
||||||
|
Salt renders SLS files through Jinja before YAML, so Docker's normal
|
||||||
|
format template cannot be emitted literally without careful escaping. Use
|
||||||
|
JSON output plus sed instead; it avoids Go-template braces in generated
|
||||||
|
Salt states and pillar data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sed_id = (
|
||||||
|
r"sed -n 's/^[[:space:]]*\"Id\":[[:space:]]*\"\([^\"]*\)\".*/\1/p' "
|
||||||
|
r"| head -n 1"
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f"{_shell_quote(engine)} image inspect {_shell_quote(ref)} "
|
||||||
|
f"2>/dev/null | {sed_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _container_tag_matches_cmd(engine: str, pull_ref: str, tag_ref: str) -> str:
|
||||||
|
"""Return a shell guard that is true only when tag_ref points at pull_ref."""
|
||||||
|
|
||||||
|
return (
|
||||||
|
f'test "$({_container_image_id_expr(engine, tag_ref)})" '
|
||||||
|
f'= "$({_container_image_id_expr(engine, pull_ref)})"'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _container_tag_cmd(engine: str, pull_ref: str, tag_ref: str) -> str:
|
def _container_tag_cmd(engine: str, pull_ref: str, tag_ref: str) -> str:
|
||||||
return f"{engine} tag {_shell_quote(pull_ref)} {_shell_quote(tag_ref)}"
|
return f"{engine} tag {_shell_quote(pull_ref)} {_shell_quote(tag_ref)}"
|
||||||
|
|
||||||
|
|
@ -581,13 +611,13 @@ def _render_static_role(srole: SaltRole) -> str:
|
||||||
if not engine or not pull_ref:
|
if not engine or not pull_ref:
|
||||||
continue
|
continue
|
||||||
if engine == "docker":
|
if engine == "docker":
|
||||||
pull_state_id = _state_id("docker_image", pull_ref, role=srole.module_name)
|
pull_state_id = _state_id("docker_pull", pull_ref, role=srole.module_name)
|
||||||
lines.extend(
|
lines.extend(
|
||||||
[
|
[
|
||||||
f"{pull_state_id}:",
|
f"{pull_state_id}:",
|
||||||
" docker_image.present:",
|
" cmd.run:",
|
||||||
f" - name: {_yaml_quote(pull_ref)}",
|
f" - name: {_yaml_quote(image.get('pull_cmd') or _container_pull_cmd(engine, pull_ref))}",
|
||||||
" - force: false",
|
f" - unless: {_yaml_quote(image.get('pull_unless') or _container_exists_cmd(engine, pull_ref))}",
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -600,9 +630,9 @@ def _render_static_role(srole: SaltRole) -> str:
|
||||||
f"{_state_id('docker_tag', tag_ref, role=srole.module_name)}:",
|
f"{_state_id('docker_tag', tag_ref, role=srole.module_name)}:",
|
||||||
" cmd.run:",
|
" cmd.run:",
|
||||||
f" - name: {_yaml_quote(alias.get('tag_cmd') or _container_tag_cmd(engine, pull_ref, tag_ref))}",
|
f" - name: {_yaml_quote(alias.get('tag_cmd') or _container_tag_cmd(engine, pull_ref, tag_ref))}",
|
||||||
f" - unless: {_yaml_quote(alias.get('tag_unless') or _container_exists_cmd(engine, tag_ref))}",
|
f" - unless: {_yaml_quote(alias.get('tag_unless') or _container_tag_matches_cmd(engine, pull_ref, tag_ref))}",
|
||||||
" - require:",
|
" - require:",
|
||||||
f" - docker_image: {pull_state_id}",
|
f" - cmd: {pull_state_id}",
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -815,10 +845,10 @@ def _render_pillar_role(srole: SaltRole) -> str:
|
||||||
"",
|
"",
|
||||||
"{% for image in role.get('container_images', []) %}",
|
"{% for image in role.get('container_images', []) %}",
|
||||||
"{% if image.get('engine') == 'docker' and image.get('pull_ref') %}",
|
"{% if image.get('engine') == 'docker' and image.get('pull_ref') %}",
|
||||||
f"enroll_docker_image_{role_key}_{{{{ loop.index }}}}:",
|
f"enroll_docker_pull_{role_key}_{{{{ loop.index }}}}:",
|
||||||
" docker_image.present:",
|
" cmd.run:",
|
||||||
" - name: {{ image.get('pull_ref')|yaml_dquote }}",
|
" - name: {{ image.get('pull_cmd')|yaml_dquote }}",
|
||||||
" - force: false",
|
" - unless: {{ image.get('pull_unless')|yaml_dquote }}",
|
||||||
"{% set image_loop = loop.index %}",
|
"{% set image_loop = loop.index %}",
|
||||||
"{% for alias in image.get('tag_aliases', []) %}",
|
"{% for alias in image.get('tag_aliases', []) %}",
|
||||||
f"enroll_docker_tag_{role_key}_{{{{ image_loop }}}}_{{{{ loop.index }}}}:",
|
f"enroll_docker_tag_{role_key}_{{{{ image_loop }}}}_{{{{ loop.index }}}}:",
|
||||||
|
|
@ -826,7 +856,7 @@ def _render_pillar_role(srole: SaltRole) -> str:
|
||||||
" - name: {{ alias.get('tag_cmd')|yaml_dquote }}",
|
" - name: {{ alias.get('tag_cmd')|yaml_dquote }}",
|
||||||
" - unless: {{ alias.get('tag_unless')|yaml_dquote }}",
|
" - unless: {{ alias.get('tag_unless')|yaml_dquote }}",
|
||||||
" - require:",
|
" - require:",
|
||||||
f" - docker_image: enroll_docker_image_{role_key}_{{{{ image_loop }}}}",
|
f" - cmd: enroll_docker_pull_{role_key}_{{{{ image_loop }}}}",
|
||||||
"{% endfor %}",
|
"{% endfor %}",
|
||||||
"{% elif image.get('engine') == 'podman' and image.get('pull_ref') %}",
|
"{% elif image.get('engine') == 'podman' and image.get('pull_ref') %}",
|
||||||
f"enroll_podman_pull_{role_key}_{{{{ loop.index }}}}:",
|
f"enroll_podman_pull_{role_key}_{{{{ loop.index }}}}:",
|
||||||
|
|
@ -1033,7 +1063,7 @@ This Salt target reuses the existing harvest state without changing harvesting b
|
||||||
- Managed directories, files, and symlinks from harvested roles.
|
- Managed directories, files, and symlinks from harvested roles.
|
||||||
- Basic service enablement/running-state resources.
|
- Basic service enablement/running-state resources.
|
||||||
- `/etc/sysctl.d/99-enroll.conf` plus an `onchanges` sysctl apply command when present.
|
- `/etc/sysctl.d/99-enroll.conf` plus an `onchanges` sysctl apply command when present.
|
||||||
- Docker images by digest using Salt's native `docker_image.present` state.
|
- Docker images by digest using guarded `docker pull` / `docker tag` command states.
|
||||||
- Podman images by digest using guarded `podman pull` / `podman tag` command states.
|
- Podman images by digest using guarded `podman pull` / `podman tag` command states.
|
||||||
|
|
||||||
## Current limitations
|
## Current limitations
|
||||||
|
|
|
||||||
|
|
@ -430,9 +430,14 @@ def test_manifest_salt_renders_container_images_in_single_and_fqdn_modes(
|
||||||
sls = (out / "states" / "roles" / "container_images" / "init.sls").read_text(
|
sls = (out / "states" / "roles" / "container_images" / "init.sls").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
assert "docker_image.present:" in sls
|
assert "docker_image.present:" not in sls
|
||||||
|
assert "docker pull" in sls
|
||||||
assert digest in sls
|
assert digest in sls
|
||||||
|
assert "docker image inspect" in sls
|
||||||
|
assert "{{.Id}}" not in sls
|
||||||
|
assert "sed -n" in sls
|
||||||
assert "docker tag" in sls
|
assert "docker tag" in sls
|
||||||
|
assert "- cmd: enroll_docker_pull_container_images" in sls
|
||||||
assert "podman pull" in sls
|
assert "podman pull" in sls
|
||||||
assert "podman tag" in sls
|
assert "podman tag" in sls
|
||||||
|
|
||||||
|
|
@ -451,7 +456,13 @@ def test_manifest_salt_renders_container_images_in_single_and_fqdn_modes(
|
||||||
fqdn_sls = (
|
fqdn_sls = (
|
||||||
fqdn_out / "states" / "roles" / "container_images" / "init.sls"
|
fqdn_out / "states" / "roles" / "container_images" / "init.sls"
|
||||||
).read_text(encoding="utf-8")
|
).read_text(encoding="utf-8")
|
||||||
assert "docker_image.present:" in fqdn_sls
|
assert "docker_image.present:" not in fqdn_sls
|
||||||
|
assert "enroll_docker_pull_container_images" in fqdn_sls
|
||||||
assert "enroll_podman_pull_container_images" in fqdn_sls
|
assert "enroll_podman_pull_container_images" in fqdn_sls
|
||||||
assert "image.get('pull_cmd')" in fqdn_sls
|
assert "image.get('pull_cmd')" in fqdn_sls
|
||||||
assert "podman pull" in pillar_path.with_suffix(".sls").read_text(encoding="utf-8")
|
pillar_text = pillar_path.with_suffix(".sls").read_text(encoding="utf-8")
|
||||||
|
assert "docker pull" in pillar_text
|
||||||
|
assert "docker image inspect" in pillar_text
|
||||||
|
assert "{{.Id}}" not in pillar_text
|
||||||
|
assert "sed -n" in pillar_text
|
||||||
|
assert "podman pull" in pillar_text
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue