mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 09:50:37 +00:00
First stab at docker provider
Huh... That was easy.
This commit is contained in:
parent
3de0aceb65
commit
4a509aba76
12 changed files with 196 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
24
bootstrapvz/common/fs/folder.py
Normal file
24
bootstrapvz/common/fs/folder.py
Normal 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
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
27
bootstrapvz/common/tasks/folder.py
Normal file
27
bootstrapvz/common/tasks/folder.py
Normal 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
|
34
bootstrapvz/providers/docker/__init__.py
Normal file
34
bootstrapvz/providers/docker/__init__.py
Normal 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))
|
32
bootstrapvz/providers/docker/manifest-schema.yml
Normal file
32
bootstrapvz/providers/docker/manifest-schema.yml
Normal 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]
|
0
bootstrapvz/providers/docker/tasks/__init__.py
Normal file
0
bootstrapvz/providers/docker/tasks/__init__.py
Normal file
13
bootstrapvz/providers/docker/tasks/commands.py
Normal file
13
bootstrapvz/providers/docker/tasks/commands.py
Normal 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'
|
20
bootstrapvz/providers/docker/tasks/image.py
Normal file
20
bootstrapvz/providers/docker/tasks/image.py
Normal 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)
|
26
manifests/examples/docker/jessie.yml
Normal file
26
manifests/examples/docker/jessie.yml
Normal 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
|
Loading…
Add table
Reference in a new issue