# Overview
Cloud-Init is a project that standardizes methods for injecting data into cloud
VMIs on launch.  Data typically includes **metadata** and **userdata**

**Metadata** is dynamically generated by the cloud provider and contains
information about the unique instance.

**Userdata** is VMI configuration data supplied by the user that executes
when the VMI instance starts.

It is common for cloud IaaS users to associate userdata with a VMI instance in
order to execute a short script that software provisions on startup.

# Data Sources
The Cloud Init project supports multiple ways of supplying metadata and
userdata to a VMI. These methods are called **data sources**.

https://cloudinit.readthedocs.io/en/latest/reference/datasources.html

KubeVirt supports the different data source standards by taking the userdata
and metadata associated with a VMI and formatting that data in a way that
adheres to the specific datasource standard in use.

## NoCloud Data Source

https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html

The **NoCloud** data source involves generating an iso with userdata and
metadata in it, and attaching that iso the VMI instance. The fedora-atomic
project supports this datasource for their VMI images. 

To associated userdata with a VMI instance using the NoCloud data source, all
users have to do is base64 encode userdata information into the VMI definition. 

Example
```
metadata:
  name: testvm-nocloud
apiVersion: kubevirt.io/v1alpha2
kind: VirtualMachineInstance
spec:
  domain:
    devices:
      disks:
      - type: ContainerDisk:v1alpha
        source:
          name: kubevirt/cirros-container-disk-demo:devel
        target:
          dev: vda
      - type: file
        target:
          dev: vdb
        cloudinit:
            nocloud:
                userDataBase64: I2Nsb3VkLWNvbmZpZwpwYXNzd29yZDogYXRvbWljCnNzaF9wd2F1dGg6IFRydWUKY2hwYXNzd2Q6IHsgZXhwaXJlOiBGYWxzZSB9Cg==
      interfaces:
      - source:
          network: default
        type: network
    memory:
      unit: MB
      value: 64
    os:
      type:
        os: hvm
    type: qemu
```

### NoCloud with UserData stored in k8s secret

Instead of placing the userdata directly into the VMI definition, another option
is to reference the userdata in a k8s secret object.

To use this method, the user must create an Opaque type kubernetes secret with
a key named 'userdata' containing a value representing the base64 encoded
userdata. The name of the kubernetes secret is then referenced in the CloudInit
object on the VMI spec.

Example: Create a k8s secret with UserData. Reference the secret in the NoCloud
disk definition.

First create the secret.
```
apiVersion: v1
kind: Secret
metadata:
  name: my-vm-secret
type: Opaque
data:
  userdata: I2Nsb3VkLWNvbmZpZwpwYXNzd29yZDogYXRvbWljCnNzaF9wd2F1dGg6IFRydWUKY2hwYXNzd2Q6IHsgZXhwaXJlOiBGYWxzZSB9Cg==
```

Then reference the secret in the userDataSecretRef field.
```
metadata:
  name: testvm-nocloud
apiVersion: kubevirt.io/v1alpha2
kind: VirtualMachineInstance
spec:
  domain:
    devices:
      disks:
      - type: ContainerDisk:v1alpha
        source:
          name: kubevirt/cirros-container-disk-demo:devel
        target:
          dev: vda
      - type: file
        target:
          dev: vdb
        cloudinit:
            nocloud:
                userDataSecretRef: my-vm-userdata 
      interfaces:
      - source:
          network: default
        type: network
    memory:
      unit: MB
      value: 64
    os:
      type:
        os: hvm
    type: qemu
```

Multiple VMIs can reference the same k8s secret object containing userdata.

### NoCloud Implementation Details

Internally, kubevirt passes the cloud-init spec to the config-disk package.
That package generates the iso files associated with the nocloud datasource.

When the VMI starts, virt-handler injects the NoCloud iso as a file based disk
that the VMI consumes.

From there the NoCloud datasource process internal to the VMI detects the
attached disk and processes the userdata and metadata stored on the disk.

## Future Disk Based Data Sources
The VMI definition structures and cloud-init package have been structured in a
way that should allow for additional disk based data sources to be added in the
future with ease. 

Example: User facing details related to another data source.
```
  cloudInit:
    SomeOtherProviderData:
      userDataBase64: I2Nsb3VkLWNvbmZpZwpwYXNzd29yZDogYXRvbWljCnNzaF9wd2F1dGg6IFRydWUKY2hwYXNzd2Q6IHsgZXhwaXJlOiBGYWxzZSB9Cg==
      Whatever1: somethingelse
      Whatever2: otherstuff
```

The cloud-init package would then get a new data source called
'SomeOtherSource'. Everything related to the 'NoCloud' source is isolated by
switch statements already. The 'SomeOtherSource' implementation details would
just need to be added in whatever way makes sense for that data source.

## Future Metadata Server Based Data Sources
Not all cloud init data sources involve injecting a disk into the VMI. Another
common method for injecting cloud init data is to use a metadata server. With
a metadata server, the VMI launches and makes a request for the cloud init
data on a well known IP address backed by the metadata server. The metadata
server responds with the userdata and metadata associated with that VMI.

For KubeVirt to support metadata servers, this will require integrating
the metadata server into the VMI launch flow. KubeVirt will have to know how to
register VMI specific information with the metadata server so that server can
provide it to the VMI upon request.

