# How to Modify Cloud Image QCOW

Cloud images are images that are optimized to run on public clouds
(EC2, OpenStack, etc). Those images are usually small – only necessary
packages are installed. One of the installed packages is
[cloud-init](https://cloudinit.readthedocs.io/en/latest/).
Cloudinit can be used to customize the initialization of the VM instance.
Such initialization can include installation of additional packages, creation
of users, configuration and more. Cloud images usually disable SSH using
username/password, and allow SSH only using key-pair. To overcome this, cloudinit
can be used to configure the
[authorized ssh keys](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#ssh).
Since logging-in to an VM instance using username/password is usually disabled,
we can’t spawn a VM instance from a cloud image in the regular way. We need
to pass the authorized ssh key to cloudinit, and ssh the instance using
key-pair. After connecting to the VM instance we can modify
the image as we want. This guide describes the necessary steps for updating
a cloud image [qcow](https://en.wikipedia.org/wiki/Qcow/).

## Requirements

* **ssh-keygen** - will be used to generate key-pair.
* **genisoimage** - will be used to create iso with the user-data for cloudinit.
* **virt-manager** - will be used to spawn a VM instance from a cloud image.

## Step-by-step Guide

1. **Generate key-pair**
   * First, we need to generate a key-pair that will be used to connect to the
     VM instance. This can be done using the ssh-keygen utility as follows:
     ```default
     ssh-keygen -m pem -f key.pem -t rsa -N ” -C ”
     ```
2. **Create cloudinit user-data and metadata files**
   * Next, you can use cloudinit to configure the authorized ssh key created
     in the previous step. To do this, create the following user-data file:
     ```default
     #cloud-config
     ssh_authorized_keys:
     ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQAzK0lsWxn6Mrj6l60bHEjUUrKKK9KIxb+VfAtOUvx0Z95cnwlkBbx+9ilxEkHe5Mu/QE81cicpGl94Pu4ClHCOghrJ4rWIlP+A37DdIeAA8yNHFOwJHd3acRjPrO49Q76ZFiuTCRvodbq3D+0yS7g9+4aSIyRZD2rr9stFYFPl+jVDzNdVQcfpJSEO7iBXpITSK9apqJuozRr6x2vyinGCR3vwsGDUd9hwtcA3yRLzWyehURo/s/UcYNsed5jjaL5rHLT8jcVDY6f/t1k9RjqkPIp76i81L7n/pIzzLjqINAJomrUNqddWLHMSBKS43xwmdaZeSuJve6Cuizre9b
     ```
   * Replace the ssh key with key generated in the previous step.
   * You also need to supply a metadata file. A minimal metadata file to set
     the hostname of the VM instance, can be defined as follows:
     ```default
     instance-id: iid-local01
     local-hostname: cloudimg
     ```
3. **Generate iso image containing the user-data and meta-data files.**
   * Since the image will not be run in a cloud environment, you should
     use the
     [NoCloud](https://cloudinit.readthedocs.io/en/latest/topics/datasources/nocloud.html)
     mode for cloudinit.
   * In NoCloud mode, cloudinit will read the user-data file from a CDROM device
     (and not from the network).
     ```default
     genisoimage  -output cidata.iso -volid cidata -joliet -rock user-data meta-data
     ```
4. **Spawn a VM from the cloud image.**
   * Use virt-manager to spawn the VM instance.
   * You should customize the configuration before the VM instance starts,
     and attach the VM to the default virtual network (NAT).

     ![20-create-vm](media/20-create-vm.png)
   * Click **Finish**. A custom configuration screen will open.

     ![21-new-vm-details](media/21-new-vm-details.png)
   * Choose **Add Hardware**, and add a CDROM device. You may attach
     the iso file created in the previous step.

     ![22-new-vm-hw](media/22-new-vm-hw.png)
   * You may now start the VM instance.
5. **Connect to VM using SSH**
   * First, you need to determine the IP address allocated to the VM instance.
     This may be done with the following virsh command:
     ```default
     sudo virsh domifaddr <vm-name>
     ```
   * For example, if the VM instance name is fedora22, then the command will
     be as follows:
     ```default
     sudo virsh domifaddr fedora22
     ```
   * And the output will be as follows:
     ```default
     Name    MAC address       Protocol    Address
     ——————————————————————————-
     vnet0   52:54:00:a6:8c:3b    ipv4     192.168.122.99/24
     ```
   * Now you may connect to the VM instance using SSH:
     ```default
     ssh -i <path-to-key.pem> <username>@<ip>
     ```
   * Following the example above, the ssh command will be as follows:
     ```default
     ssh -i key.pem fedora@192.168.122.99
     ```
6. **Modify the image**

   Once you connect to the VM instance, you may modify the image for the
   following:
   * Install packages.
   * Change configuration.
   * Modify directories/files.
   * etc.
7. **Enable cloudinit for the next boot**
   * Note that cloudinit won’t run in the next boot of a VM instance created
     from this image. In order to “reset” cloudinit and force it to run the
     full init process, delete cloudinit’s working directory as follows:
     ```default
     sudo rm -rf /var/lib/cloud/*
     ```
8. **Shutdown the VM**
   * Once you are satisfied with the modifications done in the previous steps,
     you can save all change by simply shutting down the VM instance as
     follows:
     ```default
     sudo shutdown -h 0
     ```

That’s it! Now the qcow of the cloud image contains all the desired modifications.
