Add refactor of tree-like vs graph
Introducing the refactors of the block device to allow a tree-like configuration, and start using it for the partitions level. Based on patch I3600c6a3d663c697b59d91bd3fbb5e408af345e4 Change-Id: I58bb3c256a1dfd100d29266571c333c2d43334f7 Co-Authored-By: Andreas Florath <andreas@florath.net>
This commit is contained in:
parent
91ba21dd6c
commit
08c36e4bf8
@ -15,6 +15,7 @@
|
||||
from diskimage_builder.block_device.blockdevicesetupexception \
|
||||
import BlockDeviceSetupException
|
||||
from diskimage_builder.block_device.plugin_base import NodePluginBase
|
||||
from diskimage_builder.block_device.tree_config import TreeConfig
|
||||
from diskimage_builder.block_device.utils import parse_abs_size_spec
|
||||
from diskimage_builder.graph.digraph import Digraph
|
||||
import logging
|
||||
@ -31,6 +32,7 @@ class LocalLoop(NodePluginBase):
|
||||
This class handles local loop devices that can be used
|
||||
for VM image installation.
|
||||
"""
|
||||
tree_config = TreeConfig("local_loop")
|
||||
|
||||
def __init__(self, config, default_config):
|
||||
logger.debug("Creating LocalLoop object; config [%s] "
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright 2016 Andreas Florath (andreas@florath.net)
|
||||
# Copyright
|
||||
# 2016-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
|
||||
@ -13,5 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from diskimage_builder.block_device.level1.partitioning import Partitioning
|
||||
from diskimage_builder.block_device.level1.partitioning \
|
||||
import PartitioningTreeConfig
|
||||
|
||||
__all__ = [Partitioning]
|
||||
__all__ = [Partitioning, PartitioningTreeConfig]
|
||||
|
@ -12,11 +12,11 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
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.tree_config import TreeConfig
|
||||
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
|
||||
@ -28,15 +28,50 @@ import subprocess
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PartitionTreeConfig(object):
|
||||
|
||||
@staticmethod
|
||||
def config_tree_to_digraph(config_key, config_value, pconfig, dconfig,
|
||||
base_name, plugin_manager):
|
||||
logger.debug("called [%s] [%s] [%s]"
|
||||
% (config_key, config_value, base_name))
|
||||
assert config_key == Partition.type_string
|
||||
|
||||
for partition in config_value:
|
||||
name = partition['name']
|
||||
nconfig = {'name': name}
|
||||
for k, v in partition.items():
|
||||
if k not in plugin_manager:
|
||||
nconfig[k] = v
|
||||
else:
|
||||
plugin_manager[k].plugin \
|
||||
.tree_config.config_tree_to_digraph(
|
||||
k, v, dconfig, name, plugin_manager)
|
||||
pconfig.append(nconfig)
|
||||
|
||||
logger.debug("finished [%s] [%s]" % (nconfig, dconfig))
|
||||
|
||||
|
||||
class Partition(Digraph.Node):
|
||||
|
||||
def __init__(self, name, flags, size, ptype, base, partitioning):
|
||||
type_string = "partitions"
|
||||
tree_config = TreeConfig("partitions")
|
||||
|
||||
def __init__(self, name, flags, size, ptype, base, partitioning,
|
||||
prev_partition):
|
||||
Digraph.Node.__init__(self, name)
|
||||
self.name = name
|
||||
self.flags = flags
|
||||
self.size = size
|
||||
self.ptype = ptype
|
||||
self.base = base
|
||||
self.partitioning = partitioning
|
||||
self.prev_partition = prev_partition
|
||||
|
||||
def __repr__(self):
|
||||
return "<Partition [%s] on [%s] size [%s] prev [%s]>" \
|
||||
% (self.name, self.base, self.size,
|
||||
self.prev_partition.name if self.prev_partition else "UNSET")
|
||||
|
||||
def get_flags(self):
|
||||
return self.flags
|
||||
@ -51,6 +86,9 @@ class Partition(Digraph.Node):
|
||||
bnode = dg.find(self.base)
|
||||
assert bnode is not None
|
||||
dg.create_edge(bnode, self)
|
||||
if self.prev_partition is not None:
|
||||
logger.debug("Insert edge [%s]" % self)
|
||||
dg.create_edge(self.prev_partition, self)
|
||||
|
||||
def create(self, result, rollback):
|
||||
self.partitioning.create(result, rollback)
|
||||
@ -68,8 +106,34 @@ class Partition(Digraph.Node):
|
||||
pass
|
||||
|
||||
|
||||
class PartitioningTreeConfig(object):
|
||||
|
||||
@staticmethod
|
||||
def config_tree_to_digraph(config_key, config_value, dconfig,
|
||||
default_base_name, plugin_manager):
|
||||
logger.debug("called [%s] [%s] [%s]"
|
||||
% (config_key, config_value, default_base_name))
|
||||
assert config_key == "partitioning"
|
||||
base_name = config_value['base'] if 'base' in config_value \
|
||||
else default_base_name
|
||||
nconfig = {'base': base_name}
|
||||
for k, v in config_value.items():
|
||||
if k != 'partitions':
|
||||
nconfig[k] = v
|
||||
else:
|
||||
pconfig = []
|
||||
PartitionTreeConfig.config_tree_to_digraph(
|
||||
k, v, pconfig, dconfig, base_name, plugin_manager)
|
||||
nconfig['partitions'] = pconfig
|
||||
|
||||
dconfig.append({config_key: nconfig})
|
||||
logger.debug("finished new [%s] complete [%s]" % (nconfig, dconfig))
|
||||
|
||||
|
||||
class Partitioning(PluginBase):
|
||||
|
||||
tree_config = PartitioningTreeConfig()
|
||||
|
||||
flag_boot = 1
|
||||
flag_primary = 2
|
||||
|
||||
@ -109,7 +173,9 @@ class Partitioning(PluginBase):
|
||||
if 'partitions' not in config:
|
||||
self._config_error("Partitioning config needs 'partitions'")
|
||||
|
||||
self.partitions = collections.OrderedDict()
|
||||
self.partitions = []
|
||||
prev_partition = None
|
||||
|
||||
for part_cfg in config['partitions']:
|
||||
if 'name' not in part_cfg:
|
||||
self.config_error("Missing 'name' in partition config")
|
||||
@ -133,8 +199,10 @@ class Partitioning(PluginBase):
|
||||
|
||||
ptype = int(part_cfg['type'], 16) if 'type' in part_cfg else 0x83
|
||||
|
||||
self.partitions[part_name] \
|
||||
= Partition(part_name, flags, size, ptype, self.base, self)
|
||||
np = Partition(part_name, flags, size, ptype, self.base, self,
|
||||
prev_partition)
|
||||
self.partitions.append(np)
|
||||
prev_partition = np
|
||||
logger.debug(part_cfg)
|
||||
|
||||
def _config_error(self, msg):
|
||||
@ -147,7 +215,8 @@ class Partitioning(PluginBase):
|
||||
return fd.tell()
|
||||
|
||||
def insert_nodes(self, dg):
|
||||
for _, part in self.partitions.items():
|
||||
for part in self.partitions:
|
||||
logger.debug("Insert node [%s]" % part)
|
||||
dg.add_node(part)
|
||||
|
||||
def _exec_sudo(self, cmd):
|
||||
@ -212,7 +281,8 @@ class Partitioning(PluginBase):
|
||||
partition_devices = set()
|
||||
disk_size = self._size_of_block_dev(image_path)
|
||||
with MBR(image_path, disk_size, self.align) as part_impl:
|
||||
for part_name, part_cfg in self.partitions.items():
|
||||
for part_cfg in self.partitions:
|
||||
part_name = part_cfg.get_name()
|
||||
part_bootflag = Partitioning.flag_boot \
|
||||
in part_cfg.get_flags()
|
||||
part_primary = Partitioning.flag_primary \
|
||||
|
60
diskimage_builder/block_device/tree_config.py
Normal file
60
diskimage_builder/block_device/tree_config.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Copyright 2016-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 logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TreeConfig(object):
|
||||
"""Supports simple tree-like configuration
|
||||
|
||||
When using the new (complete) configuration there is a need to
|
||||
specify the complete digraph of block level configurations. This
|
||||
provides great flexibility for the cost of complex configurations:
|
||||
each and every single element must be completely specified. In
|
||||
many simple use cases the configuration flexibility is not
|
||||
needed.
|
||||
|
||||
With the help of this object the simple to use and short tree-like
|
||||
configuration is converted automatically into the complete digraph
|
||||
configuration which can be used to create the block device
|
||||
elements.
|
||||
"""
|
||||
|
||||
def __init__(self, type_string):
|
||||
self.type_string = type_string
|
||||
|
||||
def config_tree_to_digraph(self, config_key, config_value, dconfig,
|
||||
default_base_name, plugin_manager):
|
||||
logger.debug("called [%s] [%s] [%s]"
|
||||
% (config_key, config_value, default_base_name))
|
||||
base_name = config_value['base'] if 'base' in config_value \
|
||||
else default_base_name
|
||||
name = config_value['name'] \
|
||||
if 'name' in config_value \
|
||||
else "%s_%s" % (config_key, base_name)
|
||||
assert config_key == self.type_string
|
||||
|
||||
nconfig = {'base': base_name, 'name': name}
|
||||
for k, v in config_value.items():
|
||||
if k not in plugin_manager:
|
||||
nconfig[k] = v
|
||||
else:
|
||||
plugin_manager[k].plugin \
|
||||
.tree_config.config_tree_to_digraph(
|
||||
k, v, dconfig, name, plugin_manager)
|
||||
|
||||
dconfig.append({self.type_string: nconfig})
|
||||
logger.debug("finished new [%s] complete [%s]" % (nconfig, dconfig))
|
Loading…
Reference in New Issue
Block a user