You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
5.7 KiB
173 lines
5.7 KiB
#!/usr/bin/env python2
|
|
# Copyright 2015 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import collections
|
|
import json
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
from contextlib import contextmanager
|
|
|
|
import common
|
|
from autotest_lib.client.bin import utils
|
|
from autotest_lib.site_utils.lxc import config as lxc_config
|
|
from autotest_lib.site_utils.lxc import utils as lxc_utils
|
|
|
|
class DeployConfigTest(unittest.TestCase):
|
|
"""Test DeployConfigManager.
|
|
"""
|
|
|
|
def testValidate(self):
|
|
"""Test ssp_deploy_config.json can be validated.
|
|
"""
|
|
global_deploy_config_file = os.path.join(
|
|
common.autotest_dir, lxc_config.SSP_DEPLOY_CONFIG_FILE)
|
|
with open(global_deploy_config_file) as f:
|
|
deploy_configs = json.load(f)
|
|
for config in deploy_configs:
|
|
if 'append' in config:
|
|
lxc_config.DeployConfigManager.validate(config)
|
|
elif 'mount' in config:
|
|
# validate_mount checks that the path exists, so we can't call
|
|
# it from tests.
|
|
pass
|
|
else:
|
|
self.fail('Non-deploy/mount config %s' % config)
|
|
|
|
|
|
def testPreStart(self):
|
|
"""Verifies that pre-start works correctly.
|
|
Checks that mounts are correctly created in the container.
|
|
"""
|
|
with lxc_utils.TempDir() as tmpdir:
|
|
config = [
|
|
{
|
|
'mount': True,
|
|
'source': tempfile.mkdtemp(dir=tmpdir),
|
|
'target': '/target0',
|
|
'readonly': True,
|
|
'force_create': False
|
|
},
|
|
{
|
|
'mount': True,
|
|
'source': tempfile.mkdtemp(dir=tmpdir),
|
|
'target': '/target1',
|
|
'readonly': False,
|
|
'force_create': False
|
|
},
|
|
]
|
|
with ConfigFile(config) as test_cfg, MockContainer() as container:
|
|
manager = lxc_config.DeployConfigManager(container, test_cfg)
|
|
manager.deploy_pre_start()
|
|
self.assertEqual(len(config), len(container.mounts))
|
|
for c in config:
|
|
self.assertTrue(container.has_mount(c))
|
|
|
|
|
|
def testPreStartWithCreate(self):
|
|
"""Verifies that pre-start creates mounted dirs.
|
|
|
|
Checks that missing mount points are created when force_create is
|
|
enabled.
|
|
"""
|
|
with lxc_utils.TempDir() as tmpdir:
|
|
src_dir = os.path.join(tmpdir, 'foobar')
|
|
config = [{
|
|
'mount': True,
|
|
'source': src_dir,
|
|
'target': '/target0',
|
|
'readonly': True,
|
|
'force_create': True
|
|
}]
|
|
with ConfigFile(config) as test_cfg, MockContainer() as container:
|
|
manager = lxc_config.DeployConfigManager(container, test_cfg)
|
|
# Pre-condition: the path doesn't exist.
|
|
self.assertFalse(lxc_utils.path_exists(src_dir))
|
|
|
|
# After calling deploy_pre_start, the path should exist and the
|
|
# mount should be created in the container.
|
|
manager.deploy_pre_start()
|
|
self.assertTrue(lxc_utils.path_exists(src_dir))
|
|
self.assertEqual(len(config), len(container.mounts))
|
|
for c in config:
|
|
self.assertTrue(container.has_mount(c))
|
|
|
|
|
|
class _MockContainer(object):
|
|
"""A test mock for the container class.
|
|
|
|
Don't instantiate this directly, use the MockContainer context manager
|
|
defined below.
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.rootfs = tempfile.mkdtemp()
|
|
self.mounts = []
|
|
self.MountConfig = collections.namedtuple(
|
|
'MountConfig', ['source', 'destination', 'readonly'])
|
|
|
|
|
|
def cleanup(self):
|
|
"""Clean up tmp dirs created by the container."""
|
|
# DeployConfigManager uses sudo to create some directories in the
|
|
# container, so it's necessary to use sudo to clean up.
|
|
utils.run('sudo rm -rf %s' % self.rootfs)
|
|
|
|
|
|
def mount_dir(self, src, dst, ro):
|
|
"""Stub implementation of mount_dir.
|
|
|
|
Records calls for later verification.
|
|
|
|
@param src: Mount source dir.
|
|
@param dst: Mount destination dir.
|
|
@param ro: Read-only flag.
|
|
"""
|
|
self.mounts.append(self.MountConfig(src, dst, ro))
|
|
|
|
|
|
def has_mount(self, config):
|
|
"""Verifies whether an earlier call was made to mount_dir.
|
|
|
|
@param config: The config object to verify.
|
|
|
|
@return True if an earlier call was made to mount_dir that matches the
|
|
given mount configuration; False otherwise.
|
|
"""
|
|
mount = self.MountConfig(config['source'],
|
|
config['target'],
|
|
config['readonly'])
|
|
return mount in self.mounts
|
|
|
|
|
|
@contextmanager
|
|
def MockContainer():
|
|
"""Context manager for creating a _MockContainer for testing."""
|
|
container = _MockContainer()
|
|
try:
|
|
yield container
|
|
finally:
|
|
container.cleanup()
|
|
|
|
|
|
@contextmanager
|
|
def ConfigFile(config):
|
|
"""Context manager for creating a config file.
|
|
|
|
The given configs are translated into json and pushed into a temporary file
|
|
that the DeployConfigManager can read.
|
|
|
|
@param config: A list of config objects. Each config object is a dictionary
|
|
which conforms to the format described in config.py.
|
|
"""
|
|
with tempfile.NamedTemporaryFile() as tmp:
|
|
json.dump(config, tmp)
|
|
tmp.flush()
|
|
yield tmp.name
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|