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 \
|
from diskimage_builder.block_device.blockdevicesetupexception \
|
||||||
import BlockDeviceSetupException
|
import BlockDeviceSetupException
|
||||||
from diskimage_builder.block_device.plugin_base import NodePluginBase
|
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.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
|
||||||
@ -31,6 +32,7 @@ class LocalLoop(NodePluginBase):
|
|||||||
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.
|
||||||
"""
|
"""
|
||||||
|
tree_config = TreeConfig("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] "
|
||||||
|
@ -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
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -13,5 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from diskimage_builder.block_device.level1.partitioning import Partitioning
|
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
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.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_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
|
||||||
@ -28,15 +28,50 @@ import subprocess
|
|||||||
logger = logging.getLogger(__name__)
|
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):
|
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)
|
Digraph.Node.__init__(self, name)
|
||||||
|
self.name = name
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.size = size
|
self.size = size
|
||||||
self.ptype = ptype
|
self.ptype = ptype
|
||||||
self.base = base
|
self.base = base
|
||||||
self.partitioning = partitioning
|
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):
|
def get_flags(self):
|
||||||
return self.flags
|
return self.flags
|
||||||
@ -51,6 +86,9 @@ class Partition(Digraph.Node):
|
|||||||
bnode = dg.find(self.base)
|
bnode = dg.find(self.base)
|
||||||
assert bnode is not None
|
assert bnode is not None
|
||||||
dg.create_edge(bnode, self)
|
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):
|
def create(self, result, rollback):
|
||||||
self.partitioning.create(result, rollback)
|
self.partitioning.create(result, rollback)
|
||||||
@ -68,8 +106,34 @@ class Partition(Digraph.Node):
|
|||||||
pass
|
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):
|
class Partitioning(PluginBase):
|
||||||
|
|
||||||
|
tree_config = PartitioningTreeConfig()
|
||||||
|
|
||||||
flag_boot = 1
|
flag_boot = 1
|
||||||
flag_primary = 2
|
flag_primary = 2
|
||||||
|
|
||||||
@ -109,7 +173,9 @@ class Partitioning(PluginBase):
|
|||||||
if 'partitions' not in config:
|
if 'partitions' not in config:
|
||||||
self._config_error("Partitioning config needs 'partitions'")
|
self._config_error("Partitioning config needs 'partitions'")
|
||||||
|
|
||||||
self.partitions = collections.OrderedDict()
|
self.partitions = []
|
||||||
|
prev_partition = None
|
||||||
|
|
||||||
for part_cfg in config['partitions']:
|
for part_cfg in config['partitions']:
|
||||||
if 'name' not in part_cfg:
|
if 'name' not in part_cfg:
|
||||||
self.config_error("Missing 'name' in partition config")
|
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
|
ptype = int(part_cfg['type'], 16) if 'type' in part_cfg else 0x83
|
||||||
|
|
||||||
self.partitions[part_name] \
|
np = Partition(part_name, flags, size, ptype, self.base, self,
|
||||||
= Partition(part_name, flags, size, ptype, self.base, self)
|
prev_partition)
|
||||||
|
self.partitions.append(np)
|
||||||
|
prev_partition = np
|
||||||
logger.debug(part_cfg)
|
logger.debug(part_cfg)
|
||||||
|
|
||||||
def _config_error(self, msg):
|
def _config_error(self, msg):
|
||||||
@ -147,7 +215,8 @@ class Partitioning(PluginBase):
|
|||||||
return fd.tell()
|
return fd.tell()
|
||||||
|
|
||||||
def insert_nodes(self, dg):
|
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)
|
dg.add_node(part)
|
||||||
|
|
||||||
def _exec_sudo(self, cmd):
|
def _exec_sudo(self, cmd):
|
||||||
@ -212,7 +281,8 @@ class Partitioning(PluginBase):
|
|||||||
partition_devices = set()
|
partition_devices = set()
|
||||||
disk_size = self._size_of_block_dev(image_path)
|
disk_size = self._size_of_block_dev(image_path)
|
||||||
with MBR(image_path, disk_size, self.align) as part_impl:
|
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 \
|
part_bootflag = Partitioning.flag_boot \
|
||||||
in part_cfg.get_flags()
|
in part_cfg.get_flags()
|
||||||
part_primary = Partitioning.flag_primary \
|
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