[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] Provider for LXC and Proxmox containers



The lxc provider generates .tar.xz images for Linux containers
and also Proxmox containers. It is based upon the docker provider.

Difference between LXC and Proxmox ConTainer,
is that for PCT is file  /etc/appliance.info  added.

Signed-off-by: Geert Stappers <stappers@stappers.nl>
---
 CHANGELOG.rst                                 |   5 ++
 README.rst                                    |   1 +
 bootstrapvz/providers/lxc/README.rst          | 108 ++++++++++++++++++++++++++
 bootstrapvz/providers/lxc/__init__.py         |  38 +++++++++
 bootstrapvz/providers/lxc/manifest-schema.yml |  50 ++++++++++++
 bootstrapvz/providers/lxc/tasks/__init__.py   |   0
 bootstrapvz/providers/lxc/tasks/commands.py   |  13 ++++
 bootstrapvz/providers/lxc/tasks/image.py      |  99 +++++++++++++++++++++++
 manifests/examples/lxc/builder.yml            |  53 +++++++++++++
 manifests/examples/lxc/stretch-minimized.yml  |  36 +++++++++
 10 files changed, 403 insertions(+)
 create mode 100644 bootstrapvz/providers/lxc/README.rst
 create mode 100644 bootstrapvz/providers/lxc/__init__.py
 create mode 100644 bootstrapvz/providers/lxc/manifest-schema.yml
 create mode 100644 bootstrapvz/providers/lxc/tasks/__init__.py
 create mode 100644 bootstrapvz/providers/lxc/tasks/commands.py
 create mode 100644 bootstrapvz/providers/lxc/tasks/image.py
 create mode 100644 manifests/examples/lxc/builder.yml
 create mode 100644 manifests/examples/lxc/stretch-minimized.yml

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 31b129c..a1efb40 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,11 @@
 Changelog
 =========
 
+2017-12-16
+----------
+Geert Stappers
+    * Added provider for LXC and Proxmox VE container
+
 2017-02-20
 ----------
 Hugo Antoniio Sepulveda Manriquez:
diff --git a/README.rst b/README.rst
index ae798c7..d7a111d 100644
--- a/README.rst
+++ b/README.rst
@@ -11,6 +11,7 @@ generates images for the following virtualization platforms:
    `used for official Debian images <https://wiki.debian.org/Cloud/AmazonEC2Image/Jessie>`__;
    `Quick start <#amazon-ec2-ebs-backed-ami>`__)
 -  `Docker <bootstrapvz/providers/docker>`__ (`Quick start <#docker>`__)
+-  `LXC and Proxmox VE Containers <bootstrapvz/providers/lxc>`__
 -  `Google Compute Engine <bootstrapvz/providers/gce>`__
    (`used by Google for official Debian images <https://wiki.debian.org/Cloud/GoogleComputeEngineImage>`__)
 -  `KVM <bootstrapvz/providers/kvm>`__ (Kernel-based Virtual Machine)
diff --git a/bootstrapvz/providers/lxc/README.rst b/bootstrapvz/providers/lxc/README.rst
new file mode 100644
index 0000000..2208600
--- /dev/null
+++ b/bootstrapvz/providers/lxc/README.rst
@@ -0,0 +1,108 @@
+LXC
+===
+
+The `LXC <https://linuxcontainers.org/>`__ provider
+creates a Linux container tarball from scratch.
+
+If the MANIFEST contains ``appliance_info``
+it will include an ``/etc/appliance.info`` for
+`Proxmox <https://pve.proxmox.com/>`__
+
+So the tarball can used as a PCT template.
+Yes, it mimics somewhat the
+`Debian Appliance Builder <https://pve.proxmox.com/wiki/Debian_Appliance_Builder>`__
+
+
+Manifest settings
+-----------------
+
+Provider
+~~~~~~~~
+
+-  ``tarball``: destination filename for the to be created tarball.
+   ``required``
+   ``manifest vars``
+
+-  ``appliance_info``: Information for ``/etc/appliance.info``
+   ``optional``
+   ``manifest vars``
+
+-  Within ``appliance_info`` the fields ``description``,
+   ``maintainer`` and ``section`` are required.
+
+-  The optional ``appliance_info`` field ``long_description``
+   is allowed to be multi line.
+
+Example:
+
+.. code-block:: yaml
+
+    ---
+    provider:
+      name: lxc
+      tarball: ./debian-{system.release}.tar.xz
+      appliance_info:
+        description: Debian {system.release} {system.architecture}
+        long_description: |
+          Debian {system.release}
+          for the {system.architecture} architecture.
+          .
+          Generated by bootstrap-vz LXC provider.
+        section: public
+        maintainer: You <you@example.com>
+        infopage: http://www.example.com/template/info
+
+
+Usage
+-----
+
+Using the created vz image is easy for proxmox,
+for plain LXC it needs more steps.
+
+Proxmox
+~~~~~~~
+
+Place tarball in ``/var/lib/vz/template/cache/``.
+
+It shows up as template while creating a new container.
+
+
+LXC
+~~~
+
+Say you want to use the image for container ``foo``.
+
+.. code-block:: sh
+
+    # lxc-create --name foo --template none
+
+Verify that ``/var/lib/lxc/foo/config`` has a content like
+
+.. code-block:: sh
+   :emphasize-lines: 3
+
+   lxc.include = /usr/share/lxc/config/debian.common.conf
+   lxc.arch = x86_64
+   lxc.rootfs = /var/lib/lxc/foo/rootfs
+   lxc.rootfs.backend = dir
+   lxc.utsname = foo
+   lxc.network.type = $yours
+
+Next create rootfs location, in this example it is a directory.
+
+.. code-block:: sh
+
+   # mkdir /var/lib/lxc/foo/rootfs
+
+Putting the *image* in place.
+
+.. code-block:: sh
+
+   # xzcat ./ourtarball.tar.xz | ( cd /var/lib/lxc/foo/rootfs && tar x )
+
+Now you can
+
+.. code-block:: sh
+
+   # lxc-start --name foo
+   # lxc-attach --name foo
diff --git a/bootstrapvz/providers/lxc/__init__.py b/bootstrapvz/providers/lxc/__init__.py
new file mode 100644
index 0000000..c166f85
--- /dev/null
+++ b/bootstrapvz/providers/lxc/__init__.py
@@ -0,0 +1,38 @@
+from bootstrapvz.common import task_groups
+from bootstrapvz.common.tasks import apt, folder, filesystem
+from bootstrapvz.common.tools import rel_path
+import tasks.commands
+import tasks.image
+
+
+def validate_manifest(data, validator, error):
+    schema_path = rel_path(__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,
+                    filesystem.RemoveMountTable,
+                    folder.Delete,
+                    ])
+    taskset.update(task_groups.get_network_group(manifest))
+    taskset.update(task_groups.get_apt_group(manifest))
+    taskset.update(task_groups.get_locale_group(manifest))
+    taskset.update(task_groups.security_group)
+    taskset.update(task_groups.cleanup_group)
+
+    # Let the autostart of daemons by apt remain disabled
+    taskset.discard(apt.EnableDaemonAutostart)
+
+    taskset.update([tasks.commands.AddRequiredCommands,
+                    tasks.image.CreateTarBall,
+                    ])
+    if 'appliance_info' in manifest.provider:
+        taskset.add(tasks.image.GetInstalledSize)
+        taskset.add(tasks.image.AddApplianceInfo)
+
+
+def resolve_rollback_tasks(taskset, manifest, completed, counter_task):
+    taskset.update(task_groups.get_standard_rollback_tasks(completed))
diff --git a/bootstrapvz/providers/lxc/manifest-schema.yml b/bootstrapvz/providers/lxc/manifest-schema.yml
new file mode 100644
index 0000000..e820a24
--- /dev/null
+++ b/bootstrapvz/providers/lxc/manifest-schema.yml
@@ -0,0 +1,50 @@
+---
+$schema: http://json-schema.org/draft-04/schema#
+title: LinuX Container manifest
+type: object
+properties:
+  provider:
+    type: object
+    properties:
+      tarball:
+        type: string
+      appliance_info:
+        type: object
+        properties:
+          description:
+            type: string
+          long_description:
+            type: string
+          maintainer:
+            type: string
+          section:
+            type: string
+            enum:
+              - system
+              - turnkey
+              - restricted
+              - public
+          patternProperties:
+            ^.+$: {type: string}
+        required: [description,section,maintainer]
+        addtionalProperties: true
+    required: [tarball]
+  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]
diff --git a/bootstrapvz/providers/lxc/tasks/__init__.py b/bootstrapvz/providers/lxc/tasks/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/bootstrapvz/providers/lxc/tasks/commands.py b/bootstrapvz/providers/lxc/tasks/commands.py
new file mode 100644
index 0000000..26c44a6
--- /dev/null
+++ b/bootstrapvz/providers/lxc/tasks/commands.py
@@ -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 LXC'
+    phase = phases.validation
+    successors = [host.CheckExternalCommands]
+
+    @classmethod
+    def run(cls, info):
+        None
diff --git a/bootstrapvz/providers/lxc/tasks/image.py b/bootstrapvz/providers/lxc/tasks/image.py
new file mode 100644
index 0000000..1587092
--- /dev/null
+++ b/bootstrapvz/providers/lxc/tasks/image.py
@@ -0,0 +1,99 @@
+from bootstrapvz.base import Task
+from bootstrapvz.common import phases
+from bootstrapvz.common.tools import log_check_call
+
+
+class CreateTarBall(Task):
+    description = 'Creating .tar.xz LXC tarball (It is compressing what takes so long)'
+    phase = phases.image_registration
+
+    @classmethod
+    def run(cls, info):
+        from pipes import quote
+        tar_cmd = ['tar', '--create', '--numeric-owner',
+                   '--xz', '--file', info.manifest.provider['tarball'].format(**info.manifest_vars),
+                   '--directory', info.volume.path, '.']
+        # del tar_cmd[tar_cmd.index('--xz')]  # DEBUG no compress during DEVELOPMENT
+        cmd = ' '.join(map(quote, tar_cmd))
+        log_check_call([cmd], shell=True)
+
+
+class AddApplianceInfo(Task):
+    description = 'Adding Proxmox appliance information'
+    phase = phases.image_registration
+    successors = [CreateTarBall]
+
+    @classmethod
+    def run(cls, info):
+        import logging
+        log = logging.getLogger(__name__)
+        ostype_lut = { 'info manifest sytem release': 'ostype',
+                # https://git.proxmox.com/?p=dab.git;a=blob;f=DAB.pm;hb=HEAD#l321
+                'stretch': "debian-9.0",
+                'jessie': "debian-8.0",
+                'wheezy': "debian-7.0",
+                'squeeze': "debian-6.0",
+                'lenny': "debian-5.0",
+                'etch': "debian-4.0",
+                'hardy': "ubuntu-8.04",
+                'intrepid': "ubuntu-8.10",
+                'jaunty': "ubuntu-9.04",
+                'precise': "ubuntu-12.04",
+                'trusty': "ubuntu-14.04",
+                'vivid': "ubuntu-15.04",
+                'wily': "ubuntu-15.10",
+                'xenial': "ubuntu-16.04",
+                'yakkety': "ubuntu-16.10",
+                'zesty': "ubuntu-17.04",
+                'artful': "ubuntu-17.10",
+                }
+        if info.manifest.system['release'] in ostype_lut:
+            ostype = ostype_lut[info.manifest.system['release']]
+        else:
+            ostype = 'not_in_look_up_table_of_image_builder_bootstrap-vz'
+            # _might_ cause trouble
+            # but tests in december 2017 with release 'sid' and 'unstable'
+            # with proxmox 5.1 didn't show any trouble
+        applianceinfo = """Name: %s
+Version: %s
+Type: lxc
+OS: %s
+Section: %s
+Maintainer: %s
+Architecture: %s
+Installed-Size: %s
+"""    % (info.manifest.name.format(**info.manifest_vars),
+          info.manifest.system['release'],
+          ostype,
+          info.manifest.provider['appliance_info']['section'],
+          info.manifest.provider['appliance_info']['maintainer'],
+          info.manifest.system['architecture'],
+          info._lxc['instasize'].split()[0],
+          )
+        if 'infopage' in info.manifest.provider['appliance_info']:
+            applianceinfo += "Infopage: %s\n" % info.manifest.provider['appliance_info']['infopage']
+        if 'manageurl' in info.manifest.provider['appliance_info']:
+            applianceinfo += "ManageUrl: %s\n" % info.manifest.provider['appliance_info']['manageurl']
+        if 'certified' in info.manifest.provider['appliance_info']:
+            applianceinfo += "Certified: %s\n" % info.manifest.provider['appliance_info']['certified']
+        applianceinfo += "Description: %s\n" % info.manifest.provider['appliance_info']['description'].format(**info.manifest_vars)
+        if 'long_description' in info.manifest.provider['appliance_info']:
+            for l in info.manifest.provider['appliance_info']['long_description'].split('\n'):
+                applianceinfo += " " + l.format(**info.manifest_vars) + '\n'
+        log.debug(applianceinfo[0:-3])
+        appinfl = open(info.volume.path + '/etc/appliance.info', 'w')
+        appinfl.write(applianceinfo)
+        appinfl.close()
+
+
+class GetInstalledSize(Task):
+    description = 'Getting installed size'
+    phase = phases.image_registration
+    successors = [AddApplianceInfo]
+
+    @classmethod
+    def run(cls, info):
+        from pipes import quote
+        du_cmd = ['du', '-sm', info.volume.path]
+        cmd = ' '.join(map(quote, du_cmd))
+        [info._lxc['instasize']] = log_check_call([cmd], shell=True)
diff --git a/manifests/examples/lxc/builder.yml b/manifests/examples/lxc/builder.yml
new file mode 100644
index 0000000..e35e269
--- /dev/null
+++ b/manifests/examples/lxc/builder.yml
@@ -0,0 +1,53 @@
+#
+# builder
+# See long_description below for more information
+#
+---
+name: debian-{system.release}-{system.architecture}-builder
+provider:
+  name: lxc
+  tarball: /var/lib/vz/template/cache/debian-builder-{system.release}.tar.xz
+  appliance_info:
+    description: Debian builder {system.release} {system.architecture}
+    long_description: |
+      Debian {system.release} template for Proxmox VE Container
+      with the build essential packages
+      and other debian developer tools
+      .
+      Plus SSH server
+    section: public
+    maintainer: You and me <we@example.com>
+    # optional fields
+    infopage: http://www.example.com/template/info
+    manageurl: https://skipper.example.com/theo
+    certified: by us
+bootstrapper:
+  workspace: /target
+system:
+  release: sid
+  architecture: amd64
+  bootloader: none
+  charmap: UTF-8
+  locale: en_US
+  timezone: UTC
+packages:
+  install:
+    - build-essential
+    - devscripts
+    - vim
+    - openssh-server
+volume:
+  backing: folder
+  partitions:
+    type: none
+    root:
+      filesystem: ext4
+      size: 1GiB
+plugins:
+  unattended_upgrades:
+    # days between running 'apt-get update'
+    update_interval: 1
+    # days between running 'apt-get upgrade --download-only'
+    download_interval: 1
+    # days between installing any security upgrades
+    upgrade_interval: 1
diff --git a/manifests/examples/lxc/stretch-minimized.yml b/manifests/examples/lxc/stretch-minimized.yml
new file mode 100644
index 0000000..06b98b2
--- /dev/null
+++ b/manifests/examples/lxc/stretch-minimized.yml
@@ -0,0 +1,36 @@
+---
+name: debian-{system.release}-{system.architecture}
+provider:
+  name: lxc
+  tarball: ./debian-{system.release}.tar.xz
+bootstrapper:
+  workspace: /target
+  variant: minbase
+system:
+  release: stretch
+  architecture: amd64
+  bootloader: none
+  charmap: UTF-8
+  locale: en_US
+  timezone: UTC
+packages:
+  install:
+    - inetutils-ping
+    - iproute2
+volume:
+  backing: folder
+  partitions:
+    type: none
+    root:
+      filesystem: ext4
+      size: 1GiB
+plugins:
+  minimize_size:
+    apt:
+      autoclean: true
+      languages: [none]
+      gzip_indexes: true
+      autoremove_suggests: true
+    dpkg:
+      locales: []
+      exclude_docs: true
-- 
2.11.0


Reply to: