Add a simple implementation of element dependency
This adds a new optional file to the root of elements. The file lists dependencies which will be added to the list requested by the user during disk image creation. Change-Id: Id71c3b333563604bbbaf90f9cf40e24fa9738fc8
This commit is contained in:
parent
b4e495f6ef
commit
c8c33e3bb1
@ -23,6 +23,8 @@ What tools are there?
|
|||||||
|
|
||||||
* elements can be found in the top level elements directory.
|
* elements can be found in the top level elements directory.
|
||||||
|
|
||||||
|
* element-info : Extract information about elements.
|
||||||
|
|
||||||
Why?
|
Why?
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -118,6 +120,9 @@ part of the process you need to customise:
|
|||||||
* first-boot.d: Runs inside the image before rc.local. Scripts from here are
|
* first-boot.d: Runs inside the image before rc.local. Scripts from here are
|
||||||
good for doing per-instance configuration based on cloud metadata.
|
good for doing per-instance configuration based on cloud metadata.
|
||||||
|
|
||||||
|
* element-deps : A plain text, newline separated list of elements which will
|
||||||
|
be added to the list of elements built into the image at image creation time.
|
||||||
|
|
||||||
Ramdisk elements support the following files in their element directories:
|
Ramdisk elements support the following files in their element directories:
|
||||||
|
|
||||||
* binary-deps : executables required to be fed into the ramdisk. These need
|
* binary-deps : executables required to be fed into the ramdisk. These need
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRIPTNAME=$(basename $0)
|
SCRIPTNAME=$(basename $0)
|
||||||
|
SCRIPT_HOME=$(dirname $0)
|
||||||
export _LIB=$(dirname $0)/../lib
|
export _LIB=$(dirname $0)/../lib
|
||||||
source $_LIB/die
|
source $_LIB/die
|
||||||
|
|
||||||
@ -58,6 +59,8 @@ source $_LIB/img-defaults
|
|||||||
source $_LIB/common-functions
|
source $_LIB/common-functions
|
||||||
source $_LIB/img-functions
|
source $_LIB/img-functions
|
||||||
|
|
||||||
|
IMAGE_ELEMENT=$($SCRIPT_HOME/element-info --expand-dependencies $IMAGE_ELEMENT)
|
||||||
|
|
||||||
echo "Building elements: $IMAGE_ELEMENT"
|
echo "Building elements: $IMAGE_ELEMENT"
|
||||||
echo "If prompted for sudo, install sudoers.d/img-build-sudoers into /etc/sudoers.d and restart the build."
|
echo "If prompted for sudo, install sudoers.d/img-build-sudoers into /etc/sudoers.d and restart the build."
|
||||||
mkdir -p $IMG_PATH
|
mkdir -p $IMG_PATH
|
||||||
|
1
bin/diskimage_builder
Symbolic link
1
bin/diskimage_builder
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../diskimage_builder
|
23
bin/element-info
Executable file
23
bin/element-info
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from diskimage_builder.elements import main
|
||||||
|
|
||||||
|
|
||||||
|
sys.exit(main(sys.argv))
|
@ -20,6 +20,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRIPTNAME=$(basename $0)
|
SCRIPTNAME=$(basename $0)
|
||||||
|
SCRIPT_HOME=$(dirname $0)
|
||||||
export _DIR=$(dirname $0)
|
export _DIR=$(dirname $0)
|
||||||
export _LIB=${_DIR}/../lib
|
export _LIB=${_DIR}/../lib
|
||||||
source $_LIB/die
|
source $_LIB/die
|
||||||
@ -57,6 +58,8 @@ source $_LIB/ramdisk-defaults
|
|||||||
source $_LIB/common-functions
|
source $_LIB/common-functions
|
||||||
source $_LIB/ramdisk-functions
|
source $_LIB/ramdisk-functions
|
||||||
|
|
||||||
|
RAMDISK_ELEMENT=$($SCRIPT_HOME/element-info --expand-dependencies $RAMDISK_ELEMENT)
|
||||||
|
|
||||||
echo "Building element(s): ${RAMDISK_ELEMENT}"
|
echo "Building element(s): ${RAMDISK_ELEMENT}"
|
||||||
|
|
||||||
echo "Discovering binary dependencies"
|
echo "Discovering binary dependencies"
|
||||||
|
91
diskimage_builder/elements.py
Normal file
91
diskimage_builder/elements.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 argparse
|
||||||
|
from errno import ENOENT
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_elements_dir():
|
||||||
|
if 'ELEMENTS_DIR' not in os.environ:
|
||||||
|
return os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__), '..', 'elements'))
|
||||||
|
return os.environ['ELEMENTS_DIR']
|
||||||
|
|
||||||
|
|
||||||
|
def dependencies(element, elements_dir=None):
|
||||||
|
""" Return the non-transitive list of dependencies for a single element
|
||||||
|
:param user_elements: iterable enumerating elements a user has requested
|
||||||
|
:param elements_dir: the elements dir to read from. If not supplied,
|
||||||
|
inferred by calling get_elements_dir().
|
||||||
|
|
||||||
|
:return: a set just containing all elements that the specified element
|
||||||
|
depends on.
|
||||||
|
"""
|
||||||
|
if elements_dir is None:
|
||||||
|
elements_dir = get_elements_dir()
|
||||||
|
|
||||||
|
element_deps_path = os.path.join(elements_dir, element, 'element-deps')
|
||||||
|
try:
|
||||||
|
with open(element_deps_path) as element_deps:
|
||||||
|
return set([line.strip() for line in element_deps])
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno == 2:
|
||||||
|
return set()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def expand_dependencies(user_elements, elements_dir=None):
|
||||||
|
""" Expand user requested elements using element-deps files.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
:param user_elements: iterable enumerating the elements a user requested
|
||||||
|
:param elements_dir: the elements dir to read from. Passed directly to
|
||||||
|
dependencies()
|
||||||
|
|
||||||
|
:return: a set containing user_elements and all dependent elements
|
||||||
|
including any transitive dependencies.
|
||||||
|
"""
|
||||||
|
final_elements = set(user_elements)
|
||||||
|
check_queue = list(user_elements)
|
||||||
|
|
||||||
|
while check_queue:
|
||||||
|
element = check_queue.pop()
|
||||||
|
deps = dependencies(element, elements_dir)
|
||||||
|
check_queue.extend(deps - final_elements)
|
||||||
|
final_elements.update(deps)
|
||||||
|
|
||||||
|
return final_elements
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('elements', nargs='+',
|
||||||
|
help='elements to inspect')
|
||||||
|
parser.add_argument('--expand-dependencies', '-d', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Print expanded dependencies of all args')
|
||||||
|
|
||||||
|
args = parser.parse_args(argv[1:])
|
||||||
|
|
||||||
|
if args.expand_dependencies:
|
||||||
|
print(' '.join(expand_dependencies(args.elements)))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
sys.stderr.write("ERROR: please choose an option.\n")
|
||||||
|
return -1
|
71
diskimage_builder/test_elementdeps.py
Normal file
71
diskimage_builder/test_elementdeps.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 os
|
||||||
|
|
||||||
|
from testtools import TestCase
|
||||||
|
from fixtures import Fixture, TempDir
|
||||||
|
|
||||||
|
from diskimage_builder.elements import expand_dependencies
|
||||||
|
|
||||||
|
data_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test-elements'))
|
||||||
|
|
||||||
|
def _populate_element(element_dir, element_name, element_deps=[]):
|
||||||
|
element_home = os.path.join(element_dir, element_name)
|
||||||
|
os.mkdir(element_home)
|
||||||
|
deps_path = os.path.join(element_home, 'element-deps')
|
||||||
|
with open(deps_path, 'w') as deps_file:
|
||||||
|
deps_file.write("\n".join(element_deps))
|
||||||
|
|
||||||
|
class TestElementDeps(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestElementDeps, self).setUp()
|
||||||
|
self.element_dir = self.useFixture(TempDir()).path
|
||||||
|
_populate_element(self.element_dir, 'requires-foo', ['foo'])
|
||||||
|
_populate_element(self.element_dir, 'foo')
|
||||||
|
_populate_element(self.element_dir,
|
||||||
|
'requires-requires-foo',
|
||||||
|
['requires-foo'])
|
||||||
|
_populate_element(self.element_dir, 'self', ['self'])
|
||||||
|
_populate_element(self.element_dir, 'circular1', ['circular2'])
|
||||||
|
_populate_element(self.element_dir, 'circular2', ['circular1'])
|
||||||
|
|
||||||
|
def test_non_transitive_deps(self):
|
||||||
|
result = expand_dependencies(['requires-foo'],
|
||||||
|
elements_dir=self.element_dir)
|
||||||
|
self.assertEquals(set(['requires-foo', 'foo']), result)
|
||||||
|
|
||||||
|
def test_transitive_deps(self):
|
||||||
|
result = expand_dependencies(['requires-requires-foo'],
|
||||||
|
elements_dir=self.element_dir)
|
||||||
|
self.assertEquals(set(['requires-requires-foo',
|
||||||
|
'requires-foo',
|
||||||
|
'foo']), result)
|
||||||
|
|
||||||
|
def test_no_deps(self):
|
||||||
|
result = expand_dependencies(['foo'],
|
||||||
|
elements_dir=self.element_dir)
|
||||||
|
self.assertEquals(set(['foo']), result)
|
||||||
|
|
||||||
|
def test_self(self):
|
||||||
|
result = expand_dependencies(['self'],
|
||||||
|
elements_dir=self.element_dir)
|
||||||
|
self.assertEquals(set(['self']), result)
|
||||||
|
|
||||||
|
def test_circular(self):
|
||||||
|
result = expand_dependencies(['circular1'],
|
||||||
|
elements_dir=self.element_dir)
|
||||||
|
self.assertEquals(set(['circular1', 'circular2']), result)
|
Loading…
Reference in New Issue
Block a user