Added SmartOS datasource and unit tests.
This commit is contained in:
		@@ -37,6 +37,7 @@ CFG_BUILTIN = {
 | 
				
			|||||||
        'MAAS',
 | 
					        'MAAS',
 | 
				
			||||||
        'Ec2',
 | 
					        'Ec2',
 | 
				
			||||||
        'CloudStack',
 | 
					        'CloudStack',
 | 
				
			||||||
 | 
					        'SmartOS',
 | 
				
			||||||
        # At the end to act as a 'catch' when none of the above work...
 | 
					        # At the end to act as a 'catch' when none of the above work...
 | 
				
			||||||
        'None',
 | 
					        'None',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										172
									
								
								cloudinit/sources/DataSourceSmartOS.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								cloudinit/sources/DataSourceSmartOS.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
				
			|||||||
 | 
					# vi: ts=4 expandtab
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Copyright (C) 2013 Canonical Ltd.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Author: Ben Howard <ben.howard@canonical.com>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					#    it under the terms of the GNU General Public License version 3, as
 | 
				
			||||||
 | 
					#    published by the Free Software Foundation.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					#    GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Datasource for provisioning on SmartOS. This works on Joyent
 | 
				
			||||||
 | 
					#        and public/private Clouds using SmartOS.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    SmartOS hosts use a serial console (/dev/ttyS1) on Linux Guests.
 | 
				
			||||||
 | 
					#        The meta-data is transmitted via key/value pairs made by
 | 
				
			||||||
 | 
					#        requests on the console. For example, to get the hostname, you
 | 
				
			||||||
 | 
					#        would send "GET hostname" on /dev/ttyS1.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import os.path
 | 
				
			||||||
 | 
					import serial
 | 
				
			||||||
 | 
					from cloudinit import log as logging
 | 
				
			||||||
 | 
					from cloudinit import sources
 | 
				
			||||||
 | 
					from cloudinit import util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TTY_LOC = '/dev/ttyS1'
 | 
				
			||||||
 | 
					LOG = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataSourceSmartOS(sources.DataSource):
 | 
				
			||||||
 | 
					    def __init__(self, sys_cfg, distro, paths):
 | 
				
			||||||
 | 
					        sources.DataSource.__init__(self, sys_cfg, distro, paths)
 | 
				
			||||||
 | 
					        self.seed_dir = os.path.join(paths.seed_dir, 'sdc')
 | 
				
			||||||
 | 
					        self.seed = None
 | 
				
			||||||
 | 
					        self.is_smartdc = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        root = sources.DataSource.__str__(self)
 | 
				
			||||||
 | 
					        return "%s [seed=%s]" % (root, self.seed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_data(self):
 | 
				
			||||||
 | 
					        md = {}
 | 
				
			||||||
 | 
					        ud = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not os.path.exists(TTY_LOC):
 | 
				
			||||||
 | 
					            LOG.debug("Host does not appear to be on SmartOS")
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        self.seed = TTY_LOC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        system_uuid, system_type = dmi_data()
 | 
				
			||||||
 | 
					        if 'smartdc' not in system_type.lower():
 | 
				
			||||||
 | 
					            LOG.debug("Host is not on SmartOS")
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        self.is_smartdc = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hostname = query_data("hostname", strip=True)
 | 
				
			||||||
 | 
					        if not hostname:
 | 
				
			||||||
 | 
					            hostname = system_uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        md['local-hostname'] = hostname
 | 
				
			||||||
 | 
					        md['instance-id'] = system_uuid
 | 
				
			||||||
 | 
					        md['public-keys'] = query_data("root_authorized_keys", strip=True)
 | 
				
			||||||
 | 
					        ud = query_data("user-script")
 | 
				
			||||||
 | 
					        md['iptables_disable'] = query_data("disable_iptables_flag",
 | 
				
			||||||
 | 
					                                            strip=True)
 | 
				
			||||||
 | 
					        md['motd_sys_info'] = query_data("enable_motd_sys_info", strip=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.metadata = md
 | 
				
			||||||
 | 
					        self.userdata_raw = ud
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_instance_id(self):
 | 
				
			||||||
 | 
					        return self.metadata['instance-id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_serial():
 | 
				
			||||||
 | 
					    """This is replaced in unit testing, allowing us to replace
 | 
				
			||||||
 | 
					        serial.Serial with a mocked class"""
 | 
				
			||||||
 | 
					    return serial.Serial()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def query_data(noun, strip=False):
 | 
				
			||||||
 | 
					    """Makes a request to via the serial console via "GET <NOUN>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        In the response, the first line is the status, while subsequent lines
 | 
				
			||||||
 | 
					        are is the value. A blank line with a "." is used to indicate end of
 | 
				
			||||||
 | 
					        response.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The timeout value of 60 seconds should never be hit. The value
 | 
				
			||||||
 | 
					        is taken from SmartOS own provisioning tools. Since we are reading
 | 
				
			||||||
 | 
					        each line individually up until the single ".", the transfer is
 | 
				
			||||||
 | 
					        usually very fast (i.e. microseconds) to get the response.
 | 
				
			||||||
 | 
					     """
 | 
				
			||||||
 | 
					    if not noun:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ser = get_serial()
 | 
				
			||||||
 | 
					    ser.port = '/dev/ttyS1'
 | 
				
			||||||
 | 
					    ser.open()
 | 
				
			||||||
 | 
					    if not ser.isOpen():
 | 
				
			||||||
 | 
					        LOG.debug("Serial console is not open")
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ser.write("GET %s\n" % noun.rstrip())
 | 
				
			||||||
 | 
					    status = str(ser.readline()).rstrip()
 | 
				
			||||||
 | 
					    response = []
 | 
				
			||||||
 | 
					    eom_found = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if 'SUCCESS' not in status:
 | 
				
			||||||
 | 
					        ser.close()
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while not eom_found:
 | 
				
			||||||
 | 
					        m = ser.readline()
 | 
				
			||||||
 | 
					        if m.rstrip() == ".":
 | 
				
			||||||
 | 
					            eom_found = True
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            response.append(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ser.close()
 | 
				
			||||||
 | 
					    if not strip:
 | 
				
			||||||
 | 
					        return "".join(response)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return "".join(response).rstrip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def dmi_data():
 | 
				
			||||||
 | 
					    sys_uuid, sys_type = None, None
 | 
				
			||||||
 | 
					    dmidecode_path = util.which('dmidecode')
 | 
				
			||||||
 | 
					    if not dmidecode_path:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sys_uuid_cmd = [dmidecode_path, "-s", "system-uuid"]
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        LOG.debug("Getting hostname from dmidecode")
 | 
				
			||||||
 | 
					        (sys_uuid, _err) = util.subp(sys_uuid_cmd)
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        util.logexc(LOG, "Failed to get system UUID", e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sys_type_cmd = [dmidecode_path, "-s", "system-product-name"]
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        LOG.debug("Determining hypervisor product name via dmidecode")
 | 
				
			||||||
 | 
					        (sys_type, _err) = util.subp(sys_type_cmd)
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        util.logexc(LOG, "Failed to get system UUID", e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sys_uuid.lower(), sys_type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Used to match classes to dependencies
 | 
				
			||||||
 | 
					datasources = [
 | 
				
			||||||
 | 
					    (DataSourceSmartOS, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Return a list of data sources that match this set of dependencies
 | 
				
			||||||
 | 
					def get_datasource_list(depends):
 | 
				
			||||||
 | 
					    return sources.list_from_depends(depends, datasources)
 | 
				
			||||||
@@ -1743,3 +1743,21 @@ def get_mount_info(path, log=LOG):
 | 
				
			|||||||
    mountinfo_path = '/proc/%s/mountinfo' % os.getpid()
 | 
					    mountinfo_path = '/proc/%s/mountinfo' % os.getpid()
 | 
				
			||||||
    lines = load_file(mountinfo_path).splitlines()
 | 
					    lines = load_file(mountinfo_path).splitlines()
 | 
				
			||||||
    return parse_mount_info(path, lines, log)
 | 
					    return parse_mount_info(path, lines, log)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def which(program):
 | 
				
			||||||
 | 
					    # Return path of program for execution if found in path
 | 
				
			||||||
 | 
					    def is_exe(fpath):
 | 
				
			||||||
 | 
					        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fpath, fname = os.path.split(program)
 | 
				
			||||||
 | 
					    if fpath:
 | 
				
			||||||
 | 
					        if is_exe(program):
 | 
				
			||||||
 | 
					            return program
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        for path in os.environ["PATH"].split(os.pathsep):
 | 
				
			||||||
 | 
					            path = path.strip('"')
 | 
				
			||||||
 | 
					            exe_file = os.path.join(path, program)
 | 
				
			||||||
 | 
					            if is_exe(exe_file):
 | 
				
			||||||
 | 
					                return exe_file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										191
									
								
								tests/unittests/test_datasource/test_smartos.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								tests/unittests/test_datasource/test_smartos.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					# vi: ts=4 expandtab
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Copyright (C) 2013 Canonical Ltd.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    Author: Ben Howard <ben.howard@canonical.com>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					#    it under the terms of the GNU General Public License version 3, as
 | 
				
			||||||
 | 
					#    published by the Free Software Foundation.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					#    GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   This is a testcase for the SmartOS datasource. It replicates a serial
 | 
				
			||||||
 | 
					#   console and acts like the SmartOS console does in order to validate
 | 
				
			||||||
 | 
					#   return responses.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cloudinit import helpers
 | 
				
			||||||
 | 
					from cloudinit.sources import DataSourceSmartOS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from mocker import MockerTestCase
 | 
				
			||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mock_returns = {
 | 
				
			||||||
 | 
					    'hostname': 'test-host',
 | 
				
			||||||
 | 
					    'root_authorized_keys': 'ssh-rsa AAAAB3Nz...aC1yc2E= keyname',
 | 
				
			||||||
 | 
					    'disable_iptables_flag': False,
 | 
				
			||||||
 | 
					    'enable_motd_sys_info': False,
 | 
				
			||||||
 | 
					    'system_uuid': str(uuid.uuid4()),
 | 
				
			||||||
 | 
					    'smartdc': 'smartdc',
 | 
				
			||||||
 | 
					    'userdata': """
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					/bin/true
 | 
				
			||||||
 | 
					""",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MockSerial(object):
 | 
				
			||||||
 | 
					    """Fake a serial terminal for testing the code that
 | 
				
			||||||
 | 
					        interfaces with the serial"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    port = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.last = None
 | 
				
			||||||
 | 
					        self.last = None
 | 
				
			||||||
 | 
					        self.new = True
 | 
				
			||||||
 | 
					        self.count = 0
 | 
				
			||||||
 | 
					        self.mocked_out = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self):
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isOpen(self):
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, line):
 | 
				
			||||||
 | 
					        line = line.replace('GET ', '')
 | 
				
			||||||
 | 
					        self.last = line.rstrip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        if self.new:
 | 
				
			||||||
 | 
					            self.new = False
 | 
				
			||||||
 | 
					            if self.last in mock_returns:
 | 
				
			||||||
 | 
					                return 'SUCCESS\n'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return 'NOTFOUND %s\n' % self.last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.last in mock_returns:
 | 
				
			||||||
 | 
					            if not self.mocked_out:
 | 
				
			||||||
 | 
					                self.mocked_out = [x for x in self._format_out()]
 | 
				
			||||||
 | 
					                print self.mocked_out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(self.mocked_out) > self.count:
 | 
				
			||||||
 | 
					                self.count += 1
 | 
				
			||||||
 | 
					                return self.mocked_out[self.count - 1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _format_out(self):
 | 
				
			||||||
 | 
					        if self.last in mock_returns:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                for l in mock_returns[self.last].splitlines():
 | 
				
			||||||
 | 
					                    yield "%s\n" % l
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                yield "%s\n" % mock_returns[self.last]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yield '\n'
 | 
				
			||||||
 | 
					            yield '.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestSmartOSDataSource(MockerTestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        # makeDir comes from MockerTestCase
 | 
				
			||||||
 | 
					        self.tmp = self.makeDir()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # patch cloud_dir, so our 'seed_dir' is guaranteed empty
 | 
				
			||||||
 | 
					        self.paths = helpers.Paths({'cloud_dir': self.tmp})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.unapply = []
 | 
				
			||||||
 | 
					        super(TestSmartOSDataSource, self).setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        apply_patches([i for i in reversed(self.unapply)])
 | 
				
			||||||
 | 
					        super(TestSmartOSDataSource, self).tearDown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def apply_patches(self, patches):
 | 
				
			||||||
 | 
					        ret = apply_patches(patches)
 | 
				
			||||||
 | 
					        self.unapply += ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_ds(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_serial():
 | 
				
			||||||
 | 
					            return MockSerial()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _dmi_data():
 | 
				
			||||||
 | 
					            return mock_returns['system_uuid'], 'smartdc'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = {'sys_cfg': {}}
 | 
				
			||||||
 | 
					        mod = DataSourceSmartOS
 | 
				
			||||||
 | 
					        self.apply_patches([(mod, 'get_serial', _get_serial)])
 | 
				
			||||||
 | 
					        self.apply_patches([(mod, 'dmi_data', _dmi_data)])
 | 
				
			||||||
 | 
					        dsrc = mod.DataSourceSmartOS(
 | 
				
			||||||
 | 
					            data.get('sys_cfg', {}), distro=None, paths=self.paths)
 | 
				
			||||||
 | 
					        return dsrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_seed(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals('/dev/ttyS1', dsrc.seed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_issmartdc(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertTrue(dsrc.is_smartdc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_uuid(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals(mock_returns['system_uuid'],
 | 
				
			||||||
 | 
					                          dsrc.metadata['instance-id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_root_keys(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals(mock_returns['root_authorized_keys'],
 | 
				
			||||||
 | 
					                          dsrc.metadata['public-keys'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_hostname(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals(mock_returns['hostname'],
 | 
				
			||||||
 | 
					                          dsrc.metadata['local-hostname'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_disable_iptables_flag(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals(str(mock_returns['disable_iptables_flag']),
 | 
				
			||||||
 | 
					                          dsrc.metadata['iptables_disable'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_motd_sys_info(self):
 | 
				
			||||||
 | 
					        dsrc = self._get_ds()
 | 
				
			||||||
 | 
					        ret = dsrc.get_data()
 | 
				
			||||||
 | 
					        self.assertTrue(ret)
 | 
				
			||||||
 | 
					        self.assertEquals(str(mock_returns['enable_motd_sys_info']),
 | 
				
			||||||
 | 
					                          dsrc.metadata['motd_sys_info'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def apply_patches(patches):
 | 
				
			||||||
 | 
					    ret = []
 | 
				
			||||||
 | 
					    for (ref, name, replace) in patches:
 | 
				
			||||||
 | 
					        if replace is None:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        orig = getattr(ref, name)
 | 
				
			||||||
 | 
					        setattr(ref, name, replace)
 | 
				
			||||||
 | 
					        ret.append((ref, name, orig))
 | 
				
			||||||
 | 
					    return ret
 | 
				
			||||||
		Reference in New Issue
	
	Block a user