From fb5d630c9b6ea422fbf9d40c72a9c92f8b6c2ca4 Mon Sep 17 00:00:00 2001 From: Olivier Sallou Date: Mon, 7 Apr 2014 14:23:24 +0200 Subject: [PATCH] add azure provider --- bootstrapvz/providers/azure/README.md | 28 +++++++ bootstrapvz/providers/azure/__init__.py | 73 +++++++++++++++++++ .../providers/azure/manifest-schema.json | 40 ++++++++++ bootstrapvz/providers/azure/tasks/__init__.py | 0 bootstrapvz/providers/azure/tasks/boot.py | 17 +++++ bootstrapvz/providers/azure/tasks/image.py | 26 +++++++ bootstrapvz/providers/azure/tasks/packages.py | 51 +++++++++++++ manifests/azure.manifest.json | 40 ++++++++++ 8 files changed, 275 insertions(+) create mode 100644 bootstrapvz/providers/azure/README.md create mode 100644 bootstrapvz/providers/azure/__init__.py create mode 100644 bootstrapvz/providers/azure/manifest-schema.json create mode 100644 bootstrapvz/providers/azure/tasks/__init__.py create mode 100644 bootstrapvz/providers/azure/tasks/boot.py create mode 100644 bootstrapvz/providers/azure/tasks/image.py create mode 100644 bootstrapvz/providers/azure/tasks/packages.py create mode 100644 manifests/azure.manifest.json diff --git a/bootstrapvz/providers/azure/README.md b/bootstrapvz/providers/azure/README.md new file mode 100644 index 0000000..b428f00 --- /dev/null +++ b/bootstrapvz/providers/azure/README.md @@ -0,0 +1,28 @@ +Azure provider +=========== + +This provider generates raw images for Microsoft Azure computing platform. +It also supports an optional virtio integration. + +Setup +===== + +qemu-img >= 1.7.0 required to convert raw image to vhd fixed size disk. +This release is available in wheezy-backports. + + +Manifest must use the *raw* format, provider will automatically transform the disk to a vhd disk format. + +Do not create swap space on the OS disk: + +The Windows Azure Linux Agent can automatically configure swap space using the local resource disk that is attached to the VM after provisioning on Azure. Modify the following parameters in /etc/waagent.conf appropriately: + + ResourceDisk.Format=y + ResourceDisk.Filesystem=ext4 + ResourceDisk.MountPoint=/mnt/resource + ResourceDisk.EnableSwap=y + ResourceDisk.SwapSizeMB=2048 ## NOTE: set this to whatever you need it to be. + +You can specify a waagent.conf file to replace the default one in the manifest in the azure/waagent section of the provider: + + "azure" : { "waagent" : "path_to_my_conf_file" }, ... diff --git a/bootstrapvz/providers/azure/__init__.py b/bootstrapvz/providers/azure/__init__.py new file mode 100644 index 0000000..48d17d5 --- /dev/null +++ b/bootstrapvz/providers/azure/__init__.py @@ -0,0 +1,73 @@ +import tasks.packages +import tasks.boot +import tasks.image +from bootstrapvz.common.tasks import volume +from bootstrapvz.common.tasks import loopback +from bootstrapvz.common.tasks import partitioning +from bootstrapvz.common.tasks import filesystem +from bootstrapvz.common.tasks import bootstrap +from bootstrapvz.common.tasks import security +from bootstrapvz.common.tasks import network +from bootstrapvz.common.tasks import initd +from bootstrapvz.common.tasks import cleanup +from bootstrapvz.common.tasks import workspace + + +def initialize(): + pass + + +def validate_manifest(data, validator, error): + import os.path + schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.json')) + validator(data, schema_path) + + if data['volume']['partitions']['type'] == 'none' and data['system']['bootloader'] != 'extlinux': + error('Only extlinux can boot from unpartitioned disks', ['system', 'bootloader']) + + +def resolve_tasks(tasklist, manifest): + from bootstrapvz.common import task_sets + tasklist.update(task_sets.base_set) + tasklist.update(task_sets.volume_set) + tasklist.update(task_sets.mounting_set) + tasklist.update(task_sets.get_apt_set(manifest)) + tasklist.update(task_sets.locale_set) + + tasklist.update(task_sets.bootloader_set.get(manifest.system['bootloader'])) + + if manifest.volume['partitions']['type'] != 'none': + tasklist.update(task_sets.partitioning_set) + + tasklist.update([tasks.packages.DefaultPackages, + loopback.Create, + security.EnableShadowConfig, + network.RemoveDNSInfo, + network.ConfigureNetworkIF, + network.RemoveHostname, + initd.AddSSHKeyGeneration, + initd.InstallInitScripts, + tasks.packages.Waagent, + tasks.boot.ConfigureGrub, + cleanup.ClearMOTD, + cleanup.CleanTMP, + + tasks.image.ConvertToVhd + ]) + + if manifest.bootstrapper.get('tarball', False): + tasklist.add(bootstrap.MakeTarball) + + tasklist.update(task_sets.get_fs_specific_set(manifest.volume['partitions'])) + + if 'boot' in manifest.volume['partitions']: + tasklist.update(task_sets.boot_partition_set) + + +def resolve_rollback_tasks(tasklist, manifest, counter_task): + counter_task(loopback.Create, volume.Delete) + counter_task(filesystem.CreateMountDir, filesystem.DeleteMountDir) + counter_task(partitioning.MapPartitions, partitioning.UnmapPartitions) + counter_task(filesystem.MountRoot, filesystem.UnmountRoot) + counter_task(volume.Attach, volume.Detach) + counter_task(workspace.CreateWorkspace, workspace.DeleteWorkspace) diff --git a/bootstrapvz/providers/azure/manifest-schema.json b/bootstrapvz/providers/azure/manifest-schema.json new file mode 100644 index 0000000..e2e274c --- /dev/null +++ b/bootstrapvz/providers/azure/manifest-schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Azure manifest", + "type": "object", + "properties": { + "azure": { + "type": "object", + "properties": { + "waagent": { + "type": "string" + } + } + }, + "system": { + "type": "object", + "properties": { + "bootloader": { + "type": "string", + "enum": ["grub", "extlinux"] + } + } + }, + "volume": { + "type": "object", + "properties": { + "backing": { + "type": "string", + "enum": ["raw"] + }, + "partitions": { + "type": "object", + "properties": { + "type": { "enum": ["none", "msdos", "gpt"] } + } + } + }, + "required": ["backing"] + } + } +} diff --git a/bootstrapvz/providers/azure/tasks/__init__.py b/bootstrapvz/providers/azure/tasks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bootstrapvz/providers/azure/tasks/boot.py b/bootstrapvz/providers/azure/tasks/boot.py new file mode 100644 index 0000000..e592bbb --- /dev/null +++ b/bootstrapvz/providers/azure/tasks/boot.py @@ -0,0 +1,17 @@ +from bootstrapvz.base import Task +from bootstrapvz.common import phases +from bootstrapvz.common.tasks import boot + +class ConfigureGrub(Task): + description = 'Change grub configuration to allow for ttyS0 output' + phase = phases.system_modification + successors = [boot.InstallGrub] + + @classmethod + def run(cls, info): + import os + from bootstrapvz.common.tools import sed_i + grub_config = os.path.join(info.root, 'etc/default/grub') + sed_i(grub_config, r'^(GRUB_CMDLINE_LINUX*=".*)"\s*$', r'\1console=ttyS0 earlyprintk=ttyS0 rootdelay=300"') + sed_i(grub_config, r'^.*(GRUB_TIMEOUT=).*$', r'GRUB_TIMEOUT=0') + diff --git a/bootstrapvz/providers/azure/tasks/image.py b/bootstrapvz/providers/azure/tasks/image.py new file mode 100644 index 0000000..e9f36e2 --- /dev/null +++ b/bootstrapvz/providers/azure/tasks/image.py @@ -0,0 +1,26 @@ +from bootstrapvz.base import Task +from bootstrapvz.common import phases +from bootstrapvz.common.tasks import loopback + + +class ConvertToVhd(Task): + description = 'Convert raw image to vhd disk' + phase = phases.image_registration + + @classmethod + def run(cls, info): + image_name = info.manifest.image['name'].format(**info.manifest_vars) + filename = '{image_name}.{ext}'.format(image_name=image_name, ext='vhd') + import os.path + destination = os.path.join(info.manifest.bootstrapper['workspace'], filename) + + file_size = os.path.getsize(info.volume.image_path) + rounded_vol_size = str(((file_size/(1024*1024)+1)*(1024*1024))) + + from bootstrapvz.common.tools import log_check_call + log_check_call(['qemu-img', 'resize', info.volume.image_path, rounded_vol_size]) + log_check_call(['qemu-img', 'convert', '-o', 'subformat=fixed', '-O', 'vpc', info.volume.image_path, destination]) + os.remove(info.volume.image_path) + import logging + log = logging.getLogger(__name__) + log.info('The volume image has been moved to {image_path}'.format(image_path=destination)) diff --git a/bootstrapvz/providers/azure/tasks/packages.py b/bootstrapvz/providers/azure/tasks/packages.py new file mode 100644 index 0000000..169c9e6 --- /dev/null +++ b/bootstrapvz/providers/azure/tasks/packages.py @@ -0,0 +1,51 @@ +from bootstrapvz.base import Task +from bootstrapvz.common import phases +from bootstrapvz.common.tasks import apt +from bootstrapvz.common.tasks.packages import InstallPackages + + +class DefaultPackages(Task): + description = 'Adding image packages required for Azure' + phase = phases.preparation + predecessors = [apt.AddDefaultSources] + + @classmethod + def run(cls, info): + kernels = {'amd64': 'linux-image-amd64', + 'i386': 'linux-image-686', } + info.packages.add(kernels.get(info.manifest.system['architecture'])) + info.packages.add('openssl') + info.packages.add('python-openssl') + info.packages.add('openssh-server') + info.packages.add('python-pyasn1') + info.packages.add('git') + info.packages.add('sudo') + #info.packages.add('waagent') + +class Waagent(Task): + description = 'Add waagent' + phase = phases.package_installation + predecessors = [InstallPackages] + + @classmethod + def run(cls, info): + from bootstrapvz.common.tools import log_call + import os + env = os.environ.copy() + env['GIT_SSL_NO_VERIFY'] = 'true' + status, out, err = log_call(['chroot', info.root, + 'git','clone', 'https://github.com/WindowsAzure/WALinuxAgent.git', + '/root/WALinuxAgent'], env=env) + status, out, err = log_call(['chroot', info.root, + 'cp','/root/WALinuxAgent/waagent','/usr/sbin/waagent']) + status, out, err = log_call(['chroot', info.root, + 'chmod','755','/usr/sbin/waagent']) + status, out, err = log_call(['chroot', info.root, + '/usr/sbin/waagent','-install']) + import os.path + if hasattr(info.manifest, 'azure') and info.manifest.azure['waagent']: + if os.path.isfile(info.manifest.azure['waagent']): + status, out, err = log_call(['cp', + info.manifest.azure['waagent'], + os.path.join(info.root,'etc/waagent.conf')]) + diff --git a/manifests/azure.manifest.json b/manifests/azure.manifest.json new file mode 100644 index 0000000..5cef1fe --- /dev/null +++ b/manifests/azure.manifest.json @@ -0,0 +1,40 @@ +{ + "provider": "azure", + "bootstrapper": { + "workspace": "/target", + "mirror": "http://ftp.fr.debian.org/debian/" + }, + "image": { + "name": "debian-{system.release}-{system.architecture}-{%y}{%m}{%d}", + "description": "Debian {system.release} {system.architecture}" + }, + "system": { + "release": "wheezy", + "architecture": "amd64", + "bootloader": "grub", + "timezone": "UTC", + "locale": "en_US", + "charmap": "UTF-8" + }, + "packages": { + }, + "volume": { + "backing": "raw", + "partitions": { + "type": "msdos", + "boot": { + "size": "32MiB", + "filesystem": "ext2" + }, + "root": { + "size": "7GiB", + "filesystem": "ext4" + } + } + }, + "plugins": { + "ntp": { + "servers": ["time.windows.com"] + } + } +}