From 76084a9b7e3b7f09aecd404dbb803a3bb6a1d4c4 Mon Sep 17 00:00:00 2001 From: George Kraft Date: Sat, 7 Dec 2013 12:14:23 -0600 Subject: CXMAN-263: Remove the cxmanage_api.dummy package Put the dummies back in cxmanage_api.tests. They kinda go together. --- cxmanage_api/dummy/__init__.py | 36 -- cxmanage_api/dummy/dummy.py | 61 ---- cxmanage_api/dummy/dummy_bmc.py | 565 ------------------------------- cxmanage_api/dummy/dummy_image.py | 38 --- cxmanage_api/dummy/dummy_ip_retriever.py | 52 --- cxmanage_api/dummy/dummy_node.py | 233 ------------- cxmanage_api/dummy/dummy_ubootenv.py | 43 --- cxmanage_api/tests/__init__.py | 37 +- cxmanage_api/tests/dummy.py | 61 ++++ cxmanage_api/tests/dummy_bmc.py | 564 ++++++++++++++++++++++++++++++ cxmanage_api/tests/dummy_image.py | 38 +++ cxmanage_api/tests/dummy_ip_retriever.py | 52 +++ cxmanage_api/tests/dummy_node.py | 232 +++++++++++++ cxmanage_api/tests/dummy_test.py | 2 +- cxmanage_api/tests/dummy_ubootenv.py | 43 +++ cxmanage_api/tests/fabric_test.py | 2 +- cxmanage_api/tests/node_test.py | 2 +- cxmanage_api/tests/utilities.py | 59 ++++ setup.py | 3 +- 19 files changed, 1060 insertions(+), 1063 deletions(-) delete mode 100644 cxmanage_api/dummy/__init__.py delete mode 100644 cxmanage_api/dummy/dummy.py delete mode 100644 cxmanage_api/dummy/dummy_bmc.py delete mode 100644 cxmanage_api/dummy/dummy_image.py delete mode 100644 cxmanage_api/dummy/dummy_ip_retriever.py delete mode 100644 cxmanage_api/dummy/dummy_node.py delete mode 100644 cxmanage_api/dummy/dummy_ubootenv.py create mode 100644 cxmanage_api/tests/dummy.py create mode 100644 cxmanage_api/tests/dummy_bmc.py create mode 100644 cxmanage_api/tests/dummy_image.py create mode 100644 cxmanage_api/tests/dummy_ip_retriever.py create mode 100644 cxmanage_api/tests/dummy_node.py create mode 100644 cxmanage_api/tests/dummy_ubootenv.py create mode 100644 cxmanage_api/tests/utilities.py diff --git a/cxmanage_api/dummy/__init__.py b/cxmanage_api/dummy/__init__.py deleted file mode 100644 index ff8a7ac..0000000 --- a/cxmanage_api/dummy/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -from cxmanage_api.dummy.dummy import Dummy -from cxmanage_api.dummy.dummy_bmc import DummyBMC -from cxmanage_api.dummy.dummy_node import DummyNode, DummyFailNode -from cxmanage_api.dummy.dummy_image import DummyImage -from cxmanage_api.dummy.dummy_ubootenv import DummyUbootEnv -from cxmanage_api.dummy.dummy_ip_retriever import DummyIPRetriever diff --git a/cxmanage_api/dummy/dummy.py b/cxmanage_api/dummy/dummy.py deleted file mode 100644 index 72f04ed..0000000 --- a/cxmanage_api/dummy/dummy.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -from mock import Mock - - -class Dummy(Mock): - """ Dummy class. Children of this class will automatically have their - methods be turned into Mock objects with side effects, allowing us to track - their usage and assert about how they are called. - - They dummy_spec variable gives us a spec for building the Mock object, which - restricts the names of methods that can be called. - - """ - - dummy_spec = None - - def __init__(self): - super(Dummy, self).__init__( - spec=self.dummy_spec - ) - - for name in dir(self): - if not hasattr(Mock, name): - try: - attr = getattr(self, name) - if callable(attr) and not isinstance(attr, Mock): - setattr(self, name, Mock(side_effect=attr)) - except AttributeError: - pass - - def _get_child_mock(self, *args, **kwargs): - return Mock(*args, **kwargs) diff --git a/cxmanage_api/dummy/dummy_bmc.py b/cxmanage_api/dummy/dummy_bmc.py deleted file mode 100644 index d43728a..0000000 --- a/cxmanage_api/dummy/dummy_bmc.py +++ /dev/null @@ -1,565 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -import random -import shutil -import tempfile -from mock import Mock - -from pyipmi import IpmiError -from pyipmi.bmc import LanBMC - -from cxmanage_api.tests import TestSensor -from cxmanage_api import temp_file -from cxmanage_api.simg import create_simg, get_simg_header -from cxmanage_api.tftp import InternalTftp, ExternalTftp -from cxmanage_api.dummy import Dummy - - -# pylint: disable=R0902 -class DummyBMC(Dummy): - """ Dummy BMC for the node tests """ - dummy_spec = LanBMC - - ip_addresses = [ - "192.168.100.%i" % n for n in range(1, 5) - ] - tftp = InternalTftp() - - - GUID_UNIQUE = 0 - - - def __init__(self, **kwargs): - super(DummyBMC, self).__init__() - self.handle = Mock(name="handle") - self.partitions = [ - Partition(0, 3, 0, 393216, in_use=True), # socman - Partition(1, 10, 393216, 196608, in_use=True), # factory cdb - Partition(2, 3, 589824, 393216, in_use=False), # socman - Partition(3, 10, 983040, 196608, in_use=False), # factory cdb - Partition(4, 10, 1179648, 196608, in_use=True), # running cdb - Partition(5, 11, 1376256, 12288), # ubootenv - Partition(6, 11, 1388544, 12288) # ubootenv - ] - self.ipaddr_base = '192.168.100.1' - self.unique_guid = 'FAKEGUID%s' % DummyBMC.GUID_UNIQUE - self.sel = DummyBMC.generate_sel(with_errors=False) - - DummyBMC.GUID_UNIQUE += 1 - - def guid(self): - """Returns the GUID""" - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self, dummybmc): - self.system_guid = dummybmc.unique_guid - self.time_stamp = None - return Result(self) - - def get_chassis_status(self): - """ Get chassis status """ - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.power_on = False - self.power_restore_policy = "always-off" - return Result() - - def sel_elist(self): - """ List SEL. with_errors=True simulates a SEL that contains errors """ - return self.sel - - @staticmethod - def generate_sel(with_errors=False): - """ Generates a SEL table for a Node """ - if (with_errors): - return [ - '1 | 11/20/2013 | 20:26:18 | Memory | Correctable ECC | Asserted', - '2 | 11/20/2013 | 20:26:43 | Processor | IERR | Asserted', - '83 | 11/14/2013 | 18:01:35 | OS Stop/Shutdown OS Stop Reason | ' + - 'Error during system startup | Asserted' - ] - else: - return [ - '88 | 11/14/2013 | 18:02:29 | System Boot Initiated OS Boot ' + - 'Reason | Initiated by power up | Asserted', - '91 | 11/14/2013 | 19:24:25 | System Event BMC Status |', - ] - - def get_firmware_info(self): - """ Get partition and simg info """ - return [x.fwinfo for x in self.partitions] - - def update_firmware(self, filename, partition, image_type, tftp_addr): - """ Download a file from a TFTP server to a given partition. - - Make sure the image type matches. """ - self.partitions[partition].updates += 1 - - localfile = temp_file() - self.tftp.get_file(filename, localfile) - - contents = open(localfile).read() - simg = get_simg_header(contents) - self.partitions[partition].fwinfo.offset = "%8x" % simg.imgoff - self.partitions[partition].fwinfo.size = "%8x" % simg.imglen - self.partitions[partition].fwinfo.priority = "%8x" % simg.priority - self.partitions[partition].fwinfo.daddr = "%8x" % simg.daddr - - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - """Default constructor for the Result class.""" - self.tftp_handle_id = 0 - return Result() - - def retrieve_firmware(self, filename, partition, image_type, tftp_addr): - self.partitions[partition].retrieves += 1 - - # Upload blank image to tftp - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - open("%s/%s" % (work_dir, filename), "w").write(create_simg("")) - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - shutil.rmtree(work_dir) - - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.tftp_handle_id = 0 - return Result() - - def register_firmware_read(self, filename, partition, image_type): - raise IpmiError() - - def register_firmware_write(self, filename, partition, image_type): - raise IpmiError() - - def get_firmware_status(self, handle): - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.status = "Complete" - - del handle - - return Result() - - def check_firmware(self, partition): - self.partitions[partition].checks += 1 - - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.crc32 = 0 - self.error = None - return Result() - - def activate_firmware(self, partition): - self.partitions[partition].activates += 1 - - def sdr_list(self): - """ Get sensor info from the node. """ - power_value = "%f (+/- 0) Watts" % random.uniform(0, 10) - temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50) - sensors = [ - TestSensor("Node Power", power_value), - TestSensor("Board Temp", temp_value) - ] - - return sensors - - def get_info_basic(self): - """ Get basic SoC info from this node """ - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.iana = int("0x0096CD", 16) - self.firmware_version = "ECX-0000-v0.0.0" - self.ecme_version = "v0.0.0" - self.ecme_timestamp = 0 - return Result() - - def get_info_card(self): - # pylint: disable=R0903 - class Result(object): - """Results class.""" - def __init__(self): - self.type = "TestBoard" - self.revision = "0" - return Result() - - node_count = 0 - def fabric_get_node_id(self): - result = DummyBMC.node_count - DummyBMC.node_count += 1 - return result - - def fabric_info_get_link_map(self, filename, tftp_addr=None): - """Upload a link_map file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - link_map = [] - link_map.append('Link 1: Node 2') - link_map.append('Link 3: Node 1') - link_map.append('Link 4: Node 3') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - with open('%s/%s' % (work_dir, filename), 'w') as lm_file: - for lmap in link_map: - lm_file.write(lmap + '\n') - lm_file.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_info_get_routing_table(self, filename, tftp_addr=None): - """Upload a routing_table file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - routing_table = [] - routing_table.append('Node 1: rt - 0.2.0.3.2') - routing_table.append('Node 2: rt - 0.3.0.1.2') - routing_table.append('Node 3: rt - 0.2.0.1.3') - routing_table.append('Node 12: rt - 0.2.0.0.1') - routing_table.append('Node 13: rt - 0.2.0.0.1') - routing_table.append('Node 14: rt - 0.2.0.0.1') - routing_table.append('Node 15: rt - 0.2.0.0.1') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - with open('%s/%s' % (work_dir, filename), 'w') as rt_file: - for rtable in routing_table: - rt_file.write(rtable + '\n') - rt_file.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_info_get_depth_chart(self, filename, tftp_addr=None): - """Upload a depth_chart file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - depth_chart = [] - depth_chart.append( - 'Node 1: Shortest Distance 0 hops via neighbor 0: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 2: Shortest Distance 0 hops via neighbor 0: ' + - 'other hops/neighbors - 1/3' - ) - depth_chart.append( - 'Node 3: Shortest Distance 0 hops via neighbor 0: ' + - 'other hops/neighbors - 1/2' - ) - depth_chart.append( - 'Node 4: Shortest Distance 2 hops via neighbor 6: ' + - 'other hops/neighbors - 3/7' - ) - depth_chart.append( - 'Node 5: Shortest Distance 3 hops via neighbor 4: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 6: Shortest Distance 1 hops via neighbor 2: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 7: Shortest Distance 2 hops via neighbor 6: ' + - 'other hops/neighbors - 3/4' - ) - depth_chart.append( - 'Node 8: Shortest Distance 3 hops via neighbor 10: ' + - 'other hops/neighbors - 4/11' - ) - depth_chart.append( - 'Node 9: Shortest Distance 4 hops via neighbor 8: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 10: Shortest Distance 2 hops via neighbor 6: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 11: Shortest Distance 3 hops via neighbor 10: ' + - 'other hops/neighbors - 4/8' - ) - depth_chart.append( - 'Node 12: Shortest Distance 4 hops via neighbor 14: ' + - 'other hops/neighbors - 5/15' - ) - depth_chart.append( - 'Node 13: Shortest Distance 5 hops via neighbor 12: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 14: Shortest Distance 3 hops via neighbor 10: ' + - 'other hops/neighbors -' - ) - depth_chart.append( - 'Node 15: Shortest Distance 4 hops via neighbor 14: ' + - 'other hops/neighbors - 5/12' - ) - - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - with open('%s/%s' % (work_dir, filename), 'w') as dc_file: - for dchart in depth_chart: - dc_file.write(dchart + '\n') - dc_file.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - # pylint: disable=W0222 - def fabric_get_linkstats(self, filename, tftp_addr=None, - link=None): - """Upload a link_stats file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - link_stats = [] - link_stats.append('Packet Counts for Link %s:' % link) - link_stats.append('Link0 StatspFS_LCn_CFG_0(link) = 0x1030d07f') - link_stats.append('pFS_LCn_CFG_1 = 0x105f') - link_stats.append('pFS_LCn_STATE = 0x1033') - link_stats.append('pFS_LCn_SC_STAT = 0x0') - link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0') - link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0') - link_stats.append('pFS_LCn_BYTE_CNT_0 = 0x0') - link_stats.append('pFS_LCn_BYTE_CNT_1 = 0x0') - link_stats.append('pFS_LCn_CM_TXDATA_0 = 0x82000000') - link_stats.append('pFS_LCn_CM_TXDATA_1 = 0x0') - link_stats.append('pFS_LCn_CM_RXDATA_0 = 0x0') - link_stats.append('pFS_LCn_CM_RXDATA_1 = 0x0') - link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0') - link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0') - link_stats.append('pFS_LCn_RMCSCNT = 0x1428') - link_stats.append('pFS_LCn_RUCSCNT = 0x116') - link_stats.append('pFS_LCn_RERRSCNT = 0x0') - link_stats.append('pFS_LCn_RDRPSCNT = 0xb4') - link_stats.append('pFS_LCn_RPKTSCNT = 0x0') - link_stats.append('pFS_LCn_TPKTSCNT = 0x1') - link_stats.append('pFS_LCn_TDRPSCNT = 0x0') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - with open('%s/%s' % (work_dir, filename), 'w') as ls_file: - for stat in link_stats: - ls_file.write(stat + '\n') - ls_file.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_config_get_ip_info(self, filename, tftp_addr=None): - """ Upload an ipinfo file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - - # Create IP info file - ipinfo = open("%s/%s" % (work_dir, filename), "w") - for i in range(len(self.ip_addresses)): - ipinfo.write("Node %i: %s\n" % (i, self.ip_addresses[i])) - ipinfo.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_config_get_uplink_info(self, filename, tftp_addr=None): - if not(tftp_addr): - raise IpmiError('No tftp address!') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - # Create uplink info file - ulinfo = open("%s/%s" % (work_dir, filename), "w") - for i in range(1, len(self.ip_addresses)): - ulinfo.write("Node %i: eth0 0, eth1 0, mgmt 0\n" % i) - ulinfo.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_config_get_uplink(self, iface): - return 0 - - def fabric_config_get_mac_addresses(self, filename, tftp_addr=None): - """ Upload a macaddrs file from the node to TFTP""" - if not(tftp_addr): - raise IpmiError('No tftp address!') - - work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") - - # Create macaddrs file - macaddrs = open("%s/%s" % (work_dir, filename), "w") - for i in range(len(self.ip_addresses)): - for port in range(3): - macaddr = "00:00:00:00:%x:%x" % (i, port) - macaddrs.write("Node %i, Port %i: %s\n" % (i, port, macaddr)) - macaddrs.close() - - # Upload to tftp - address, port = tftp_addr.split(":") - port = int(port) - tftp = ExternalTftp(address, port) - tftp.put_file("%s/%s" % (work_dir, filename), filename) - - shutil.rmtree(work_dir) - - def fabric_config_get_ip_src(self): - return 2 - - def fabric_config_set_ip_src(self, ipsrc_mode): - self.fabric_ipsrc = ipsrc_mode - - def fabric_config_get_ip_addr_base(self): - """Provide a fake base IP addr""" - return self.ipaddr_base - - def fabric_get_linkspeed(self, link="", actual=""): - return 1 - - def fabric_config_get_linkspeed(self): - return 1 - - def fabric_config_set_linkspeed(self, linkspeed): - self.fabric_linkspeed = linkspeed - - def fabric_config_get_linkspeed_policy(self): - return 1 - - def fabric_config_set_linkspeed_policy(self, ls_policy): - self.fabric_ls_policy = ls_policy - - def fabric_config_get_link_users_factor(self): - return 1 - - def fabric_config_set_link_users_factor(self, lu_factor): - self.fabric_lu_factor = lu_factor - - def fabric_config_get_macaddr_base(self): - return "00:00:00:00:00:00" - - def fabric_config_get_macaddr_mask(self): - return "00:00:00:00:00:00" - - def fabric_get_uplink_info(self): - """Corresponds to Node.get_uplink_info()""" - return 'Node 0: eth0 0, eth1 0, mgmt 0' - - def fabric_get_uplink_speed(self): - """Corresponds to Node.get_uplink_speed()""" - return 1 - - def fru_read(self, fru_number, filename): - with open(filename, "w") as fru_image: - # Writes a fake FRU image with version "0.0" - fru_image.write("x00" * 516 + "0.0" + "x00"*7673) - - def pmic_get_version(self): - return "0" - - -# pylint: disable=R0913, R0903 -class Partition(object): - """Partition class.""" - def __init__(self, partition, type_, offset=0, - size=0, priority=0, daddr=0, in_use=None): - self.updates = 0 - self.retrieves = 0 - self.checks = 0 - self.activates = 0 - self.fwinfo = FWInfoEntry(partition, type_, offset, size, priority, - daddr, in_use) - - -class FWInfoEntry(object): - """ Firmware info for a single partition """ - - def __init__(self, partition, type_, offset=0, size=0, priority=0, daddr=0, - in_use=None): - self.partition = "%2i" % partition - self.type = { - 2: "02 (S2_ELF)", - 3: "03 (SOC_ELF)", - 10: "0a (CDB)", - 11: "0b (UBOOTENV)" - }[type_] - self.offset = "%8x" % offset - self.size = "%8x" % size - self.priority = "%8x" % priority - self.daddr = "%8x" % daddr - self.in_use = {None: "Unknown", True: "1", False: "0"}[in_use] - self.flags = "fffffffd" - self.version = "v0.0.0" diff --git a/cxmanage_api/dummy/dummy_image.py b/cxmanage_api/dummy/dummy_image.py deleted file mode 100644 index 534befa..0000000 --- a/cxmanage_api/dummy/dummy_image.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -# pylint: disable=R0903 -class DummyImage(object): - """Dummy Image class.""" - - def __init__(self, filename, image_type, *args): - self.filename = filename - self.type = image_type - self.args = args diff --git a/cxmanage_api/dummy/dummy_ip_retriever.py b/cxmanage_api/dummy/dummy_ip_retriever.py deleted file mode 100644 index 4767856..0000000 --- a/cxmanage_api/dummy/dummy_ip_retriever.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -from cxmanage_api.cx_exceptions import IPDiscoveryError - - -# pylint: disable=R0903 -class DummyIPRetriever(object): - """ Dummy IP retriever """ - - def __init__(self, ecme_ip, aggressive=False, verbosity=0, **kwargs): - self.executed = False - self.ecme_ip = ecme_ip - self.aggressive = aggressive - self.verbosity = verbosity - for name, value in kwargs.iteritems(): - setattr(self, name, value) - - def run(self): - """ Set the server_ip variable. Raises an error if called more than - once. """ - if self.executed: - raise IPDiscoveryError("DummyIPRetriever.run() was called twice!") - self.executed = True - self.server_ip = "192.168.200.1" diff --git a/cxmanage_api/dummy/dummy_node.py b/cxmanage_api/dummy/dummy_node.py deleted file mode 100644 index 4d4aa3a..0000000 --- a/cxmanage_api/dummy/dummy_node.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -import random - -from cxmanage_api.ubootenv import UbootEnv -from cxmanage_api.tests import TestSensor -from cxmanage_api.dummy import Dummy, DummyBMC -from cxmanage_api.node import Node - - -class DummyNode(Dummy): - """ Dummy node """ - dummy_spec = Node - - ip_addresses = DummyBMC.ip_addresses - - # pylint: disable=W0613 - def __init__(self, ip_address, username="admin", password="admin", - tftp=None, *args, **kwargs): - super(DummyNode, self).__init__() - self.power_state = False - self.ip_address = ip_address - self.tftp = tftp - self.sel = [] - self.bmc = DummyBMC() - # - # For now, we hard code this to 0 ... - # - self._chassis_id = 0 - - @property - def guid(self): - """Returns the node GUID""" - return self.bmc.guid().system_guid - - @property - def chassis_id(self): - """Returns the chasis ID.""" - return self._chassis_id - - def get_sel(self): - """Simulate get_sel()""" - return self.sel - - def get_power(self): - """Simulate get_power(). """ - return self.power_state - - def get_power_policy(self): - """Simulate get_power_policy(). """ - return "always-off" - - def get_sensors(self, name=""): - """Simulate get_sensors(). """ - power_value = "%f (+/- 0) Watts" % random.uniform(0, 10) - temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50) - sensors = [ - TestSensor("Node Power", power_value), - TestSensor("Board Temp", temp_value) - ] - return [s for s in sensors if name.lower() in s.sensor_name.lower()] - - def get_boot_order(self): - """Simulate get_boot_order(). """ - return ["disk", "pxe"] - - def get_pxe_interface(self): - """Simulate get_pxe_interface(). """ - return "eth0" - - def get_versions(self): - """Simulate get_versions(). """ - # pylint: disable=R0902, R0903 - class Result(object): - """Result Class. """ - def __init__(self): - self.header = "Calxeda SoC (0x0096CD)" - self.hardware_version = "TestBoard X00" - self.firmware_version = "v0.0.0" - self.ecme_version = "v0.0.0" - self.ecme_timestamp = "0" - self.a9boot_version = "v0.0.0" - self.uboot_version = "v0.0.0" - self.chip_name = "Unknown" - return Result() - - def ipmitool_command(self, ipmitool_args): - """Simulate ipmitool_command(). """ - return "Dummy output" - - def get_ubootenv(self): - """Simulate get_ubootenv(). """ - ubootenv = UbootEnv() - ubootenv.variables["bootcmd0"] = "run bootcmd_default" - ubootenv.variables["bootcmd_default"] = "run bootcmd_sata" - return ubootenv - - @staticmethod - def get_fabric_ipinfo(): - """Simulates get_fabric_ipinfo(). """ - return {} - - # pylint: disable=R0913 - def get_server_ip(self, interface=None, ipv6=False, user="user1", - password="1Password", aggressive=False): - """Simulate get_server_ip(). """ - return "192.168.200.1" - - def get_fabric_macaddrs(self): - """Simulate get_fabric_macaddrs(). """ - result = {} - for node in range(len(self.ip_addresses)): - result[node] = {} - for port in range(3): - address = "00:00:00:00:%02x:%02x" % (node, port) - result[node][port] = address - return result - - def get_fabric_uplink_info(self): - """Simulate get_fabric_uplink_info(). """ - results = {} - for nid in range(1, len(self.ip_addresses)): - results[nid] = {'eth0': 0, 'eth1': 0, 'mgmt': 0} - return results - - def get_uplink_info(self): - """Simulate get_uplink_info(). """ - return 'Node 0: eth0 0, eth1 0, mgmt 0' - - def get_uplink_speed(self): - """Simulate get_uplink_speed(). """ - return 1 - - def get_link_stats(self, link=0): - """Simulate get_link_stats(). """ - return { - 'FS_LC%s_BYTE_CNT_0' % link: '0x0', - 'FS_LC%s_BYTE_CNT_1' % link: '0x0', - 'FS_LC%s_CFG_0' % link: '0x1030107f', - 'FS_LC%s_CFG_1' % link: '0x104f', - 'FS_LC%s_CM_RXDATA_0' % link: '0x0', - 'FS_LC%s_CM_RXDATA_1' % link: '0x0', - 'FS_LC%s_CM_TXDATA_0' % link: '0x0', - 'FS_LC%s_CM_TXDATA_1' % link: '0x0', - 'FS_LC%s_PKT_CNT_0' % link: '0x0', - 'FS_LC%s_PKT_CNT_1' % link: '0x0', - 'FS_LC%s_RDRPSCNT' % link: '0x0', - 'FS_LC%s_RERRSCNT' % link: '0x0', - 'FS_LC%sRMCSCNT' % link: '0x0', - 'FS_LC%s_RPKTSCNT' % link: '0x0', - 'FS_LC%s_RUCSCNT' % link: '0x0', - 'FS_LC%s_SC_STAT' % link: '0x0', - 'FS_LC%s_STATE' % link: '0x1033', - 'FS_LC%s_TDRPSCNT' % link: '0x0', - 'FS_LC%s_TPKTSCNT' % link: '0x1' - } - - def get_linkmap(self): - """Simulate get_linkmap(). """ - results = {} - for nid in range(0, len(self.ip_addresses)): - results[nid] = {nid: {1: 2, 3: 1, 4: 3}} - return results - - def get_routing_table(self): - """Simulate get_routing_table(). """ - results = {} - for nid in range(0, len(self.ip_addresses)): - results[nid] = {nid: {1: [0, 0, 0, 3, 0], - 2: [0, 3, 0, 0, 2], - 3: [0, 2, 0, 0, 3]}} - return results - - def get_depth_chart(self): - """Simulate get_depth_chart(). """ - results = {} - for nid in range(0, len(self.ip_addresses)): - results[nid] = {nid: {1: {'shortest': (0, 0)}, - 2: {'hops': [(3, 1)], 'shortest': (0, 0)}, - 3: {'hops': [(2, 1)], 'shortest': (0, 0)}}} - return results - - def get_uplink(self, iface): - """Simulate get_uplink(). """ - return 0 - - def get_node_fru_version(self): - """Simulate get_node_fru_version(). """ - return "0.0" - - def get_slot_fru_version(self): - """Simulate get_slot_fru_version(). """ - return "0.0" - - -class DummyFailNode(DummyNode): - """ Dummy node that should fail on some commands """ - - class DummyFailError(Exception): - """Dummy Fail Error class.""" - pass - - def get_power(self): - """Simulate get_power(). """ - raise DummyFailNode.DummyFailError diff --git a/cxmanage_api/dummy/dummy_ubootenv.py b/cxmanage_api/dummy/dummy_ubootenv.py deleted file mode 100644 index a937419..0000000 --- a/cxmanage_api/dummy/dummy_ubootenv.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2012-2013, Calxeda Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Calxeda Inc. nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -# DAMAGE. - -from cxmanage_api.ubootenv import UbootEnv - - -class DummyUbootEnv(UbootEnv): - """UbootEnv info.""" - - def get_boot_order(self): - """Hard coded boot order for testing.""" - return ["disk", "pxe"] - - def set_boot_order(self, boot_args): - """ Do nothing """ - pass diff --git a/cxmanage_api/tests/__init__.py b/cxmanage_api/tests/__init__.py index d8d5307..bf136c0 100644 --- a/cxmanage_api/tests/__init__.py +++ b/cxmanage_api/tests/__init__.py @@ -1,6 +1,3 @@ -"""Calxeda: __init__.py""" - - # Copyright (c) 2012-2013, Calxeda Inc. # # All rights reserved. @@ -31,30 +28,10 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. - -import os -import random -import tempfile - -from cxmanage_api.image import Image - -def random_file(size): - """ Create a random file """ - contents = "".join([chr(random.randint(0, 255)) for _ in range(size)]) - file_, filename = tempfile.mkstemp(prefix='cxmanage_test-') - with os.fdopen(file_, "w") as file_handle: - file_handle.write(contents) - - return filename - -class TestImage(Image): - """TestImage Class.""" - def verify(self): - return True - -# pylint: disable=R0903 -class TestSensor(object): - """ Sensor result from bmc/target """ - def __init__(self, sensor_name, sensor_reading): - self.sensor_name = sensor_name - self.sensor_reading = sensor_reading +from cxmanage_api.tests.utilities import random_file, TestImage, TestSensor +from cxmanage_api.tests.dummy import Dummy +from cxmanage_api.tests.dummy_bmc import DummyBMC +from cxmanage_api.tests.dummy_node import DummyNode, DummyFailNode +from cxmanage_api.tests.dummy_image import DummyImage +from cxmanage_api.tests.dummy_ubootenv import DummyUbootEnv +from cxmanage_api.tests.dummy_ip_retriever import DummyIPRetriever diff --git a/cxmanage_api/tests/dummy.py b/cxmanage_api/tests/dummy.py new file mode 100644 index 0000000..72f04ed --- /dev/null +++ b/cxmanage_api/tests/dummy.py @@ -0,0 +1,61 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +from mock import Mock + + +class Dummy(Mock): + """ Dummy class. Children of this class will automatically have their + methods be turned into Mock objects with side effects, allowing us to track + their usage and assert about how they are called. + + They dummy_spec variable gives us a spec for building the Mock object, which + restricts the names of methods that can be called. + + """ + + dummy_spec = None + + def __init__(self): + super(Dummy, self).__init__( + spec=self.dummy_spec + ) + + for name in dir(self): + if not hasattr(Mock, name): + try: + attr = getattr(self, name) + if callable(attr) and not isinstance(attr, Mock): + setattr(self, name, Mock(side_effect=attr)) + except AttributeError: + pass + + def _get_child_mock(self, *args, **kwargs): + return Mock(*args, **kwargs) diff --git a/cxmanage_api/tests/dummy_bmc.py b/cxmanage_api/tests/dummy_bmc.py new file mode 100644 index 0000000..cc515db --- /dev/null +++ b/cxmanage_api/tests/dummy_bmc.py @@ -0,0 +1,564 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +import random +import shutil +import tempfile +from mock import Mock + +from pyipmi import IpmiError +from pyipmi.bmc import LanBMC + +from cxmanage_api.tests import Dummy, TestSensor +from cxmanage_api import temp_file +from cxmanage_api.simg import create_simg, get_simg_header +from cxmanage_api.tftp import InternalTftp, ExternalTftp + + +# pylint: disable=R0902 +class DummyBMC(Dummy): + """ Dummy BMC for the node tests """ + dummy_spec = LanBMC + + ip_addresses = [ + "192.168.100.%i" % n for n in range(1, 5) + ] + tftp = InternalTftp() + + + GUID_UNIQUE = 0 + + + def __init__(self, **kwargs): + super(DummyBMC, self).__init__() + self.handle = Mock(name="handle") + self.partitions = [ + Partition(0, 3, 0, 393216, in_use=True), # socman + Partition(1, 10, 393216, 196608, in_use=True), # factory cdb + Partition(2, 3, 589824, 393216, in_use=False), # socman + Partition(3, 10, 983040, 196608, in_use=False), # factory cdb + Partition(4, 10, 1179648, 196608, in_use=True), # running cdb + Partition(5, 11, 1376256, 12288), # ubootenv + Partition(6, 11, 1388544, 12288) # ubootenv + ] + self.ipaddr_base = '192.168.100.1' + self.unique_guid = 'FAKEGUID%s' % DummyBMC.GUID_UNIQUE + self.sel = DummyBMC.generate_sel(with_errors=False) + + DummyBMC.GUID_UNIQUE += 1 + + def guid(self): + """Returns the GUID""" + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self, dummybmc): + self.system_guid = dummybmc.unique_guid + self.time_stamp = None + return Result(self) + + def get_chassis_status(self): + """ Get chassis status """ + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.power_on = False + self.power_restore_policy = "always-off" + return Result() + + def sel_elist(self): + """ List SEL. with_errors=True simulates a SEL that contains errors """ + return self.sel + + @staticmethod + def generate_sel(with_errors=False): + """ Generates a SEL table for a Node """ + if (with_errors): + return [ + '1 | 11/20/2013 | 20:26:18 | Memory | Correctable ECC | Asserted', + '2 | 11/20/2013 | 20:26:43 | Processor | IERR | Asserted', + '83 | 11/14/2013 | 18:01:35 | OS Stop/Shutdown OS Stop Reason | ' + + 'Error during system startup | Asserted' + ] + else: + return [ + '88 | 11/14/2013 | 18:02:29 | System Boot Initiated OS Boot ' + + 'Reason | Initiated by power up | Asserted', + '91 | 11/14/2013 | 19:24:25 | System Event BMC Status |', + ] + + def get_firmware_info(self): + """ Get partition and simg info """ + return [x.fwinfo for x in self.partitions] + + def update_firmware(self, filename, partition, image_type, tftp_addr): + """ Download a file from a TFTP server to a given partition. + + Make sure the image type matches. """ + self.partitions[partition].updates += 1 + + localfile = temp_file() + self.tftp.get_file(filename, localfile) + + contents = open(localfile).read() + simg = get_simg_header(contents) + self.partitions[partition].fwinfo.offset = "%8x" % simg.imgoff + self.partitions[partition].fwinfo.size = "%8x" % simg.imglen + self.partitions[partition].fwinfo.priority = "%8x" % simg.priority + self.partitions[partition].fwinfo.daddr = "%8x" % simg.daddr + + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + """Default constructor for the Result class.""" + self.tftp_handle_id = 0 + return Result() + + def retrieve_firmware(self, filename, partition, image_type, tftp_addr): + self.partitions[partition].retrieves += 1 + + # Upload blank image to tftp + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + open("%s/%s" % (work_dir, filename), "w").write(create_simg("")) + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + shutil.rmtree(work_dir) + + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.tftp_handle_id = 0 + return Result() + + def register_firmware_read(self, filename, partition, image_type): + raise IpmiError() + + def register_firmware_write(self, filename, partition, image_type): + raise IpmiError() + + def get_firmware_status(self, handle): + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.status = "Complete" + + del handle + + return Result() + + def check_firmware(self, partition): + self.partitions[partition].checks += 1 + + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.crc32 = 0 + self.error = None + return Result() + + def activate_firmware(self, partition): + self.partitions[partition].activates += 1 + + def sdr_list(self): + """ Get sensor info from the node. """ + power_value = "%f (+/- 0) Watts" % random.uniform(0, 10) + temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50) + sensors = [ + TestSensor("Node Power", power_value), + TestSensor("Board Temp", temp_value) + ] + + return sensors + + def get_info_basic(self): + """ Get basic SoC info from this node """ + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.iana = int("0x0096CD", 16) + self.firmware_version = "ECX-0000-v0.0.0" + self.ecme_version = "v0.0.0" + self.ecme_timestamp = 0 + return Result() + + def get_info_card(self): + # pylint: disable=R0903 + class Result(object): + """Results class.""" + def __init__(self): + self.type = "TestBoard" + self.revision = "0" + return Result() + + node_count = 0 + def fabric_get_node_id(self): + result = DummyBMC.node_count + DummyBMC.node_count += 1 + return result + + def fabric_info_get_link_map(self, filename, tftp_addr=None): + """Upload a link_map file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + link_map = [] + link_map.append('Link 1: Node 2') + link_map.append('Link 3: Node 1') + link_map.append('Link 4: Node 3') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + with open('%s/%s' % (work_dir, filename), 'w') as lm_file: + for lmap in link_map: + lm_file.write(lmap + '\n') + lm_file.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_info_get_routing_table(self, filename, tftp_addr=None): + """Upload a routing_table file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + routing_table = [] + routing_table.append('Node 1: rt - 0.2.0.3.2') + routing_table.append('Node 2: rt - 0.3.0.1.2') + routing_table.append('Node 3: rt - 0.2.0.1.3') + routing_table.append('Node 12: rt - 0.2.0.0.1') + routing_table.append('Node 13: rt - 0.2.0.0.1') + routing_table.append('Node 14: rt - 0.2.0.0.1') + routing_table.append('Node 15: rt - 0.2.0.0.1') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + with open('%s/%s' % (work_dir, filename), 'w') as rt_file: + for rtable in routing_table: + rt_file.write(rtable + '\n') + rt_file.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_info_get_depth_chart(self, filename, tftp_addr=None): + """Upload a depth_chart file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + depth_chart = [] + depth_chart.append( + 'Node 1: Shortest Distance 0 hops via neighbor 0: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 2: Shortest Distance 0 hops via neighbor 0: ' + + 'other hops/neighbors - 1/3' + ) + depth_chart.append( + 'Node 3: Shortest Distance 0 hops via neighbor 0: ' + + 'other hops/neighbors - 1/2' + ) + depth_chart.append( + 'Node 4: Shortest Distance 2 hops via neighbor 6: ' + + 'other hops/neighbors - 3/7' + ) + depth_chart.append( + 'Node 5: Shortest Distance 3 hops via neighbor 4: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 6: Shortest Distance 1 hops via neighbor 2: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 7: Shortest Distance 2 hops via neighbor 6: ' + + 'other hops/neighbors - 3/4' + ) + depth_chart.append( + 'Node 8: Shortest Distance 3 hops via neighbor 10: ' + + 'other hops/neighbors - 4/11' + ) + depth_chart.append( + 'Node 9: Shortest Distance 4 hops via neighbor 8: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 10: Shortest Distance 2 hops via neighbor 6: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 11: Shortest Distance 3 hops via neighbor 10: ' + + 'other hops/neighbors - 4/8' + ) + depth_chart.append( + 'Node 12: Shortest Distance 4 hops via neighbor 14: ' + + 'other hops/neighbors - 5/15' + ) + depth_chart.append( + 'Node 13: Shortest Distance 5 hops via neighbor 12: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 14: Shortest Distance 3 hops via neighbor 10: ' + + 'other hops/neighbors -' + ) + depth_chart.append( + 'Node 15: Shortest Distance 4 hops via neighbor 14: ' + + 'other hops/neighbors - 5/12' + ) + + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + with open('%s/%s' % (work_dir, filename), 'w') as dc_file: + for dchart in depth_chart: + dc_file.write(dchart + '\n') + dc_file.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + # pylint: disable=W0222 + def fabric_get_linkstats(self, filename, tftp_addr=None, + link=None): + """Upload a link_stats file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + link_stats = [] + link_stats.append('Packet Counts for Link %s:' % link) + link_stats.append('Link0 StatspFS_LCn_CFG_0(link) = 0x1030d07f') + link_stats.append('pFS_LCn_CFG_1 = 0x105f') + link_stats.append('pFS_LCn_STATE = 0x1033') + link_stats.append('pFS_LCn_SC_STAT = 0x0') + link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0') + link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0') + link_stats.append('pFS_LCn_BYTE_CNT_0 = 0x0') + link_stats.append('pFS_LCn_BYTE_CNT_1 = 0x0') + link_stats.append('pFS_LCn_CM_TXDATA_0 = 0x82000000') + link_stats.append('pFS_LCn_CM_TXDATA_1 = 0x0') + link_stats.append('pFS_LCn_CM_RXDATA_0 = 0x0') + link_stats.append('pFS_LCn_CM_RXDATA_1 = 0x0') + link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0') + link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0') + link_stats.append('pFS_LCn_RMCSCNT = 0x1428') + link_stats.append('pFS_LCn_RUCSCNT = 0x116') + link_stats.append('pFS_LCn_RERRSCNT = 0x0') + link_stats.append('pFS_LCn_RDRPSCNT = 0xb4') + link_stats.append('pFS_LCn_RPKTSCNT = 0x0') + link_stats.append('pFS_LCn_TPKTSCNT = 0x1') + link_stats.append('pFS_LCn_TDRPSCNT = 0x0') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + with open('%s/%s' % (work_dir, filename), 'w') as ls_file: + for stat in link_stats: + ls_file.write(stat + '\n') + ls_file.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_config_get_ip_info(self, filename, tftp_addr=None): + """ Upload an ipinfo file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + + # Create IP info file + ipinfo = open("%s/%s" % (work_dir, filename), "w") + for i in range(len(self.ip_addresses)): + ipinfo.write("Node %i: %s\n" % (i, self.ip_addresses[i])) + ipinfo.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_config_get_uplink_info(self, filename, tftp_addr=None): + if not(tftp_addr): + raise IpmiError('No tftp address!') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + # Create uplink info file + ulinfo = open("%s/%s" % (work_dir, filename), "w") + for i in range(1, len(self.ip_addresses)): + ulinfo.write("Node %i: eth0 0, eth1 0, mgmt 0\n" % i) + ulinfo.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_config_get_uplink(self, iface): + return 0 + + def fabric_config_get_mac_addresses(self, filename, tftp_addr=None): + """ Upload a macaddrs file from the node to TFTP""" + if not(tftp_addr): + raise IpmiError('No tftp address!') + + work_dir = tempfile.mkdtemp(prefix="cxmanage_test-") + + # Create macaddrs file + macaddrs = open("%s/%s" % (work_dir, filename), "w") + for i in range(len(self.ip_addresses)): + for port in range(3): + macaddr = "00:00:00:00:%x:%x" % (i, port) + macaddrs.write("Node %i, Port %i: %s\n" % (i, port, macaddr)) + macaddrs.close() + + # Upload to tftp + address, port = tftp_addr.split(":") + port = int(port) + tftp = ExternalTftp(address, port) + tftp.put_file("%s/%s" % (work_dir, filename), filename) + + shutil.rmtree(work_dir) + + def fabric_config_get_ip_src(self): + return 2 + + def fabric_config_set_ip_src(self, ipsrc_mode): + self.fabric_ipsrc = ipsrc_mode + + def fabric_config_get_ip_addr_base(self): + """Provide a fake base IP addr""" + return self.ipaddr_base + + def fabric_get_linkspeed(self, link="", actual=""): + return 1 + + def fabric_config_get_linkspeed(self): + return 1 + + def fabric_config_set_linkspeed(self, linkspeed): + self.fabric_linkspeed = linkspeed + + def fabric_config_get_linkspeed_policy(self): + return 1 + + def fabric_config_set_linkspeed_policy(self, ls_policy): + self.fabric_ls_policy = ls_policy + + def fabric_config_get_link_users_factor(self): + return 1 + + def fabric_config_set_link_users_factor(self, lu_factor): + self.fabric_lu_factor = lu_factor + + def fabric_config_get_macaddr_base(self): + return "00:00:00:00:00:00" + + def fabric_config_get_macaddr_mask(self): + return "00:00:00:00:00:00" + + def fabric_get_uplink_info(self): + """Corresponds to Node.get_uplink_info()""" + return 'Node 0: eth0 0, eth1 0, mgmt 0' + + def fabric_get_uplink_speed(self): + """Corresponds to Node.get_uplink_speed()""" + return 1 + + def fru_read(self, fru_number, filename): + with open(filename, "w") as fru_image: + # Writes a fake FRU image with version "0.0" + fru_image.write("x00" * 516 + "0.0" + "x00"*7673) + + def pmic_get_version(self): + return "0" + + +# pylint: disable=R0913, R0903 +class Partition(object): + """Partition class.""" + def __init__(self, partition, type_, offset=0, + size=0, priority=0, daddr=0, in_use=None): + self.updates = 0 + self.retrieves = 0 + self.checks = 0 + self.activates = 0 + self.fwinfo = FWInfoEntry(partition, type_, offset, size, priority, + daddr, in_use) + + +class FWInfoEntry(object): + """ Firmware info for a single partition """ + + def __init__(self, partition, type_, offset=0, size=0, priority=0, daddr=0, + in_use=None): + self.partition = "%2i" % partition + self.type = { + 2: "02 (S2_ELF)", + 3: "03 (SOC_ELF)", + 10: "0a (CDB)", + 11: "0b (UBOOTENV)" + }[type_] + self.offset = "%8x" % offset + self.size = "%8x" % size + self.priority = "%8x" % priority + self.daddr = "%8x" % daddr + self.in_use = {None: "Unknown", True: "1", False: "0"}[in_use] + self.flags = "fffffffd" + self.version = "v0.0.0" diff --git a/cxmanage_api/tests/dummy_image.py b/cxmanage_api/tests/dummy_image.py new file mode 100644 index 0000000..534befa --- /dev/null +++ b/cxmanage_api/tests/dummy_image.py @@ -0,0 +1,38 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +# pylint: disable=R0903 +class DummyImage(object): + """Dummy Image class.""" + + def __init__(self, filename, image_type, *args): + self.filename = filename + self.type = image_type + self.args = args diff --git a/cxmanage_api/tests/dummy_ip_retriever.py b/cxmanage_api/tests/dummy_ip_retriever.py new file mode 100644 index 0000000..4767856 --- /dev/null +++ b/cxmanage_api/tests/dummy_ip_retriever.py @@ -0,0 +1,52 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +from cxmanage_api.cx_exceptions import IPDiscoveryError + + +# pylint: disable=R0903 +class DummyIPRetriever(object): + """ Dummy IP retriever """ + + def __init__(self, ecme_ip, aggressive=False, verbosity=0, **kwargs): + self.executed = False + self.ecme_ip = ecme_ip + self.aggressive = aggressive + self.verbosity = verbosity + for name, value in kwargs.iteritems(): + setattr(self, name, value) + + def run(self): + """ Set the server_ip variable. Raises an error if called more than + once. """ + if self.executed: + raise IPDiscoveryError("DummyIPRetriever.run() was called twice!") + self.executed = True + self.server_ip = "192.168.200.1" diff --git a/cxmanage_api/tests/dummy_node.py b/cxmanage_api/tests/dummy_node.py new file mode 100644 index 0000000..02af2c2 --- /dev/null +++ b/cxmanage_api/tests/dummy_node.py @@ -0,0 +1,232 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +import random + +from cxmanage_api.ubootenv import UbootEnv +from cxmanage_api.tests import Dummy, DummyBMC, TestSensor +from cxmanage_api.node import Node + + +class DummyNode(Dummy): + """ Dummy node """ + dummy_spec = Node + + ip_addresses = DummyBMC.ip_addresses + + # pylint: disable=W0613 + def __init__(self, ip_address, username="admin", password="admin", + tftp=None, *args, **kwargs): + super(DummyNode, self).__init__() + self.power_state = False + self.ip_address = ip_address + self.tftp = tftp + self.sel = [] + self.bmc = DummyBMC() + # + # For now, we hard code this to 0 ... + # + self._chassis_id = 0 + + @property + def guid(self): + """Returns the node GUID""" + return self.bmc.guid().system_guid + + @property + def chassis_id(self): + """Returns the chasis ID.""" + return self._chassis_id + + def get_sel(self): + """Simulate get_sel()""" + return self.sel + + def get_power(self): + """Simulate get_power(). """ + return self.power_state + + def get_power_policy(self): + """Simulate get_power_policy(). """ + return "always-off" + + def get_sensors(self, name=""): + """Simulate get_sensors(). """ + power_value = "%f (+/- 0) Watts" % random.uniform(0, 10) + temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50) + sensors = [ + TestSensor("Node Power", power_value), + TestSensor("Board Temp", temp_value) + ] + return [s for s in sensors if name.lower() in s.sensor_name.lower()] + + def get_boot_order(self): + """Simulate get_boot_order(). """ + return ["disk", "pxe"] + + def get_pxe_interface(self): + """Simulate get_pxe_interface(). """ + return "eth0" + + def get_versions(self): + """Simulate get_versions(). """ + # pylint: disable=R0902, R0903 + class Result(object): + """Result Class. """ + def __init__(self): + self.header = "Calxeda SoC (0x0096CD)" + self.hardware_version = "TestBoard X00" + self.firmware_version = "v0.0.0" + self.ecme_version = "v0.0.0" + self.ecme_timestamp = "0" + self.a9boot_version = "v0.0.0" + self.uboot_version = "v0.0.0" + self.chip_name = "Unknown" + return Result() + + def ipmitool_command(self, ipmitool_args): + """Simulate ipmitool_command(). """ + return "Dummy output" + + def get_ubootenv(self): + """Simulate get_ubootenv(). """ + ubootenv = UbootEnv() + ubootenv.variables["bootcmd0"] = "run bootcmd_default" + ubootenv.variables["bootcmd_default"] = "run bootcmd_sata" + return ubootenv + + @staticmethod + def get_fabric_ipinfo(): + """Simulates get_fabric_ipinfo(). """ + return {} + + # pylint: disable=R0913 + def get_server_ip(self, interface=None, ipv6=False, user="user1", + password="1Password", aggressive=False): + """Simulate get_server_ip(). """ + return "192.168.200.1" + + def get_fabric_macaddrs(self): + """Simulate get_fabric_macaddrs(). """ + result = {} + for node in range(len(self.ip_addresses)): + result[node] = {} + for port in range(3): + address = "00:00:00:00:%02x:%02x" % (node, port) + result[node][port] = address + return result + + def get_fabric_uplink_info(self): + """Simulate get_fabric_uplink_info(). """ + results = {} + for nid in range(1, len(self.ip_addresses)): + results[nid] = {'eth0': 0, 'eth1': 0, 'mgmt': 0} + return results + + def get_uplink_info(self): + """Simulate get_uplink_info(). """ + return 'Node 0: eth0 0, eth1 0, mgmt 0' + + def get_uplink_speed(self): + """Simulate get_uplink_speed(). """ + return 1 + + def get_link_stats(self, link=0): + """Simulate get_link_stats(). """ + return { + 'FS_LC%s_BYTE_CNT_0' % link: '0x0', + 'FS_LC%s_BYTE_CNT_1' % link: '0x0', + 'FS_LC%s_CFG_0' % link: '0x1030107f', + 'FS_LC%s_CFG_1' % link: '0x104f', + 'FS_LC%s_CM_RXDATA_0' % link: '0x0', + 'FS_LC%s_CM_RXDATA_1' % link: '0x0', + 'FS_LC%s_CM_TXDATA_0' % link: '0x0', + 'FS_LC%s_CM_TXDATA_1' % link: '0x0', + 'FS_LC%s_PKT_CNT_0' % link: '0x0', + 'FS_LC%s_PKT_CNT_1' % link: '0x0', + 'FS_LC%s_RDRPSCNT' % link: '0x0', + 'FS_LC%s_RERRSCNT' % link: '0x0', + 'FS_LC%sRMCSCNT' % link: '0x0', + 'FS_LC%s_RPKTSCNT' % link: '0x0', + 'FS_LC%s_RUCSCNT' % link: '0x0', + 'FS_LC%s_SC_STAT' % link: '0x0', + 'FS_LC%s_STATE' % link: '0x1033', + 'FS_LC%s_TDRPSCNT' % link: '0x0', + 'FS_LC%s_TPKTSCNT' % link: '0x1' + } + + def get_linkmap(self): + """Simulate get_linkmap(). """ + results = {} + for nid in range(0, len(self.ip_addresses)): + results[nid] = {nid: {1: 2, 3: 1, 4: 3}} + return results + + def get_routing_table(self): + """Simulate get_routing_table(). """ + results = {} + for nid in range(0, len(self.ip_addresses)): + results[nid] = {nid: {1: [0, 0, 0, 3, 0], + 2: [0, 3, 0, 0, 2], + 3: [0, 2, 0, 0, 3]}} + return results + + def get_depth_chart(self): + """Simulate get_depth_chart(). """ + results = {} + for nid in range(0, len(self.ip_addresses)): + results[nid] = {nid: {1: {'shortest': (0, 0)}, + 2: {'hops': [(3, 1)], 'shortest': (0, 0)}, + 3: {'hops': [(2, 1)], 'shortest': (0, 0)}}} + return results + + def get_uplink(self, iface): + """Simulate get_uplink(). """ + return 0 + + def get_node_fru_version(self): + """Simulate get_node_fru_version(). """ + return "0.0" + + def get_slot_fru_version(self): + """Simulate get_slot_fru_version(). """ + return "0.0" + + +class DummyFailNode(DummyNode): + """ Dummy node that should fail on some commands """ + + class DummyFailError(Exception): + """Dummy Fail Error class.""" + pass + + def get_power(self): + """Simulate get_power(). """ + raise DummyFailNode.DummyFailError diff --git a/cxmanage_api/tests/dummy_test.py b/cxmanage_api/tests/dummy_test.py index c445272..8012ed2 100644 --- a/cxmanage_api/tests/dummy_test.py +++ b/cxmanage_api/tests/dummy_test.py @@ -1,6 +1,6 @@ import unittest from mock import Mock, call -from cxmanage_api.dummy import Dummy +from cxmanage_api.tests import Dummy class DummyTest(unittest.TestCase): diff --git a/cxmanage_api/tests/dummy_ubootenv.py b/cxmanage_api/tests/dummy_ubootenv.py new file mode 100644 index 0000000..a937419 --- /dev/null +++ b/cxmanage_api/tests/dummy_ubootenv.py @@ -0,0 +1,43 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +from cxmanage_api.ubootenv import UbootEnv + + +class DummyUbootEnv(UbootEnv): + """UbootEnv info.""" + + def get_boot_order(self): + """Hard coded boot order for testing.""" + return ["disk", "pxe"] + + def set_boot_order(self, boot_args): + """ Do nothing """ + pass diff --git a/cxmanage_api/tests/fabric_test.py b/cxmanage_api/tests/fabric_test.py index 6008388..3863186 100644 --- a/cxmanage_api/tests/fabric_test.py +++ b/cxmanage_api/tests/fabric_test.py @@ -38,7 +38,7 @@ from cxmanage_api.fabric import Fabric from cxmanage_api.tftp import InternalTftp, ExternalTftp from cxmanage_api.firmware_package import FirmwarePackage from cxmanage_api.cx_exceptions import CommandFailedError -from cxmanage_api.dummy import DummyNode, DummyFailNode +from cxmanage_api.tests import DummyNode, DummyFailNode # pylint: disable=R0904 diff --git a/cxmanage_api/tests/node_test.py b/cxmanage_api/tests/node_test.py index e692e3e..1bbd6bc 100644 --- a/cxmanage_api/tests/node_test.py +++ b/cxmanage_api/tests/node_test.py @@ -37,8 +37,8 @@ import tempfile import unittest from mock import call +from cxmanage_api.tests import DummyBMC, DummyUbootEnv, DummyIPRetriever from cxmanage_api.tests import TestImage, random_file -from cxmanage_api.dummy import DummyBMC, DummyUbootEnv, DummyIPRetriever from cxmanage_api.node import Node from cxmanage_api.firmware_package import FirmwarePackage diff --git a/cxmanage_api/tests/utilities.py b/cxmanage_api/tests/utilities.py new file mode 100644 index 0000000..6a405d7 --- /dev/null +++ b/cxmanage_api/tests/utilities.py @@ -0,0 +1,59 @@ +# Copyright (c) 2012-2013, Calxeda Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Calxeda Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +import os +import random +import tempfile + +from cxmanage_api.image import Image + + +def random_file(size): + """ Create a random file """ + contents = "".join([chr(random.randint(0, 255)) for _ in range(size)]) + file_, filename = tempfile.mkstemp(prefix='cxmanage_test-') + with os.fdopen(file_, "w") as file_handle: + file_handle.write(contents) + + return filename + + +class TestImage(Image): + """TestImage Class.""" + def verify(self): + return True + + +# pylint: disable=R0903 +class TestSensor(object): + """ Sensor result from bmc/target """ + def __init__(self, sensor_name, sensor_reading): + self.sensor_name = sensor_name + self.sensor_reading = sensor_reading diff --git a/setup.py b/setup.py index 358e71a..8d3bc15 100644 --- a/setup.py +++ b/setup.py @@ -49,8 +49,7 @@ setup( 'cxmanage_api', 'cxmanage_api.cli', 'cxmanage_api.cli.commands', - 'cxmanage_api.tests', - 'cxmanage_api.dummy' + 'cxmanage_api.tests' ], scripts=['scripts/cxmanage', 'scripts/sol_tabs', 'scripts/cxmux'], description='Calxeda Management Utility', -- cgit v1.2.1