mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +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.virtualdiskimage import VirtualDiskImage
|
||||||
from bootstrapvz.common.fs.virtualharddisk import VirtualHardDisk
|
from bootstrapvz.common.fs.virtualharddisk import VirtualHardDisk
|
||||||
from bootstrapvz.common.fs.virtualmachinedisk import VirtualMachineDisk
|
from bootstrapvz.common.fs.virtualmachinedisk import VirtualMachineDisk
|
||||||
|
from bootstrapvz.common.fs.folder import Folder
|
||||||
volume_backing = {'raw': LoopbackVolume,
|
volume_backing = {'raw': LoopbackVolume,
|
||||||
's3': LoopbackVolume,
|
's3': LoopbackVolume,
|
||||||
'vdi': VirtualDiskImage,
|
'vdi': VirtualDiskImage,
|
||||||
'vhd': VirtualHardDisk,
|
'vhd': VirtualHardDisk,
|
||||||
'vmdk': VirtualMachineDisk,
|
'vmdk': VirtualMachineDisk,
|
||||||
'ebs': EBSVolume
|
'ebs': EBSVolume,
|
||||||
|
'folder': Folder
|
||||||
}.get(data['backing'])
|
}.get(data['backing'])
|
||||||
|
|
||||||
# Instantiate the partition map
|
# Instantiate the partition map
|
||||||
|
|
|
@ -31,6 +31,13 @@ properties:
|
||||||
tarball: {type: boolean}
|
tarball: {type: boolean}
|
||||||
workspace:
|
workspace:
|
||||||
$ref: '#/definitions/path'
|
$ref: '#/definitions/path'
|
||||||
|
variant:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- minbase
|
||||||
|
- buildd
|
||||||
|
- fakechroot
|
||||||
|
- scratchbox
|
||||||
required: [workspace]
|
required: [workspace]
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
image:
|
image:
|
||||||
|
@ -50,6 +57,7 @@ properties:
|
||||||
- pvgrub
|
- pvgrub
|
||||||
- grub
|
- grub
|
||||||
- extlinux
|
- extlinux
|
||||||
|
- none
|
||||||
charmap: {type: string}
|
charmap: {type: string}
|
||||||
hostname:
|
hostname:
|
||||||
type: string
|
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 initd
|
||||||
from tasks import ssh
|
from tasks import ssh
|
||||||
from tasks import kernel
|
from tasks import kernel
|
||||||
|
from tasks import folder
|
||||||
|
|
||||||
|
|
||||||
def get_standard_groups(manifest):
|
def get_standard_groups(manifest):
|
||||||
|
@ -94,6 +95,9 @@ ssh_group = [ssh.AddOpenSSHPackage,
|
||||||
|
|
||||||
|
|
||||||
def get_network_group(manifest):
|
def get_network_group(manifest):
|
||||||
|
if manifest.bootstrapper.get('variant', None) == 'minbase':
|
||||||
|
# minbase has no networking
|
||||||
|
return []
|
||||||
group = [network.ConfigureNetworkIF,
|
group = [network.ConfigureNetworkIF,
|
||||||
network.RemoveDNSInfo]
|
network.RemoveDNSInfo]
|
||||||
if manifest.system.get('hostname', False):
|
if manifest.system.get('hostname', False):
|
||||||
|
@ -182,6 +186,7 @@ rollback_map = {workspace.CreateWorkspace: workspace.DeleteWorkspace,
|
||||||
partitioning.MapPartitions: partitioning.UnmapPartitions,
|
partitioning.MapPartitions: partitioning.UnmapPartitions,
|
||||||
filesystem.CreateMountDir: filesystem.DeleteMountDir,
|
filesystem.CreateMountDir: filesystem.DeleteMountDir,
|
||||||
filesystem.MountRoot: filesystem.UnmountRoot,
|
filesystem.MountRoot: filesystem.UnmountRoot,
|
||||||
|
folder.Create: folder.Delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ def get_bootstrap_args(info):
|
||||||
executable = ['debootstrap']
|
executable = ['debootstrap']
|
||||||
arch = info.manifest.system.get('userspace_architecture', info.manifest.system.get('architecture'))
|
arch = info.manifest.system.get('userspace_architecture', info.manifest.system.get('architecture'))
|
||||||
options = ['--arch=' + arch]
|
options = ['--arch=' + arch]
|
||||||
|
if 'variant' in info.manifest.bootstrapper:
|
||||||
|
options.append('--variant=' + info.manifest.bootstrapper['variant'])
|
||||||
if len(info.include_packages) > 0:
|
if len(info.include_packages) > 0:
|
||||||
options.append('--include=' + ','.join(info.include_packages))
|
options.append('--include=' + ','.join(info.include_packages))
|
||||||
if len(info.exclude_packages) > 0:
|
if len(info.exclude_packages) > 0:
|
||||||
|
@ -53,8 +55,8 @@ class MakeTarball(Task):
|
||||||
else:
|
else:
|
||||||
from ..tools import log_call
|
from ..tools import log_call
|
||||||
status, out, err = log_call(executable + options + ['--make-tarball=' + info.tarball] + arguments)
|
status, out, err = log_call(executable + options + ['--make-tarball=' + info.tarball] + arguments)
|
||||||
if status != 1:
|
if status not in [0, 1]: # variant=minbase exits with 0
|
||||||
msg = 'debootstrap exited with status {status}, it should exit with status 1'.format(status=status)
|
msg = 'debootstrap exited with status {status}, it should exit with status 0 or 1'.format(status=status)
|
||||||
raise TaskError(msg)
|
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