Skip to content

Instantly share code, notes, and snippets.

@jamesog
Last active December 13, 2020 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesog/6362dd8546a217b24ede4677d804a876 to your computer and use it in GitHub Desktop.
Save jamesog/6362dd8546a217b24ede4677d804a876 to your computer and use it in GitHub Desktop.
I dreamed a dream

Better config management

Syntax

Use HCL, not YAML.

# Ensure blocks group actions
ensure "Foo service" {
    package "foo" {
        version = "1.0.0"  # No version means install latest available
    }
    file "/etc/foo.conf" {
        source = file.conf.tmpl
        user = "foo"
        group = "foo"
        mode = 0644
        validate = "/usr/bin/foo validate"  # Some way of running a command to validate the template?
    }
    # Or explicitly create a new action?
    exec {
      command = ["/usr/bin/foo", "validate", "/etc/foo.conf"]
    }
    service "foo" {
        state = "running"
        enable = true  # Ensure started at boot
        # Should requirements be explicit or purely based on ordering?
        require = {
            package: "foo",
            file: "/etc/foo.conf",
        }
    }
}

ensure "Some external condition" {
    # This group needs another group to have completed
    require = {ensure: "Foo service"}
    # Alternatively, run this group when another changes
    when = {changed: "Foo service"}
    exec {
        command = ["/usr/bin/echo", "one", "two"]
        expect = "one two"  # Ensure this output
    }
    exec {
        command = ["/usr/bin/touch", "/tmp/foo"]
        creates = "/tmp/foo"  # Ensure this file is created
    }

The equivalent in Salt would be:

# Salt lets you group states, although they all have the same "name" which may need to be overridden in the state
Foo service:
  pkg.installed:
    - name: foo
    - version: 1.0.0
  file.managed:
    - name: /etc/foo.conf
    - source: salt://foo.conf.tmpl
  service.running:
    - name: foo
    - enable: true
    - require:
        - pkg: foo
        - file: /etc/foo.conf

Some external condition:
  cmd.run:
    - name: /usr/bin/echo one two

# Note you can't have two cmd.run in the same block so this one must be separate
Some second condition:
  cmd.run:
    - name: /usr/bin/touch /tmp/foo
    - creates: /tmp/foo

And in Ansible:

# Ansible groups tasks too.
- name: Setup foo service
  tasks:
  - name: Install foo package
    pkg:
      name: foo
  - name: Install foo config
    template:
      src: foo.conf.j2
      dest: /etc/foo.conf
  - name: Ensure foo is running
    service:
      name: foo
      state: started

- name: Some external condition
  tasks:
  - name: echo one two
    command: /usr/bin/echo one two
  - name: touch /tmp/foo
    command:
      cmd: /usr/bin/touch /tmp/foo
      creates: /tmp/foo

Templating

Oh god not Jinja. Nor Go text/template. There must be something better? HCL2 has its own basic templating although the docs are vague.

Variables could be injected in a similar way to Ansible.

How should loops / repeated actions work? Maybe instead of templating inside the file, you have a template file that gets repeated N times

package "${package.name}" {
  version = "${package.version}"
}
service "${service.name}" {
  state = "${service.state}"
}

The package and service vars could be populated by a map elsewhere, which calls that template each time. No more messy generated loops?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment