diff --git a/diskimage_builder/block_device/blockdevice.py b/diskimage_builder/block_device/blockdevice.py index 897c0d4b..18b5e55e 100644 --- a/diskimage_builder/block_device/blockdevice.py +++ b/diskimage_builder/block_device/blockdevice.py @@ -15,13 +15,12 @@ import codecs from diskimage_builder.block_device.blockdevicesetupexception \ import BlockDeviceSetupException -from diskimage_builder.block_device.level0 import LocalLoop -from diskimage_builder.block_device.level1 import Partitioning from diskimage_builder.graph.digraph import Digraph import json import logging import os import shutil +from stevedore import extension import sys import yaml @@ -85,13 +84,6 @@ class BlockDevice(object): # type: ext4 # mount_point: / - # A dictionary to map sensible names to internal implementation. - cfg_type_map = { - 'local_loop': LocalLoop, - 'partitioning': Partitioning, - 'mkfs': 'not yet implemented', - } - def __init__(self, block_device_config, build_dir, default_image_size, default_image_dir): logger.debug("Creating BlockDevice object") @@ -109,6 +101,9 @@ class BlockDevice(object): "states/block-device") self.state_json_file_name \ = os.path.join(self.state_dir, "state.json") + self.plugin_manager = extension.ExtensionManager( + namespace='diskimage_builder.block_device.plugin', + invoke_on_load=False) def write_state(self, result): logger.debug("Write state [%s]" % self.state_json_file_name) @@ -138,11 +133,11 @@ class BlockDevice(object): # As the first step the configured objects are created # (if it exists) - if cfg_obj_name not in BlockDevice.cfg_type_map: + if cfg_obj_name not in self.plugin_manager: logger.error("Configured top level element [%s] " "does not exists." % cfg_obj_name) return 1 - cfg_obj = BlockDevice.cfg_type_map[cfg_obj_name]( + cfg_obj = self.plugin_manager[cfg_obj_name].plugin( cfg_obj_val, default_config) # At this point it is only possible to add the nodes: # adding the edges needs all nodes first. diff --git a/diskimage_builder/block_device/level0/localloop.py b/diskimage_builder/block_device/level0/localloop.py index 7fd21b3d..dfa543d8 100644 --- a/diskimage_builder/block_device/level0/localloop.py +++ b/diskimage_builder/block_device/level0/localloop.py @@ -14,6 +14,7 @@ from diskimage_builder.block_device.blockdevicesetupexception \ import BlockDeviceSetupException +from diskimage_builder.block_device.plugin_base import NodePluginBase from diskimage_builder.block_device.utils import parse_abs_size_spec from diskimage_builder.graph.digraph import Digraph import logging @@ -24,15 +25,13 @@ import subprocess logger = logging.getLogger(__name__) -class LocalLoop(Digraph.Node): +class LocalLoop(NodePluginBase): """Level0: Local loop image device handling. This class handles local loop devices that can be used for VM image installation. """ - type_string = "local_loop" - def __init__(self, config, default_config): logger.debug("Creating LocalLoop object; config [%s] " "default_config [%s]" % (config, default_config)) @@ -50,9 +49,6 @@ class LocalLoop(Digraph.Node): Digraph.Node.__init__(self, self.name) self.filename = os.path.join(self.image_dir, self.name + ".raw") - def insert_nodes(self, dg): - dg.add_node(self) - def insert_edges(self, dg): """Because this is created without base, there are no edges.""" pass diff --git a/diskimage_builder/block_device/level1/partitioning.py b/diskimage_builder/block_device/level1/partitioning.py index 28f2a688..2d79ddb5 100644 --- a/diskimage_builder/block_device/level1/partitioning.py +++ b/diskimage_builder/block_device/level1/partitioning.py @@ -16,6 +16,7 @@ import collections from diskimage_builder.block_device.blockdevicesetupexception \ import BlockDeviceSetupException from diskimage_builder.block_device.level1.mbr import MBR +from diskimage_builder.block_device.plugin_base import PluginBase from diskimage_builder.block_device.utils import parse_abs_size_spec from diskimage_builder.block_device.utils import parse_rel_size_spec from diskimage_builder.graph.digraph import Digraph @@ -67,9 +68,7 @@ class Partition(Digraph.Node): pass -class Partitioning(object): - - type_string = "partitioning" +class Partitioning(PluginBase): flag_boot = 1 flag_primary = 2 diff --git a/diskimage_builder/block_device/plugin_base.py b/diskimage_builder/block_device/plugin_base.py new file mode 100644 index 00000000..c92ff77c --- /dev/null +++ b/diskimage_builder/block_device/plugin_base.py @@ -0,0 +1,51 @@ +# Copyright 2017 Andreas Florath (andreas@florath.net) +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc +from diskimage_builder.graph.digraph import Digraph +import six + + +@six.add_metaclass(abc.ABCMeta) +class PluginBase(object): + """Abstract base class for block device plugins""" + + def __init__(self, name): + """All plugins must have a name""" + self.name = name + + @abc.abstractmethod + def create(self, state, rollback): + """Create the block device plugin + + :param state: a dictionary to store results for this plugin. + These are used in two scenarios: other plugins + can use this to get information about the + result of the plugin and it can be used in + later runs of dib-block-device for cleaning up. + :type state: dict(str:?) + + :param rollback: a list of python functions that will be + called in reversed order to cleanup if there + occurs an error later within the same + dib-block-device run. + :type rollback: list(function) + """ + + +class NodePluginBase(PluginBase, Digraph.Node): + + def insert_nodes(self, dg): + """Adds self as a node to the given digraph""" + dg.add_node(self) diff --git a/requirements.txt b/requirements.txt index 2f2d1093..6077f0c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ pbr>=2.0.0 # Apache-2.0 PyYAML>=3.10.0 # MIT flake8<2.6.0,>=2.5.4 # MIT six>=1.9.0 # MIT +stevedore>=1.20.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index 5eac8745..6a42eb0c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,3 +56,7 @@ console_scripts = disk-image-create = diskimage_builder.disk_image_create:main ramdisk-image-create = diskimage_builder.disk_image_create:main dib-run-parts = diskimage_builder.dib_run_parts:main + +diskimage_builder.block_device.plugin = + local_loop = diskimage_builder.block_device.level0.localloop:LocalLoop + partitioning = diskimage_builder.block_device.level1.partitioning:Partitioning