First stab at docker provider

Huh... That was easy.
This commit is contained in:
Anders Ingemann 2015-12-09 19:00:06 +01:00 committed by Anders Ingemann
parent 3de0aceb65
commit 4a509aba76
12 changed files with 196 additions and 3 deletions

View file

@ -24,12 +24,14 @@ def load_volume(data, bootloader):
from bootstrapvz.common.fs.virtualdiskimage import VirtualDiskImage
from bootstrapvz.common.fs.virtualharddisk import VirtualHardDisk
from bootstrapvz.common.fs.virtualmachinedisk import VirtualMachineDisk
from bootstrapvz.common.fs.folder import Folder
volume_backing = {'raw': LoopbackVolume,
's3': LoopbackVolume,
'vdi': VirtualDiskImage,
'vhd': VirtualHardDisk,
'vmdk': VirtualMachineDisk,
'ebs': EBSVolume
'ebs': EBSVolume,
'folder': Folder
}.get(data['backing'])
# Instantiate the partition map

View file

@ -31,6 +31,13 @@ properties:
tarball: {type: boolean}
workspace:
$ref: '#/definitions/path'
variant:
type: string
enum:
- minbase
- buildd
- fakechroot
- scratchbox
required: [workspace]
additionalProperties: false
image:
@ -50,6 +57,7 @@ properties:
- pvgrub
- grub
- extlinux
- none
charmap: {type: string}
hostname:
type: string

View file

@ -0,0 +1,24 @@
from bootstrapvz.base.fs.volume import Volume
class Folder(Volume):
# Override the states this volume can be in (i.e. we can't "format" or "attach" it)
events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'attached'},
{'name': 'delete', 'src': 'attached', 'dst': 'deleted'},
]
extension = 'chroot'
def create(self, path):
self.fsm.create(path=path)
def _before_create(self, e):
import os
self.path = e.path
os.mkdir(self.path)
def _before_delete(self, e):
from shutil import rmtree
rmtree(self.path)
del self.path

View file

