3d48a528c1
Block device handling can be somewhat complex - especially when taking things like md, lvm or encryption into account. This patch factors out the creation and deletion of the local loop image device handling into a python library. The main propose of this patch is to implement the needed infrastructure. Based on this, more advanced functions can be added. Example: (advanced) partitioning, LVM, handling different boot scenarios (BIOS, UEFI, ...), possibility of handling multiple images (local loop image, iSCSI, physical hard disk, ...), handling of different filesystems for different partitions / LVs. Change-Id: Ib626b36a00f8a5dc3dbde8df3e2619a2438eaaf1 Signed-off-by: Andreas Florath <andreas@florath.net>
120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
# Copyright 2016 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.
|
|
|
|
from diskimage_builder.block_device.level0 import Level0
|
|
from diskimage_builder.block_device.utils import convert_to_utf8
|
|
import json
|
|
import logging
|
|
import os
|
|
import shutil
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BlockDevice(object):
|
|
|
|
# Currently there is only the need for a first element (which must
|
|
# be a list).
|
|
DefaultConfig = [
|
|
[["local_loop",
|
|
{"name": "rootdisk"}]]]
|
|
# The reason for the complex layout is, that for future layers
|
|
# there is a need to add additional lists, like:
|
|
# DefaultConfig = [
|
|
# [["local_loop",
|
|
# {"name": "rootdisk"}]],
|
|
# [["partitioning",
|
|
# {"rootdisk": {
|
|
# "label": "mbr",
|
|
# "partitions":
|
|
# [{"name": "rd-partition1",
|
|
# "flags": ["boot"],
|
|
# "size": "100%"}]}}]],
|
|
# [["fs",
|
|
# {"rd-partition1": {}}]]
|
|
# ]
|
|
|
|
def __init__(self, block_device_config, build_dir,
|
|
default_image_size, default_image_dir):
|
|
if block_device_config is None:
|
|
self.config = BlockDevice.DefaultConfig
|
|
else:
|
|
self.config = json.loads(block_device_config)
|
|
self.default_config = {
|
|
'image_size': default_image_size,
|
|
'image_dir': default_image_dir}
|
|
self.state_dir = os.path.join(build_dir,
|
|
"states/block-device")
|
|
self.state_json_file_name \
|
|
= os.path.join(self.state_dir, "state.json")
|
|
|
|
def write_state(self, result):
|
|
logger.debug("Write state [%s]" % self.state_json_file_name)
|
|
os.makedirs(self.state_dir)
|
|
with open(self.state_json_file_name, "w") as fd:
|
|
json.dump([self.config, self.default_config, result], fd)
|
|
|
|
def load_state(self):
|
|
with open(self.state_json_file_name, "r") as fd:
|
|
return convert_to_utf8(json.load(fd))
|
|
|
|
def cmd_create(self):
|
|
"""Creates the block device"""
|
|
|
|
logger.info("create() called")
|
|
logger.debug("config [%s]" % self.config)
|
|
lvl0 = Level0(self.config[0], self.default_config, None)
|
|
result = lvl0.create()
|
|
logger.debug("Result level 0 [%s]" % result)
|
|
|
|
# To be compatible with the current implementation, echo the
|
|
# result to stdout.
|
|
print("%s" % result['rootdisk']['device'])
|
|
|
|
self.write_state(result)
|
|
|
|
logger.info("create() finished")
|
|
return 0
|
|
|
|
def cmd_umount(self):
|
|
"""Unmounts the blockdevice and cleanup resources"""
|
|
|
|
logger.info("umount() called")
|
|
try:
|
|
os.stat(self.state_json_file_name)
|
|
except OSError:
|
|
logger.info("State already cleaned - no way to do anything here")
|
|
return 0
|
|
|
|
config, default_config, state = self.load_state()
|
|
logger.debug("Using config [%s]" % config)
|
|
logger.debug("Using default config [%s]" % default_config)
|
|
logger.debug("Using state [%s]" % state)
|
|
|
|
level0 = Level0(config[0], default_config, state)
|
|
result = level0.delete()
|
|
|
|
# If everything finished well, remove the results.
|
|
if result:
|
|
logger.info("Removing temporary dir [%s]" % self.state_dir)
|
|
shutil.rmtree(self.state_dir)
|
|
|
|
# To be compatible with the current implementation, echo the
|
|
# result to stdout.
|
|
print("%s" % state['rootdisk']['image'])
|
|
|
|
logger.info("umount() finished result [%d]" % result)
|
|
return 0 if result else 1
|