Use stevedore for plugin config of block device

This patch introduces stevedore plugin mechanism for use
with the block device layer.  This makes it possible that
other projects pass in their own block device plugins.

Change-Id: Id3ea56aaf75f5a20a4e1b6ac2a68adb12c56b574
Signed-off-by: Andreas Florath <andreas@florath.net>
This commit is contained in:
Andreas Florath 2017-03-17 18:10:04 +00:00
parent f128d08cf0
commit 57c9e0bb41
6 changed files with 66 additions and 20 deletions

View File

@ -15,13 +15,12 @@
import codecs import codecs
from diskimage_builder.block_device.blockdevicesetupexception \ from diskimage_builder.block_device.blockdevicesetupexception \
import 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 from diskimage_builder.graph.digraph import Digraph
import json import json
import logging import logging
import os import os
import shutil import shutil
from stevedore import extension
import sys import sys
import yaml import yaml
@ -85,13 +84,6 @@ class BlockDevice(object):
# type: ext4 # type: ext4
# mount_point: / # 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, def __init__(self, block_device_config, build_dir,
default_image_size, default_image_dir): default_image_size, default_image_dir):
logger.debug("Creating BlockDevice object") logger.debug("Creating BlockDevice object")
@ -109,6 +101,9 @@ class BlockDevice(object):
"states/block-device") "states/block-device")
self.state_json_file_name \ self.state_json_file_name \
= os.path.join(self.state_dir, "state.json") = 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): def write_state(self, result):
logger.debug("Write state [%s]" % self.state_json_file_name) 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 # As the first step the configured objects are created
# (if it exists) # (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] " logger.error("Configured top level element [%s] "
"does not exists." % cfg_obj_name) "does not exists." % cfg_obj_name)
return 1 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) cfg_obj_val, default_config)
# At this point it is only possible to add the nodes: # At this point it is only possible to add the nodes:
# adding the edges needs all nodes first. # adding the edges needs all nodes first.

View File

@ -14,6 +14,7 @@
from diskimage_builder.block_device.blockdevicesetupexception \ from diskimage_builder.block_device.blockdevicesetupexception \
import 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.block_device.utils import parse_abs_size_spec
from diskimage_builder.graph.digraph import Digraph from diskimage_builder.graph.digraph import Digraph
import logging import logging
@ -24,15 +25,13 @@ import subprocess
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class LocalLoop(Digraph.Node): class LocalLoop(NodePluginBase):
"""Level0: Local loop image device handling. """Level0: Local loop image device handling.
This class handles local loop devices that can be used This class handles local loop devices that can be used
for VM image installation. for VM image installation.
""" """
type_string = "local_loop"
def __init__(self, config, default_config): def __init__(self, config, default_config):
logger.debug("Creating LocalLoop object; config [%s] " logger.debug("Creating LocalLoop object; config [%s] "
"default_config [%s]" % (config, default_config)) "default_config [%s]" % (config, default_config))
@ -50,9 +49,6 @@ class LocalLoop(Digraph.Node):
Digraph.Node.__init__(self, self.name) Digraph.Node.__init__(self, self.name)
self.filename = os.path.join(self.image_dir, self.name + ".raw") 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): def insert_edges(self, dg):
"""Because this is created without base, there are no edges.""" """Because this is created without base, there are no edges."""
pass pass

View File

@ -16,6 +16,7 @@ import collections
from diskimage_builder.block_device.blockdevicesetupexception \ from diskimage_builder.block_device.blockdevicesetupexception \
import BlockDeviceSetupException import BlockDeviceSetupException
from diskimage_builder.block_device.level1.mbr import MBR 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_abs_size_spec
from diskimage_builder.block_device.utils import parse_rel_size_spec from diskimage_builder.block_device.utils import parse_rel_size_spec
from diskimage_builder.graph.digraph import Digraph from diskimage_builder.graph.digraph import Digraph
@ -67,9 +68,7 @@ class Partition(Digraph.Node):
pass pass
class Partitioning(object): class Partitioning(PluginBase):
type_string = "partitioning"
flag_boot = 1 flag_boot = 1
flag_primary = 2 flag_primary = 2

View File

@ -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)

View File

@ -6,3 +6,4 @@ pbr>=2.0.0 # Apache-2.0
PyYAML>=3.10.0 # MIT PyYAML>=3.10.0 # MIT
flake8<2.6.0,>=2.5.4 # MIT flake8<2.6.0,>=2.5.4 # MIT
six>=1.9.0 # MIT six>=1.9.0 # MIT
stevedore>=1.20.0 # Apache-2.0

View File

@ -56,3 +56,7 @@ console_scripts =
disk-image-create = diskimage_builder.disk_image_create:main disk-image-create = diskimage_builder.disk_image_create:main
ramdisk-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 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