@ -16,6 +16,7 @@ from tasks import network
from tasks import initd
from tasks import ssh
from tasks import kernel
from tasks import folder
def get_standard_groups(manifest):
@ -94,6 +95,9 @@ ssh_group = [ssh.AddOpenSSHPackage,
def get_network_group(manifest):
if manifest.bootstrapper.get('variant', None) == 'minbase':
# minbase has no networking
return []
group = [network.ConfigureNetworkIF,
network.RemoveDNSInfo]
if manifest.system.get('hostname', False):
@ -182,6 +186,7 @@ rollback_map = {workspace.CreateWorkspace: workspace.DeleteWorkspace,
partitioning.MapPartitions: partitioning.UnmapPartitions,
filesystem.CreateMountDir: filesystem.DeleteMountDir,
filesystem.MountRoot: filesystem.UnmountRoot,
folder.Create: folder.Delete,
}

View file

@ -21,6 +21,8 @@ def get_bootstrap_args(info):
executable = ['debootstrap']
arch = info.manifest.system.get('userspace_architecture', info.manifest.system.get('architecture'))
options = ['--arch=' + arch]
if 'variant' in info.manifest.bootstrapper:
options.append('--variant=' + info.manifest.bootstrapper['variant'])
if len(info.include_packages) > 0:
options.append('--include=' + ','.join(info.include_packages))
if len(info.exclude_packages) > 0:
@ -53,8 +55,8 @@ class MakeTarball(Task):
else:
from ..tools import log_call
status, out, err = log_call(executable + options + ['--make-tarball=' + info.tarball] + arguments)
if status != 1:
msg = 'debootstrap exited with status {status}, it should exit with status 1'.format(status=status)
if status not in [0, 1]: # variant=minbase exits with 0
msg = 'debootstrap exited with status {status}, it should exit with status 0 or 1'.format(status=status)
raise TaskError(msg)

View file

@ -0,0 +1,27 @@
from bootstrapvz.base import Task
from bootstrapvz.common import phases
import volume
import workspace
class Create(Task):
description = 'Creating volume folder'
phase = phases.volume_creation
successors = [volume.Attach]
@classmethod
def run(cls, info):
import os.path
info.root = os.path.join(info.workspace, 'root')
info.volume.create(info.root)
class Delete(Task):
description = 'Deleting volume folder'
phase = phases.cleaning
successors = [workspace.DeleteWorkspace]
@classmethod
def run(cls, info):
info.volume.delete()
del info.root

View file

@ -0,0 +1,34 @@
from bootstrapvz.common.tasks import folder
from bootstrapvz.common.tasks import filesystem
from bootstrapvz.common.tasks import locale
from bootstrapvz.common import task_groups
import tasks.commands
import tasks.image
def validate_manifest(data, validator, error):
import os.path
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml'))
validator(data, schema_path)
def resolve_tasks(taskset, manifest):
taskset.update(task_groups.get_base_group(manifest))
taskset.update([folder.Create,
filesystem.CopyMountTable,
locale.SetTimezone,
filesystem.RemoveMountTable,
folder.Delete,
])
taskset.update(task_groups.get_network_group(manifest))
taskset.update(task_groups.get_apt_group(manifest))
taskset.update(task_groups.security_group)
taskset.update(task_groups.cleanup_group)
taskset.update([tasks.commands.AddRequiredCommands,
tasks.image.CreateImage,
])
def resolve_rollback_tasks(taskset, manifest, completed, counter_task):
taskset.update(task_groups.get_standard_rollback_tasks(completed))

View file

@ -0,0 +1,32 @@
---
$schema: http://json-schema.org/draft-04/schema#
title: Docker manifest
type: object
properties:
provider:
type: object
properties:
repository:
type: string
tag:
type: string
required: [repository, tag]
system:
type: object
properties:
bootloader:
type: string
enum: [none]
volume:
type: object
properties:
backing:
type: string
enum: [folder]
partitions:
type: object
properties:
type:
type: string
enum: [none]
required: [backing]

View file

@ -0,0 +1,13 @@
from bootstrapvz.base import Task
from bootstrapvz.common import phases
from bootstrapvz.common.tasks import host
class AddRequiredCommands(Task):
description = 'Adding commands required for docker'
phase = phases.preparation
successors = [host.CheckExternalCommands]
@classmethod
def run(cls, info):
info.host_dependencies['docker'] = 'docker.io'

View file

@ -0,0 +1,20 @@
from bootstrapvz.base import Task
from bootstrapvz.common import phases
from bootstrapvz.common.tasks import image
from bootstrapvz.common.tools import log_check_call
class CreateImage(Task):
description = 'Creating docker image'
phase = phases.image_registration
predecessors = [image.MoveImage]
@classmethod
def run(cls, info):
from pipes import quote
tar_cmd = ['tar', '--create', '--numeric-owner',
'--directory', info.volume.path, '.']
docker_cmd = ['docker', 'import', '-',
info.manifest.provider['repository'] + ':' + info.manifest.provider['tag']]
cmd = ' '.join(map(quote, tar_cmd)) + ' | ' + ' '.join(map(quote, docker_cmd))
[info._docker['container_id']] = log_check_call(cmd, shell=True)

View file

@ -0,0 +1,26 @@
---
provider:
name: docker
repository: bootstrap-vz
tag: latest
bootstrapper:
workspace: /target
variant: minbase
image:
name: debian-{system.release}-{system.architecture}-{%y}{%m}{%d}
description: Debian {system.release} {system.architecture}
system:
release: jessie
architecture: amd64
bootloader: none
charmap: UTF-8
locale: en_US
timezone: UTC
packages: {}
volume:
backing: folder
partitions:
type: none
root:
filesystem: ext4
size: 1GiB