├── .gitignore ├── scripts ├── cleanup.sh └── oem.sh ├── oem ├── opennebula-common ├── opennebula-ssh-key ├── opennebula-cloudinit ├── coreos-setup-environment ├── opennebula-hostname └── opennebula-network ├── templates ├── t1.micro.tmpl └── coreos-alpha.tmpl ├── packer.sh ├── files ├── vagrant_id_rsa └── install.yml ├── coreos.json ├── Makefile ├── generate-appliance-json.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /builds/ 2 | /packer_cache/ -------------------------------------------------------------------------------- /scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Remove SSH server keys from image. 4 | 5 | sudo rm -f /etc/ssh/ssh_host_*_key 6 | sudo rm -f /etc/ssh/ssh_host_*_key.pub 7 | -------------------------------------------------------------------------------- /oem/opennebula-common: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$DEBUG" ] ; then 4 | set -x 5 | fi 6 | 7 | echo "Reading OpenNebula context variables" 8 | 9 | if [ ! -r /mnt/context.sh ] ; then 10 | mount -L CONTEXT -o ro /mnt 11 | fi 12 | . /mnt/context.sh 13 | umount /mnt 14 | -------------------------------------------------------------------------------- /oem/opennebula-ssh-key: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$DEBUG" ] ; then 4 | set -x 5 | fi 6 | 7 | here="$(cd $(dirname $0) && pwd)" 8 | 9 | . $here/opennebula-common 10 | 11 | echo "Adding OpenNebula SSH public key" 12 | echo $SSH_PUBLIC_KEY | update-ssh-keys -u core -a coreos-cloudinit -------------------------------------------------------------------------------- /scripts/oem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Put the OEM `cloud-config` dependent scripts in the right place. 4 | sudo mkdir /usr/share/oem/bin 5 | for f in cloudinit common hostname network ssh-key ; do 6 | sudo mv ~/opennebula-$f /usr/share/oem/bin/ 7 | done 8 | sudo mv ~/coreos-setup-environment /usr/share/oem/bin/ 9 | sudo chown -R root: /usr/share/oem/ 10 | sudo chmod -R 0755 /usr/share/oem/bin 11 | -------------------------------------------------------------------------------- /templates/t1.micro.tmpl: -------------------------------------------------------------------------------- 1 | NAME = t1.micro 2 | EC2_INSTANCE_TYPE = t1.micro 3 | MEMORY = 512 4 | CPU = 1 5 | HYPERVISOR = kvm 6 | OS = [ 7 | ARCH = x86_64, 8 | BOOT = hd 9 | ] 10 | NIC=[ 11 | NETWORK = private-net 12 | ] 13 | NIC=[ 14 | NETWORK = public-net 15 | ] 16 | GRAPHICS = [ 17 | TYPE = VNC, 18 | LISTEN = 0.0.0.0 19 | ] 20 | CONTEXT = [ 21 | NETWORK = YES, 22 | SET_HOSTNAME = "$NAME", 23 | SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" 24 | ] 25 | -------------------------------------------------------------------------------- /packer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | if [ -r /dev/kvm ] ; then 6 | accelerator="kvm" 7 | boot_wait="60s" 8 | else 9 | accelerator="none" 10 | boot_wait="120s" 11 | fi 12 | headless="${HEADLESS:-false}" 13 | 14 | exec packer $1 \ 15 | -var accelerator=$accelerator \ 16 | -var boot_wait=$boot_wait \ 17 | -var headless=$headless \ 18 | -var coreos_channel=$COREOS_CHANNEL \ 19 | -var coreos_version=$COREOS_VERSION \ 20 | -var iso_checksum=$COREOS_MD5_CHECKSUM \ 21 | $2 22 | -------------------------------------------------------------------------------- /templates/coreos-alpha.tmpl: -------------------------------------------------------------------------------- 1 | NAME = coreos-alpha 2 | MEMORY = 512 3 | CPU = 1 4 | HYPERVISOR = kvm 5 | OS = [ 6 | ARCH = x86_64, 7 | BOOT = hd 8 | ] 9 | DISK = [ 10 | DRIVER = qcow2, 11 | IMAGE = coreos-alpha 12 | ] 13 | NIC=[ 14 | NETWORK = private-net 15 | ] 16 | NIC=[ 17 | NETWORK = public-net 18 | ] 19 | GRAPHICS = [ 20 | TYPE = VNC, 21 | LISTEN = 0.0.0.0 22 | ] 23 | USER_INPUTS = [ 24 | USER_DATA = "M|text|User data for `cloud-config`" 25 | ] 26 | CONTEXT = [ 27 | NETWORK = YES, 28 | SET_HOSTNAME = "$NAME", 29 | SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]", 30 | USER_DATA = "$USER_DATA" 31 | ] 32 | -------------------------------------------------------------------------------- /oem/opennebula-cloudinit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$DEBUG" ] ; then 4 | set -x 5 | fi 6 | 7 | here="$(cd $(dirname $0) && pwd)" 8 | 9 | . $here/opennebula-common 10 | 11 | echo "Running cloud-init with user data" 12 | 13 | if [ -z "$USER_DATA" ] ; then 14 | if [ -z "$EC2_USER_DATA" ] ; then 15 | echo "No user data, leaving." 16 | exit 0 17 | fi 18 | USER_DATA="$(echo $EC2_USER_DATA | base64 -d)" 19 | fi 20 | 21 | user_data="$(mktemp /tmp/user-data-XXXXXX.yml)" 22 | echo "$USER_DATA" > $user_data 23 | 24 | set -e 25 | coreos-cloudinit --from-file $user_data --validate 26 | coreos-cloudinit --from-file $user_data 27 | -------------------------------------------------------------------------------- /oem/coreos-setup-environment: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ENV=$1 4 | 5 | if [[ -z "$ENV" ]]; then 6 | echo "usage: $0 /etc/environment" >&2 7 | exit 1 8 | fi 9 | 10 | # Make sure that the file is writable 11 | touch $ENV 12 | if [[ $? -ne 0 ]]; then 13 | echo "$0: unable to modify ${ENV}" >&2 14 | exit 1 15 | fi 16 | 17 | sed -i -e '/^COREOS_PUBLIC_IPV4=/d' \ 18 | -e '/^COREOS_PRIVATE_IPV4=/d' \ 19 | "${ENV}" 20 | 21 | here="$(cd $(dirname $0) && pwd)" 22 | . $here/opennebula-common 23 | 24 | if [ -z "$ETH0_IP" ] ; then 25 | exit 0 26 | fi 27 | 28 | echo "COREOS_PRIVATE_IPV4=$ETH0_IP" >> $ENV 29 | if [ -n "$ETH1_IP" ] ; then 30 | echo "COREOS_PUBLIC_IPV4=$ETH1_IP" >> $ENV 31 | else 32 | echo "COREOS_PUBLIC_IPV4=$ETH0_IP" >> $ENV 33 | fi 34 | -------------------------------------------------------------------------------- /oem/opennebula-hostname: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$DEBUG" ] ; then 4 | set -x 5 | fi 6 | 7 | here="$(cd $(dirname $0) && pwd)" 8 | 9 | . $here/opennebula-common 10 | 11 | echo "Setting host name" 12 | 13 | if [ -z "$SET_HOSTNAME" ] ; then 14 | # No host name provided by user. Try guessing it. 15 | 16 | if [ "$DNS_HOSTNAME" = "YES" ] ; then 17 | # Try DNS. 18 | for i in $(seq 0 9) ; do 19 | ip_var="ETH${i}_IP" 20 | if [ -n "${!ip_var}" ] ; then 21 | hostname="$(host ${!ip_var})" 22 | if [ "$?" = "0" ] ; then 23 | SET_HOSTNAME=$hostname 24 | break 25 | fi 26 | fi 27 | done 28 | fi 29 | 30 | if [ -z "$SET_HOSTNAME" ] ; then 31 | # DNS lookup did not work (or lookup was not requested), try 32 | # MAC addresses. 33 | for i in $(seq 0 9) ; do 34 | mac_var="ETH${i}_MAC" 35 | if [ -n "${!mac_var}" ] ; then 36 | SET_HOSTNAME="coreos-$(echo "${!mac_var}" | tr : -)" 37 | break 38 | fi 39 | done 40 | fi 41 | 42 | if [ -z "$SET_HOSTNAME" ] ; then 43 | # No MAC addresses found 44 | SET_HOSTNAME="localhost" 45 | fi 46 | 47 | fi 48 | 49 | # Ensure there are no dots in the host name. 50 | SET_HOSTNAME="$(echo $SET_HOSTNAME | tr . -)" 51 | 52 | hostnamectl set-hostname $SET_HOSTNAME 53 | -------------------------------------------------------------------------------- /files/vagrant_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI 3 | w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP 4 | kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2 5 | hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO 6 | Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW 7 | yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd 8 | ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1 9 | Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf 10 | TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK 11 | iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A 12 | sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf 13 | 4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP 14 | cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk 15 | EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN 16 | CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX 17 | 3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG 18 | YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj 19 | 3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+ 20 | dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz 21 | 6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC 22 | P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF 23 | llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ 24 | kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH 25 | +vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ 26 | NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s= 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /coreos.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "CoreOS image for OpenNebula", 3 | "variables": { 4 | "accelerator": "kvm", 5 | "boot_wait": "60s", 6 | "coreos_channel": "alpha", 7 | "coreos_version": "", 8 | "headless": "false", 9 | "install_target": "/dev/vda", 10 | "iso_checksum": "", 11 | "iso_checksum_type": "md5", 12 | "memory": "1024" 13 | }, 14 | "builders": [ 15 | { 16 | "type": "qemu", 17 | "iso_url": "http://{{user `coreos_channel`}}.release.core-os.net/amd64-usr/{{user `coreos_version`}}/coreos_production_iso_image.iso", 18 | "iso_checksum": "{{user `iso_checksum`}}", 19 | "iso_checksum_type": "{{user `iso_checksum_type`}}", 20 | "ssh_username": "core", 21 | "accelerator": "{{user `accelerator`}}", 22 | "boot_command": [ 23 | "sudo -i", 24 | "systemctl stop sshd.socket", 25 | "wget http://{{ .HTTPIP }}:{{ .HTTPPort }}/install.yml", 26 | "coreos-install -d {{user `install_target`}} -C {{user `coreos_channel`}} -c install.yml", 27 | "reboot" 28 | ], 29 | "boot_wait": "{{user `boot_wait`}}", 30 | "disk_size": 10240, 31 | "format": "qcow2", 32 | "headless": "{{user `headless`}}", 33 | "http_directory": "files", 34 | "output_directory": "builds/coreos-{{user `coreos_channel`}}-{{user `coreos_version`}}-qemu", 35 | "qemuargs": [ 36 | ["-m", "{{user `memory`}}"] 37 | ], 38 | "shutdown_command": "sudo -S shutdown -P now", 39 | "communicator": "ssh", 40 | "ssh_private_key_file": "files/vagrant_id_rsa", 41 | "ssh_timeout": "60m", 42 | "ssh_username": "core" 43 | } 44 | ], 45 | "provisioners": [ 46 | { 47 | "type": "file", 48 | "source": "oem/", 49 | "destination": "/home/core" 50 | }, 51 | { 52 | "type": "shell", 53 | "environment_vars": [], 54 | "scripts": [ 55 | "scripts/oem.sh", 56 | "scripts/cleanup.sh" 57 | ] 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | COREOS_CHANNEL = alpha 2 | COREOS_VERSION = 1000.0.0 3 | COREOS_MD5_CHECKSUM = 2207f09699ee37e79c32aae972432059 4 | OPENNEBULA_DATASTORE = default 5 | 6 | PACKER_IMAGE_DIR = builds/coreos-$(COREOS_CHANNEL)-$(COREOS_VERSION)-qemu 7 | PACKER_IMAGE_NAME = coreos-$(COREOS_CHANNEL)-$(COREOS_VERSION) 8 | PACKER_IMAGE = $(PACKER_IMAGE_DIR)/$(PACKER_IMAGE_NAME) 9 | PACKER_IMAGE_BZ2 = $(PACKER_IMAGE).bz2 10 | PACKER_IMAGE_DEPS = \ 11 | coreos.json \ 12 | packer.sh \ 13 | files/install.yml \ 14 | oem/coreos-setup-environment \ 15 | oem/opennebula-cloudinit \ 16 | oem/opennebula-common \ 17 | oem/opennebula-hostname \ 18 | oem/opennebula-network \ 19 | oem/opennebula-ssh-key \ 20 | scripts/cleanup.sh \ 21 | scripts/oem.sh 22 | 23 | all: $(PACKER_IMAGE) 24 | 25 | $(PACKER_IMAGE): $(PACKER_IMAGE_DEPS) 26 | rm -rf $(PACKER_IMAGE_DIR) 27 | env \ 28 | COREOS_CHANNEL=$(COREOS_CHANNEL) \ 29 | COREOS_VERSION=$(COREOS_VERSION) \ 30 | COREOS_MD5_CHECKSUM=$(COREOS_MD5_CHECKSUM) \ 31 | PACKER_LOG=1 \ 32 | ./packer.sh validate coreos.json 33 | env \ 34 | COREOS_CHANNEL=$(COREOS_CHANNEL) \ 35 | COREOS_VERSION=$(COREOS_VERSION) \ 36 | COREOS_MD5_CHECKSUM=$(COREOS_MD5_CHECKSUM) \ 37 | PACKER_LOG=1 \ 38 | ./packer.sh build coreos.json 39 | mv $(PACKER_IMAGE_DIR)/packer-qemu $(PACKER_IMAGE) 40 | bzip2 -9vk $(PACKER_IMAGE) 41 | echo "Image file $(PACKER_IMAGE) ready" 42 | 43 | .PHONY: appliance register clean 44 | 45 | OPENNEBULA_IMAGE = coreos-$(COREOS_CHANNEL) 46 | 47 | register: $(PACKER_IMAGE) 48 | -oneimage delete $(OPENNEBULA_IMAGE) 49 | oneimage create \ 50 | --name $(OPENNEBULA_IMAGE) \ 51 | --description "CoreOS $(COREOS_CHANNEL) (version $(COREOS_VERSION))" \ 52 | --type OS \ 53 | --driver qcow2 \ 54 | --datastore $(OPENNEBULA_DATASTORE) \ 55 | --path $(PACKER_IMAGE) 56 | echo "EC2_AMI=YES" > .ec2_attrs 57 | oneimage update $(OPENNEBULA_IMAGE) --append .ec2_attrs 58 | rm -f .ec2_attrs 59 | 60 | appliance: $(PACKER_IMAGE) 61 | ./generate-appliance-json.py \ 62 | --output appliance.json \ 63 | $(COREOS_CHANNEL) \ 64 | $(COREOS_VERSION) \ 65 | $(PACKER_IMAGE).bz2 \ 66 | $(IMAGE_URL) 67 | 68 | clean: 69 | rm -rf builds 70 | -------------------------------------------------------------------------------- /files/install.yml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | units: 5 | # Disable CoreOS' default DHCP network setup. 6 | - name: zz-default.network 7 | content: "" 8 | 9 | # Set up network parameters for `systemd-networkd.service` from 10 | # OpenNebula context variables. 11 | - name: opennebula-network.service 12 | command: restart 13 | runtime: yes 14 | content: | 15 | [Unit] 16 | Description=OpenNebula network setup 17 | Before=systemd-networkd.service 18 | After=network-pre.target 19 | 20 | [Service] 21 | Type=oneshot 22 | StandardOutput=journal+console 23 | ExecStart=/usr/share/oem/bin/opennebula-network 24 | 25 | # Reload network configuration (with debugging enabled, in case 26 | # something goes wrong). 27 | - name: systemd-networkd.service 28 | drop-ins: 29 | - name: 10-debug.conf 30 | content: | 31 | [Service] 32 | Environment=SYSTEMD_LOG_LEVEL=debug 33 | command: restart 34 | 35 | # Set host name (might need network to be up in order to do DNS 36 | # queries). 37 | - name: opennebula-hostname.service 38 | command: restart 39 | runtime: yes 40 | content: | 41 | [Unit] 42 | Description=Set host name. 43 | Requires=network.target 44 | After=network.target 45 | 46 | [Service] 47 | Type=oneshot 48 | ExecStart=/usr/share/oem/bin/opennebula-hostname 49 | 50 | # Set SSH public key for CoreOS user `core` from OpenNebula 51 | # context variables. 52 | - name: opennebula-ssh-key.service 53 | command: restart 54 | runtime: yes 55 | content: | 56 | [Unit] 57 | Description=OpenNebula SSH key setup 58 | 59 | [Service] 60 | Type=oneshot 61 | StandardOutput=journal+console 62 | ExecStart=/usr/share/oem/bin/opennebula-ssh-key 63 | 64 | # Process `cloud-config` user data from OpenNebula context 65 | # variables. 66 | - name: opennebula-cloudinit.service 67 | command: restart 68 | runtime: yes 69 | content: | 70 | [Unit] 71 | Description=User-provided cloud-init setup 72 | Requires=network.target,coreos-setup-environment.service 73 | After=network.target,coreos-setup-environment.service 74 | 75 | [Service] 76 | Type=oneshot 77 | EnvironmentFile=/etc/environment 78 | ExecStart=/usr/share/oem/bin/opennebula-cloudinit 79 | 80 | oem: 81 | id: opennebula 82 | name: OpenNebula 83 | version-id: 0.1 84 | home-url: http://github.com/carletes/coreos-opennebula-image 85 | bug-report-url: http://github.com/carletes/coreos-opennebula-image 86 | 87 | ssh_authorized_keys: 88 | # Set Vagrant's insecure SSH public key for second stage of 89 | # installation (it will be overwritten with the user's SSH key by 90 | # `opennebula-ssh-key.service`). 91 | - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key 92 | -------------------------------------------------------------------------------- /oem/opennebula-network: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$DEBUG" ] ; then 4 | set -x 5 | fi 6 | 7 | here="$(cd $(dirname $0) && pwd)" 8 | 9 | . $here/opennebula-common 10 | 11 | function setup_interface() { 12 | iface="$1" 13 | 14 | network_mask_var="${iface}_MASK" 15 | case "${!network_mask_var}" in 16 | "") 17 | ;; 18 | 128.0.0.0) 19 | netmask=1 20 | ;; 21 | 22 | 192.0.0.0) 23 | netmask=2 24 | ;; 25 | 26 | 224.0.0.0) 27 | netmask=3 28 | ;; 29 | 30 | 240.0.0.0) 31 | netmask=4 32 | ;; 33 | 34 | 248.0.0.0) 35 | netmask=5 36 | ;; 37 | 38 | 252.0.0.0) 39 | netmask=6 40 | ;; 41 | 42 | 254.0.0.0) 43 | netmask=7 44 | ;; 45 | 46 | 255.0.0.0) 47 | netmask=8 48 | ;; 49 | 50 | 255.128.0.0) 51 | netmask=9 52 | ;; 53 | 54 | 255.192.0.0) 55 | netmask=10 56 | ;; 57 | 58 | 255.224.0.0) 59 | netmask=11 60 | ;; 61 | 62 | 255.240.0.0) 63 | netmask=12 64 | ;; 65 | 66 | 255.248.0.0) 67 | netmask=13 68 | ;; 69 | 70 | 255.252.0.0) 71 | netmask=14 72 | ;; 73 | 74 | 255.254.0.0) 75 | netmask=15 76 | ;; 77 | 78 | 255.255.0.0) 79 | netmask=16 80 | ;; 81 | 82 | 255.255.128.0) 83 | netmask=17 84 | ;; 85 | 86 | 255.255.192.0) 87 | netmask=18 88 | ;; 89 | 90 | 255.255.224.0) 91 | netmask=19 92 | ;; 93 | 94 | 255.255.240.0) 95 | netmask=20 96 | ;; 97 | 98 | 255.255.248.0) 99 | netmask=21 100 | ;; 101 | 102 | 255.255.252.0) 103 | netmask=22 104 | ;; 105 | 106 | 255.255.254.0) 107 | netmask=23 108 | ;; 109 | 110 | 255.255.255.0) 111 | netmask=24 112 | ;; 113 | 114 | 255.255.255.128) 115 | netmask=25 116 | ;; 117 | 118 | 255.255.255.192) 119 | netmask=26 120 | ;; 121 | 122 | 255.255.255.224) 123 | netmask=27 124 | ;; 125 | 126 | 255.255.255.240) 127 | netmask=28 128 | ;; 129 | 130 | 255.255.255.248) 131 | netmask=29 132 | ;; 133 | 134 | 255.255.255.252) 135 | netmask=30 136 | ;; 137 | 138 | 255.255.255.254) 139 | netmask=31 140 | ;; 141 | *) 142 | echo "Unsupported netmask ${!network_mask_var}" 143 | exit 1 144 | ;; 145 | esac 146 | 147 | ip_address_var="${iface}_IP" 148 | mac_address_var="${iface}_MAC" 149 | gateway_var="${iface}_GATEWAY" 150 | dns_var="${iface}_DNS" 151 | 152 | network_conf="/etc/systemd/network/99-opennebula-$(echo ${!mac_address_var} | tr : -).network" 153 | if [ -n "$DEBUG" ] ; then 154 | network_conf="/tmp/opennebula.network" 155 | fi 156 | 157 | echo "${!mac_address_var}: IP Address is ${!ip_address_var}/$netmask" 158 | cat > $network_conf <> $network_conf <> $network_conf <> $network_conf <> $network_conf < 35 | 36 | Contributions are most welcome! 37 | """.strip() 38 | 39 | IMAGE_TEMPLATE_TEXT = json.dumps({ 40 | "CONTEXT": { 41 | "NETWORK": "YES", 42 | "SET_HOSTNAME": "$NAME", 43 | "SSH_PUBLIC_KEY": "$USER[SSH_PUBLIC_KEY]", 44 | "USER_DATA": "$USER_DATA", 45 | }, 46 | "CPU": "1", 47 | "GRAPHICS": { 48 | "LISTEN": "0.0.0.0", 49 | "TYPE": "vnc" 50 | }, 51 | "MEMORY": "512", 52 | "OS": { 53 | "ARCH": "x86_64" 54 | }, 55 | "USER_INPUTS": { 56 | "USER_DATA": "M|text|User data for `cloud-config`", 57 | } 58 | }) 59 | 60 | 61 | def main(): 62 | p = argparse.ArgumentParser(description=__doc__.strip()) 63 | p.add_argument("channel", 64 | help="CoreOS channel of the image") 65 | p.add_argument("version", 66 | help="CoreOS version of the image") 67 | p.add_argument("image", 68 | help="path to the qcow2 image file") 69 | p.add_argument("url", 70 | help="URL of qcow2 image file") 71 | p.add_argument("--output", 72 | help=("path to the outpu JSON file. If not given, the " 73 | "image will not be uploaded.")) 74 | 75 | args = p.parse_args() 76 | vars = { 77 | "channel": args.channel, 78 | "version": args.version, 79 | } 80 | 81 | hypervisor = "KVM" 82 | image_fmt = "qcow2" 83 | os_arch = "x86_64" 84 | os_id = "CoreOS" 85 | os_release = "%s (%s channel)" % (args.version, args.channel) 86 | appliance = json.dumps({ 87 | "name": "CoreOS %s" % (args.channel,), 88 | "short_description": SHORT_DESCRIPTION_TEMPLATE % vars, 89 | "description": DESCRIPTION_TEMPLATE % vars, 90 | "version": args.version, 91 | "opennebula_version": "4.14", 92 | "files": [ 93 | { 94 | "name": "coreos-%s-%s" % (args.channel, args.version), 95 | "url": args.url, 96 | "size": str(os.stat(args.image).st_size), 97 | "md5": md5_hash(args.image), 98 | "compression": "bz2", 99 | "driver": image_fmt, 100 | "type": "OS", 101 | "hypervisor": hypervisor, 102 | "format": image_fmt, 103 | "os-id": os_id, 104 | "os-release": os_release, 105 | "os-arch": os_arch, 106 | } 107 | ], 108 | "hypervisor": hypervisor, 109 | "format": image_fmt, 110 | "os-id": os_id, 111 | "os-release": os_release, 112 | "os-arch": os_arch, 113 | "opennebula_template": IMAGE_TEMPLATE_TEXT, 114 | }, indent=4) 115 | 116 | if args.output is None: 117 | print appliance 118 | return 119 | 120 | with open(args.output, "w") as f: 121 | f.write(appliance) 122 | 123 | 124 | def md5_hash(fname): 125 | md5 = hashlib.md5() 126 | with open(fname, "rb") as f: 127 | md5.update(f.read()) 128 | return md5.hexdigest() 129 | 130 | 131 | if __name__ == "__main__": 132 | sys.exit(main()) 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoreOS image for OpenNebula 2 | 3 | This repository contains a [Packer](https://www.packer.io) template 4 | for creating [CoreOS](https://coreos.com) KVM images for 5 | [OpenNebula](http://opennebula.org). 6 | 7 | Based on [@bfraser](https://github.com/bfraser)'s 8 | [packer-coreos-qemu](https://github.com/bfraser/packer-coreos-qemu). 9 | 10 | 11 | ## Building the OpenNebula image 12 | 13 | You will need: 14 | 15 | * [Packer](https://www.packer.io) (tested with version 0.10.0) 16 | * [QEMU](http://wiki.qemu.org/Main_Page) (tested with version 2.0.0) 17 | * [GNU Make](https://www.gnu.org/software/make/) 18 | 19 | A Linux host with KVM support will make the build much faster. 20 | 21 | The build process is driven with `make`: 22 | 23 | $ make 24 | [..] 25 | Image file builds/coreos-alpha-991.0.0-qemu/packer-qemu ready 26 | $ 27 | 28 | By default, `make` will build a CoreOS image from the 29 | [CoreOS alpha channel](https://coreos.com/releases/). You may specify 30 | a particular CoreOS version and channel by passing the appropriate 31 | parameters to `make`: 32 | 33 | $ make COREOS_CHANNEL=stable COREOS_VERSION=899.13.0 COREOS_MD5_CHECKSUM=31f1756ecdf5bca92a8bff355417598f 34 | [..] 35 | Image file builds/coreos-stable-899.13.0-qemu/packer-qemu ready 36 | $ 37 | 38 | 39 | ## Registering the image with OpenNebula 40 | 41 | Once the image has been built, you may upload it to OpenNebula using 42 | the 43 | [Sunstone UI](http://docs.opennebula.org/4.14/user/virtual_resource_management/img_guide.html#id1). 44 | 45 | Alternatively, if you are allowed to access OpenNebula using its 46 | [command-line tools](http://docs.opennebula.org/4.14/user/references/cli.html#id1), 47 | you may upload the image usng `make`: 48 | 49 | $ make register 50 | 51 | The `register` target also accepts specific CoreOS channels and 52 | versions: 53 | 54 | $ make register COREOS_CHANNEL=stable COREOS_VERSION=899.13.0 COREOS_MD5_CHECKSUM=31f1756ecdf5bca92a8bff355417598f 55 | 56 | If you plan on using OpenNebula's 57 | [EC2 interface](http://docs.opennebula.org/4.14/advanced_administration/public_cloud/ec2qcg.html), 58 | the image should be tagged with the attribute `EC2_AMI` set to `YES` 59 | (the `register` target does this for you). 60 | 61 | 62 | ## Creating an OpenNebula VM template 63 | 64 | Before creating CoreOS VMs, you will need to create an 65 | [OpenNebula VM template](http://docs.opennebula.org/4.14/user/virtual_resource_management/vm_guide.html#creating-virtual-machines) 66 | which uses the CoreOS images you have built. The VM template should 67 | follow these conventions: 68 | 69 | * It should use the image you have created and uploaded. 70 | * The first network interface will be used as CoreOS' private IPv4 71 | address. 72 | * If there is a second network interface defined, it will be used as 73 | CoreOS' public IPv4 network. 74 | * You should add a user input field called `USER_DATA`, so that you 75 | may pass extra 76 | [cloud-config](https://coreos.com/os/docs/latest/cloud-config.html) 77 | user data to configure your CoreOS instance. 78 | 79 | The following template assumes a CoreOS image called `coreos-alpha`, 80 | and two virtual networks called `public-net` and `private-net`, and 81 | uses them to provide the disk and the two network interfaces of a 82 | virtual machine: 83 | 84 | NAME = coreos-alpha 85 | MEMORY = 512 86 | CPU = 1 87 | HYPERVISOR = kvm 88 | OS = [ 89 | ARCH = x86_64, 90 | BOOT = hd 91 | ] 92 | DISK = [ 93 | DRIVER = qcow2, 94 | IMAGE = coreos-alpha 95 | ] 96 | NIC=[ 97 | NETWORK = private-net 98 | ] 99 | NIC=[ 100 | NETWORK = public-net 101 | ] 102 | GRAPHICS = [ 103 | TYPE = VNC, 104 | LISTEN = 0.0.0.0 105 | ] 106 | USER_INPUTS = [ 107 | USER_DATA = "M|text|User data for `cloud-config`" 108 | ] 109 | CONTEXT = [ 110 | NETWORK = YES, 111 | SET_HOSTNAME = "$NAME", 112 | SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]", 113 | USER_DATA = "$USER_DATA" 114 | ] 115 | 116 | 117 | ### Templates for the OpenNebula EC2 interface 118 | 119 | If you plan on using OpenNebula's 120 | [EC2 interface](http://docs.opennebula.org/4.14/advanced_administration/public_cloud/ec2qcg.html), 121 | your template should follow instead these conventions: 122 | 123 | * It must **not** use any image, since the disk will be provided by 124 | the AMI you choose when you create your instances. 125 | * It must include the attribute `EC2_INSTANCE_TYPE` set to a valid AWS 126 | instance type. If you plan on using OpenNebula's `econe-*` 127 | command-line tools, ensure that name is recognised by the Ruby AWS 128 | modules they depend on. 129 | * The first network interface will be used as CoreOS' private IPv4 130 | address. 131 | * If there is a second network interface defined, it will be used as 132 | CoreOS' public IPv4 network. 133 | 134 | The following template assumes you have two virtual networks called 135 | `public-net` and `private-net`, and uses them to provide the two 136 | network interfaces of a virtual machine: 137 | 138 | NAME = t1.micro 139 | EC2_INSTANCE_TYPE = t1.micro 140 | MEMORY = 512 141 | CPU = 1 142 | HYPERVISOR = kvm 143 | OS = [ 144 | ARCH = x86_64, 145 | BOOT = hd 146 | ] 147 | NIC=[ 148 | NETWORK = private-net 149 | ] 150 | NIC=[ 151 | NETWORK = public-net 152 | ] 153 | GRAPHICS = [ 154 | TYPE = VNC, 155 | LISTEN = 0.0.0.0 156 | ] 157 | CONTEXT = [ 158 | NETWORK = YES, 159 | SET_HOSTNAME = "$NAME", 160 | SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" 161 | ] 162 | 163 | 164 | ### Setting the VM host name 165 | 166 | In both examples above, the host name in the VM will be set to the 167 | OpenNebula VM name. If you want the host name to be assigned by 168 | reverse DNS lookup, replace the line: 169 | 170 | SET_HOSTNAME = "SNAME" 171 | 172 | with: 173 | 174 | DNS_HOSTNAME = YES 175 | 176 | in the `CONTEXT` section, as you would do with any other OpenNebula 177 | template. 178 | 179 | If no host name is passed (or none can be found with reverse DNS 180 | lookup), the VM host name will be set to a value based on the MAC 181 | address of the first network interface. 182 | 183 | If you specify a value for the `hostname` field in the `cloud-config` 184 | user data, it will take precedence over anything else. 185 | 186 | 187 | ## Contributing 188 | 189 | Just fork this repository and open a pull request. 190 | --------------------------------------------------------------------------------