crossplane-contrib / provider-cloudinit

Crossplane provider for Cloud-init templating
Apache License 2.0
12 stars 1 forks source link

Support "strongly typed" cloud init documents #8

Open negz opened 3 years ago

negz commented 3 years ago

Currently I believe this provider requires the author of a Config to pass a cloud-config as opaque data, e.g:

apiVersion: cloudinit.crossplane.io/v1alpha1
kind: Config
metadata:
  name: cloudinit
  namespace: default
spec:
  writeCloudInitToRef:
    name: cloudinit
    namespace: default
    key: cloud-init
  forProvider:
    boundary: MIMEBOUNDARY
    parts:
    - configMapKeyRef:
      name: foo
      namespace: default
      key: foo
      optional: true
    - content: |
        #!/bin/sh
        echo "Hello World, from provider-cloudinit"
    - content: |
        #cloud-config
        users:
        - default
        - name: yourusername
          gecos: Your Name
          sudo: ALL=(ALL) NOPASSWD:ALL
          ssh_authorized_keys:
            - ssh-rsa YOURKEY

Would it be feasible to model (a subset of?) the config document as part of the actual schema? e.g.

---
apiVersion: cloudinit.crossplane.io/v1alpha1
kind: Config
metadata:
  name: cloudinit
  namespace: default
spec:
  writeCloudInitToRef:
    name: cloudinit
    namespace: default
    key: cloud-init
  forProvider:
    boundary: MIMEBOUNDARY
    parts:
    - configMapKeyRef:
      name: foo
      namespace: default
      key: foo
      optional: true
    # This is an opaque blob.
    - rawContent: |
        #!/bin/sh
        echo "Hello World, from provider-cloudinit"
    # This is validatable using our CRD schema.
    - content:
        users:
        - default
        - name: yourusername
          gecos: Your Name
          sudo: ALL=(ALL) NOPASSWD:ALL
          ssh_authorized_keys:
            - ssh-rsa YOURKEY
displague commented 3 years ago

Thanks for creating this issue, @negz.

I had a similar thought when I was sketching this project out: https://github.com/displague/provider-cloudinit/blame/main/SLIDES.md#L288

The thing that gave me hesitation was not knowing if the content could be serialized faithfully, strictly validated, or if there was any benefit over embedding cloud-config as text.

If we can't find an official go cloud-config definition, preferably with struct tags, this project might have to become a self-authority on that definition and that could lead to required maintainance to follow up stream changes. An open text field avoids that, and is still permitted through rawContent.

https://github.com/juju/juju/blob/develop/cloudconfig/cloudinit/cloudinit.go

displague commented 3 years ago

Taking this one step deeper, one piece of content, supported by cloud-config is write_files.

# cloud-config
write_files:
  - content: |
        {
          "exec-opts": ["native.cgroupdriver=systemd"],
          "log-driver": "json-file",
          "log-opts": {
            "max-size": "100m"
          },
          "storage-driver": "overlay2"
        }
    path: /etc/docker/daemon.json
  - content: foo
    path: /root/foo

Should a cloud-config field like this one be made more accessible, allowing for the file to be ConfigMap derived:

---
apiVersion: cloudinit.crossplane.io/v1alpha1
kind: Config
metadata:
  name: cloudinit
  namespace: default
spec:
  writeCloudInitToRef:
    name: cloudinit
    namespace: default
    key: cloud-init
  forProvider:
    boundary: MIMEBOUNDARY
    parts:
    - configMapKeyRef:
        name: foo
        namespace: default
        key: foo
        optional: true
      writeFilesPath: /root/foo # or perhaps writeFile or path
      # this would construct the following part:
      #
      # #cloud-config
      # write-files:
      # - path: /root/foo
      #   content: foo