summaryrefslogtreecommitdiff
path: root/cxmanage_api/fabric.py
diff options
context:
space:
mode:
Diffstat (limited to 'cxmanage_api/fabric.py')
-rw-r--r--cxmanage_api/fabric.py904
1 files changed, 904 insertions, 0 deletions
diff --git a/cxmanage_api/fabric.py b/cxmanage_api/fabric.py
new file mode 100644
index 0000000..34f435e
--- /dev/null
+++ b/cxmanage_api/fabric.py
@@ -0,0 +1,904 @@
+# Copyright (c) 2012, 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.tasks import DEFAULT_TASK_QUEUE
+from cxmanage_api.tftp import InternalTftp
+from cxmanage_api.node import Node as NODE
+from cxmanage_api.cx_exceptions import CommandFailedError
+
+
+class Fabric(object):
+ """ The Fabric class provides management of multiple nodes.
+
+ >>> from cxmanage_api.fabric import Fabric
+ >>> fabric = Fabric('10.20.1.9')
+
+ :param ip_address: The ip_address of ANY known node for the Fabric.
+ :type ip_address: string
+ :param username: The login username credential. [Default admin]
+ :type username: string
+ :param password: The login password credential. [Default admin]
+ :type password: string
+ :param tftp: Tftp server to facilitate IPMI command responses.
+ :type tftp: `Tftp <tftp.html>`_
+ :param task_queue: TaskQueue to use for sending commands.
+ :type task_queue: `TaskQueue <tasks.html#cxmanage_api.tasks.TaskQueue>`_
+ :param verbose: Flag to turn on verbose output (cmd/response).
+ :type verbose: boolean
+ :param node: Node type, for dependency integration.
+ :type node: `Node <node.html>`_
+ """
+
+ def __init__(self, ip_address, username="admin", password="admin",
+ tftp=None, ecme_tftp_port=5001, task_queue=None,
+ verbose=False, node=None):
+ """Default constructor for the Fabric class."""
+ self.ip_address = ip_address
+ self.username = username
+ self.password = password
+ self._tftp = tftp
+ self.ecme_tftp_port = ecme_tftp_port
+ self.task_queue = task_queue
+ self.verbose = verbose
+ self.node = node
+
+ self._nodes = {}
+
+ if (not self.node):
+ self.node = NODE
+
+ if (not self.task_queue):
+ self.task_queue = DEFAULT_TASK_QUEUE
+
+ if (not self._tftp):
+ self._tftp = InternalTftp()
+
+ def __eq__(self, other):
+ """__eq__() override."""
+ return (isinstance(other, Fabric) and self.nodes == other.nodes)
+
+ def __hash__(self):
+ """__hash__() override."""
+ return hash(tuple(self.nodes.iteritems()))
+
+ def __str__(self):
+ """__str__() override."""
+ return 'Fabric Node 0: %s (%d nodes)' % (self.nodes[0].ip_address,
+ len(self.nodes))
+
+ @property
+ def tftp(self):
+ """Returns the tftp server for this Fabric.
+
+ >>> fabric.tftp
+ <cxmanage_api.tftp.InternalTftp object at 0x7f5ebbd20b10>
+
+ :return: The tftp server.
+ :rtype: `Tftp <tftp.html>`_
+
+ """
+ return self._tftp
+
+ @tftp.setter
+ def tftp(self, value):
+ """ Set the TFTP server for this fabric (and all nodes) """
+ self._tftp = value
+
+ if not self._nodes:
+ return
+
+ for node in self.nodes.values():
+ node.tftp = value
+
+ @property
+ def nodes(self):
+ """List of nodes in this fabric.
+
+ >>> fabric.nodes
+ {
+ 0: <cxmanage_api.node.Node object at 0x2052710>,
+ 1: <cxmanage_api.node.Node object at 0x2052790>,
+ 2: <cxmanage_api.node.Node object at 0x2052850>,
+ 3: <cxmanage_api.node.Node object at 0x2052910>
+ }
+
+ .. note::
+ * Fabric nodes are lazily initialized.
+
+ :returns: A mapping of node ids to node objects.
+ :rtype: dictionary
+
+ """
+ if not self._nodes:
+ self._discover_nodes(self.ip_address)
+ return self._nodes
+
+ @property
+ def primary_node(self):
+ """The node to use for fabric config operations.
+
+ Today, this is always node 0.
+
+ >>> fabric.primary_node
+ <cxmanage_api.node.Node object at 0x210d790>
+
+ :return: Node object for primary node
+ :rtype: Node object
+ """
+ return self.nodes[0]
+
+ def get_mac_addresses(self):
+ """Gets MAC addresses from all nodes.
+
+ >>> fabric.get_mac_addresses()
+ {
+ 0: ['fc:2f:40:3b:ec:40', 'fc:2f:40:3b:ec:41', 'fc:2f:40:3b:ec:42'],
+ 1: ['fc:2f:40:91:dc:40', 'fc:2f:40:91:dc:41', 'fc:2f:40:91:dc:42'],
+ 2: ['fc:2f:40:ab:f7:14', 'fc:2f:40:ab:f7:15', 'fc:2f:40:ab:f7:16'],
+ 3: ['fc:2f:40:88:b3:6c', 'fc:2f:40:88:b3:6d', 'fc:2f:40:88:b3:6e']
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :return: The MAC addresses for each node.
+ :rtype: dictionary
+
+ """
+ return self.primary_node.get_fabric_macaddrs()
+
+ def get_uplink_info(self):
+ """Gets the fabric uplink info.
+
+ >>> fabric.get_uplink_info()
+ {
+ 0: {0: 0, 1: 0, 2: 0}
+ 1: {0: 0, 1: 0, 2: 0}
+ 2: {0: 0, 1: 0, 2: 0}
+ 3: {0: 0, 1: 0, 2: 0}
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :return: The uplink info for each node.
+ :rtype: dictionary
+
+ """
+ return self.primary_node.get_fabric_uplink_info()
+
+ def get_power(self, async=False):
+ """Returns the power status for all nodes.
+
+ >>> fabric.get_power()
+ {0: False, 1: False, 2: False, 3: False}
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (for cmd status, etc.).
+ :type async: boolean
+
+ :return: The power status of each node.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_power")
+
+ def set_power(self, mode, async=False):
+ """Send an IPMI power command to all nodes.
+
+ >>> # On ...
+ >>> fabric.set_power(mode='on')
+ >>> # Off ...
+ >>> fabric.set_power(mode='off')
+ >>> # Sanity check ...
+ >>> fabric.get_power()
+ {0: False, 1: False, 2: False, 3: False}
+
+ :param mode: Mode to set the power to (for all nodes).
+ :type mode: string
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ self._run_on_all_nodes(async, "set_power", mode)
+
+ def get_power_policy(self, async=False):
+ """Gets the power policy from all nodes.
+
+ >>> fabric.get_power_policy()
+ {0: 'always-on', 1: 'always-on', 2: 'always-on', 3: 'always-on'}
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :return: The power policy for all nodes on this fabric.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_power_policy")
+
+ def set_power_policy(self, state, async=False):
+ """Sets the power policy on all nodes.
+
+ >>> fabric.set_power_policy(state='always-off')
+ >>> # Check to see if it took ...
+ >>> fabric.get_power_policy()
+ {0: 'always-off', 1: 'always-off', 2: 'always-off', 3: 'always-off'}
+
+ :param state: State to set the power policy to for all nodes.
+ :type state: string
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ self._run_on_all_nodes(async, "set_power_policy", state)
+
+ def mc_reset(self, wait=False, async=False):
+ """Resets the management controller on all nodes.
+
+ >>> fabric.mc_reset()
+
+ :param wait: Wait for the nodes to come back up.
+ :type wait: boolean
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ self._run_on_all_nodes(async, "mc_reset", wait)
+
+ def get_sensors(self, search="", async=False):
+ """Gets sensors from all nodes.
+
+ >>> fabric.get_sensors()
+ {
+ 0: {
+ 'DRAM VDD Current' : <pyipmi.sdr.AnalogSdr object at 0x1a1eb50>,
+ 'DRAM VDD Voltage' : <pyipmi.sdr.AnalogSdr object at 0x1a1ef10>,
+ 'MP Temp 0' : <pyipmi.sdr.AnalogSdr object at 0x1a1ec90>,
+ 'Node Power' : <pyipmi.sdr.AnalogSdr object at 0x1a1ed90>,
+ 'TOP Temp 0' : <pyipmi.sdr.AnalogSdr object at 0x1a1ecd0>,
+ 'TOP Temp 1' : <pyipmi.sdr.AnalogSdr object at 0x1a1ed50>,
+ 'TOP Temp 2' : <pyipmi.sdr.AnalogSdr object at 0x1a1edd0>,
+ 'Temp 0' : <pyipmi.sdr.AnalogSdr object at 0x1a1ead0>,
+ 'Temp 1' : <pyipmi.sdr.AnalogSdr object at 0x1a1ebd0>,
+ 'Temp 2' : <pyipmi.sdr.AnalogSdr object at 0x1a1ec10>,
+ 'Temp 3' : <pyipmi.sdr.AnalogSdr object at 0x1a1ec50>,
+ 'V09 Current' : <pyipmi.sdr.AnalogSdr object at 0x1a1ef90>,
+ 'V09 Voltage' : <pyipmi.sdr.AnalogSdr object at 0x1a1ee90>,
+ 'V18 Current' : <pyipmi.sdr.AnalogSdr object at 0x1a1ef50>,
+ 'V18 Voltage' : <pyipmi.sdr.AnalogSdr object at 0x1a1ee50>,
+ 'VCORE Current' : <pyipmi.sdr.AnalogSdr object at 0x1a1efd0>,
+ 'VCORE Power' : <pyipmi.sdr.AnalogSdr object at 0x1a1ee10>,
+ 'VCORE Voltage' : <pyipmi.sdr.AnalogSdr object at 0x1a1eed0>
+ },
+ #
+ # Output trimmed for brevity ... The output would be the same
+ # (format) for the remaining 3 ECMEs on this system.
+ #
+ },
+
+ .. note::
+ * Output condensed for brevity.
+ * If the name parameter is not specified, all sensors are returned.
+
+ :param name: Name of the sensor to get. (for all nodes)
+ :type name: string
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ return self._run_on_all_nodes(async, "get_sensors", search)
+
+ def get_firmware_info(self, async=False):
+ """Gets the firmware info from all nodes.
+
+ >>> fabric.get_firmware_info()
+ {
+ 0: [<pyipmi.fw.FWInfo object at 0x2808110>, ...],
+ 1: [<pyipmi.fw.FWInfo object at 0x28080d0>, ...],
+ 2: [<pyipmi.fw.FWInfo object at 0x2808090>, ...],
+ 3: [<pyipmi.fw.FWInfo object at 0x7f35540660d0>, ...]
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :return: THe firmware info for all nodes.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_firmware_info")
+
+ def get_firmware_info_dict(self, async=False):
+ """Gets the firmware info from all nodes.
+
+ >>> fabric.get_firmware_info_dict()
+ {0:
+ [
+ #
+ # Each dictionary (in order) in this list represents the
+ # corresponding partition information
+ #
+ {# Partition 0
+ 'daddr' : '20029000',
+ 'flags' : 'fffffffd',
+ 'in_use' : 'Unknown',
+ 'offset' : '00000000',
+ 'partition' : '00',
+ 'priority' : '0000000c',
+ 'size' : '00005000',
+ 'type' : '02 (S2_ELF)',
+ 'version' : 'v0.9.1'
+ },
+ # Partitions 1 - 17
+ ],
+ #
+ # Output trimmed for brevity ... The remaining Nodes in the Fabric
+ # would display all the partition format in the same manner.
+ #
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :return: The firmware info for all nodes.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_firmware_info_dict")
+
+ def is_updatable(self, package, partition_arg="INACTIVE", priority=None,
+ async=False):
+ """Checks to see if all nodes can be updated with this fw package.
+
+ >>> fabric.is_updatable(package=fwpkg)
+ {0: True, 1: True, 2: True, 3: True}
+
+ :param package: Firmware package to test for updating.
+ :type package: `FirmwarePackage <firmware_package.html>`_
+ :param partition: Partition to test for updating.
+ :type partition: string
+ :param priority: SIMG Header priority.
+ :type priority: integer
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :return: Whether or not a node can be updated with the specified
+ firmware package.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "is_updatable", package,
+ partition_arg, priority)
+
+ def update_firmware(self, package, partition_arg="INACTIVE",
+ priority=None, async=False):
+ """Updates the firmware on all nodes.
+
+ >>> fabric.update_firmware(package=fwpkg)
+
+ :param package: Firmware package to update to.
+ :type package: `FirmwarePackage <firmware_package.html>`_
+ :param partition_arg: Which partition to update.
+ :type partition_arg: string
+ :param priority: SIMG header Priority setting.
+ :type priority: integer
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+ """
+ self._run_on_all_nodes(async, "update_firmware", package,
+ partition_arg, priority)
+
+ def config_reset(self, async=False):
+ """Resets the configuration on all nodes to factory defaults.
+
+ >>> fabric.config_reset()
+ {0: None, 1: None, 2: None, 3: None}
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ self._run_on_all_nodes(async, "config_reset")
+
+ def set_boot_order(self, boot_args, async=False):
+ """Sets the boot order on all nodes.
+
+ >>> fabric.set_boot_order(boot_args=['pxe', 'disk'])
+
+ :param boot_args: Boot order list.
+ :type boot_args: list
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ """
+ self._run_on_all_nodes(async, "set_boot_order", boot_args)
+
+ def get_boot_order(self, async=False):
+ """Gets the boot order from all nodes.
+
+ >>> fabric.get_boot_order()
+ {
+ 0: ['disk', 'pxe'],
+ 1: ['disk', 'pxe'],
+ 2: ['disk', 'pxe'],
+ 3: ['disk', 'pxe']
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The boot order of each node on this fabric.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_boot_order")
+
+ def get_versions(self, async=False):
+ """Gets the version info from all nodes.
+
+ >>> fabric.get_versions()
+ {
+ 0: <pyipmi.info.InfoBasicResult object at 0x1f74150>,
+ 1: <pyipmi.info.InfoBasicResult object at 0x1f745d0>,
+ 2: <pyipmi.info.InfoBasicResult object at 0x1f743d0>,
+ 3: <pyipmi.info.InfoBasicResult object at 0x1f74650>
+ }
+
+ .. seealso::
+ `Node.get_versions() <node.html#cxmanage_api.node.Node.get_versions>`_
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Command object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The basic SoC info for all nodes.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_versions")
+
+ def get_versions_dict(self, async=False):
+ """Gets the version info from all nodes.
+
+ >>> fabric.get_versions_dict()
+ {0:
+ {
+ 'a9boot_version' : 'v2012.10.16',
+ 'bootlog_version' : 'v0.9.1-39-g7e10987',
+ 'build_number' : '7E10987C',
+ 'card' : 'EnergyCard X02',
+ 'cdb_version' : 'v0.9.1-39-g7e10987',
+ 'dtb_version' : 'v3.6-rc1_cx_2012.10.02',
+ 'header' : 'Calxeda SoC (0x0096CD)',
+ 'soc_version' : 'v0.9.1',
+ 'stage2_version' : 'v0.9.1',
+ 'timestamp' : '1352911670',
+ 'uboot_version' : 'v2012.07_cx_2012.10.29',
+ 'ubootenv_version' : 'v2012.07_cx_2012.10.29',
+ 'version' : 'ECX-1000-v1.7.1'
+ },
+ #
+ # Output trimmed for brevity ... Each remaining Nodes get_versions
+ # dictionary would be printed.
+ #
+ }
+
+ .. seealso::
+ `Node.get_versions_dict() <node.html#cxmanage_api.node.Node.get_versions_dict>`_
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The basic SoC info for all nodes.
+ :rtype: dictionary or `Task <tasks.html>`__
+
+ """
+ return self._run_on_all_nodes(async, "get_versions_dict")
+
+ def ipmitool_command(self, ipmitool_args, asynchronous=False):
+ """Run an arbitrary IPMItool command on all nodes.
+
+ >>> # Gets eth0's MAC Address for each node ...
+ >>> fabric.ipmitool_command(['cxoem', 'fabric', 'get', 'macaddr',
+ >>> ...'interface', '0'])
+ {
+ 0: 'fc:2f:40:3b:ec:40',
+ 1: 'fc:2f:40:91:dc:40',
+ 2: 'fc:2f:40:ab:f7:14',
+ 3: 'fc:2f:40:88:b3:6c'
+ }
+
+ :param ipmitool_args: Arguments to pass on to the ipmitool command.
+ :type ipmitool_args: list
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: IPMI command response.
+ :rtype: string
+
+ """
+ return self._run_on_all_nodes(asynchronous, "ipmitool_command",
+ ipmitool_args)
+
+ def get_ubootenv(self, async=False):
+ """Gets the u-boot environment from all nodes.
+
+ >>> fabric.get_ubootenv()
+ {
+ 0: <cxmanage_api.ubootenv.UbootEnv instance at 0x7fc2d4058098>,
+ 1: <cxmanage_api.ubootenv.UbootEnv instance at 0x7fc2d4058908>,
+ 2: <cxmanage_api.ubootenv.UbootEnv instance at 0x7fc2d40582d8>,
+ 3: <cxmanage_api.ubootenv.UbootEnv instance at 0x7fc2d40589e0>
+ }
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: UBootEnvironment objects for all nodes.
+ :rtype: dictionary or `Task <command.html>`_
+
+ """
+ return self._run_on_all_nodes(async, "get_ubootenv")
+
+ def get_server_ip(self, interface=None, ipv6=False, user="user1",
+ password="1Password", aggressive=False, async=False):
+ """Get the server IP address from all nodes. The nodes must be powered
+ on for this to work.
+
+ >>> fabric.get_server_ip()
+ {
+ 0: '192.168.100.100',
+ 1: '192.168.100.101',
+ 2: '192.168.100.102',
+ 3: '192.168.100.103'
+ }
+
+ :param interface: Network interface to check (e.g. eth0).
+ :type interface: string
+ :param ipv6: Return an IPv6 address instead of IPv4.
+ :type ipv6: boolean
+ :param user: Linux username.
+ :type user: string
+ :param password: Linux password.
+ :type password: string
+ :param aggressive: Discover the IP aggressively (may power cycle node).
+ :type aggressive: boolean
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :return: Server IP addresses for all nodes..
+ :rtype: dictionary or `Task <command.html>`_
+
+ """
+ return self._run_on_all_nodes(async, "get_server_ip", interface, ipv6,
+ user, password, aggressive)
+
+ def get_ipsrc(self):
+ """Return the ipsrc for the fabric.
+
+ >>> fabric.get_ipsrc()
+ 2
+
+ :return: 1 for static, 2 for DHCP
+ :rtype: integer
+ """
+ return self.primary_node.bmc.fabric_config_get_ip_src()
+
+ def set_ipsrc(self, ipsrc_mode):
+ """Set the ipsrc for the fabric.
+
+ >>> fabric.set_ipsrc(2)
+
+ :param ipsrc_mode: 1 for static, 2 for DHCP
+ :type ipsrc_mode: integer
+ """
+ self.primary_node.bmc.fabric_config_set_ip_src(ipsrc_mode)
+
+ def apply_factory_default_config(self):
+ """Sets the fabric config to factory default
+
+ >>> fabric.apply_factory_default_config()
+ """
+ self.primary_node.bmc.fabric_config_factory_default()
+
+ def get_ipaddr_base(self):
+ """The base IPv4 address for a range of static IP addresses used
+ for the nodes in the fabric
+
+ >>> fabric.get_ipaddr_base()
+ '192.168.100.1'
+
+ :return: The first IP address in the range of static IP addresses
+ :rtype: string
+ """
+ return self.primary_node.bmc.fabric_config_get_ip_addr_base()
+
+ def update_config(self):
+ """Push out updated configuration data for all nodes in the fabric.
+
+ >>> fabric.update_config()
+
+ """
+ self.primary_node.bmc.fabric_config_update_config()
+
+ def get_linkspeed(self):
+ """Get the global linkspeed for the fabric. In the partition world
+ this means the linkspeed for Configuration 0, Partition 0, Profile 0.
+
+ >>> fabric.get_linkspeed()
+ 2.5
+
+ :return: Linkspeed for the fabric.
+ :rtype: float
+
+ """
+ return self.primary_node.bmc.fabric_config_get_linkspeed()
+
+ def set_linkspeed(self, linkspeed):
+ """Set the global linkspeed for the fabric. In the partition world
+ this means the linkspeed for Configuration 0, Partition 0, Profile 0.
+
+ >>> fabric.set_linkspeed(10)
+
+ :param linkspeed: Linkspeed specified in Gbps.
+ :type linkspeed: float
+
+ """
+ self.primary_node.bmc.fabric_config_set_linkspeed(linkspeed)
+
+ def add_macaddr(self, nodeid, iface, macaddr):
+ """Add a new macaddr to a node/interface in the fabric.
+
+ >>> fabric.add_macaddr(3, 1, "66:55:44:33:22:11")
+
+ :param nodeid: Node id to which the macaddr is to be added
+ :type nodeid: integer
+ :param iface: interface on the node to which the macaddr is to be added
+ :type iface: integer
+ :param macaddr: mac address to be added
+ :type macaddr: string
+
+ """
+ self.primary_node.bmc.fabric_add_macaddr(nodeid=nodeid, iface=iface,
+ macaddr=macaddr)
+
+ def rm_macaddr(self, nodeid, iface, macaddr):
+ """Remove a macaddr to a node/interface in the fabric.
+
+ >>> fabric.rm_macaddr(3, 1, "66:55:44:33:22:11")
+
+ :param nodeid: Node id from which the macaddr is to be remove
+ :type nodeid: integer
+ :param iface: interface on the node from which the macaddr is to be removed
+ :type iface: integer
+ :param macaddr: mac address to be removed
+ :type macaddr: string
+
+ """
+ self.primary_node.bmc.fabric_rm_macaddr(nodeid=nodeid, iface=iface,
+ macaddr=macaddr)
+
+ def get_linkspeed_policy(self):
+ """Get the global linkspeed policy for the fabric. In the partition
+ world this means the linkspeed for Configuration 0, Partition 0,
+ Profile 0.
+
+ >>> fabric.get_linkspeed_policy()
+ 1
+
+ :return: Linkspeed Policy for the fabric.
+ :rtype: integer
+
+ """
+ return self.primary_node.bmc.fabric_config_get_linkspeed_policy()
+
+ def set_linkspeed_policy(self, ls_policy):
+ """Set the global linkspeed policy for the fabric. In the partition
+ world this means the linkspeed policy for Configuration 0,
+ Partition 0, Profile 0.
+
+ >>> fabric.set_linkspeed_policy(1)
+
+ :param linkspeed: Linkspeed Policy. 0: Fixed, 1: Topological
+ :type linkspeed: integer
+
+ """
+ self.primary_node.bmc.fabric_config_set_linkspeed_policy(ls_policy)
+
+ def get_link_users_factor(self):
+ """Get the global link users factor for the fabric. In the partition
+ world this means the link users factor for Configuration 0,
+ Partition 0, Profile 0.
+
+ >>> fabric.get_link_users_factor()
+ 1
+
+ :return: Link users factor for the fabric.
+ :rtype: integer
+
+ """
+ return self.primary_node.bmc.fabric_config_get_link_users_factor()
+
+ def set_link_users_factor(self, lu_factor):
+ """Set the global link users factor for the fabric. In the partition
+ world this means the link users factor for Configuration 0,
+ Partition 0, Profile 0.
+
+ >>> fabric.set_link_users_factor(10)
+
+ :param lu_factor: Multiplying factor for topological linkspeeds
+ :type lu_factor: integer
+
+ """
+ self.primary_node.bmc.fabric_config_set_link_users_factor(lu_factor)
+
+ def get_uplink(self, iface=0):
+ """Get the uplink for an interface to xmit a packet out of the cluster.
+
+ >>> fabric.get_uplink(0)
+ 0
+
+ :param iface: The interface for the uplink.
+ :type iface: integer
+
+ :return: The uplink iface is using.
+ :rtype: integer
+
+ """
+ return self.primary_node.bmc.fabric_config_get_uplink(iface=iface)
+
+ def set_uplink(self, uplink=0, iface=0):
+ """Set the uplink for an interface to xmit a packet out of the cluster.
+
+ >>> fabric.set_uplink(0,0)
+
+ :param uplink: The uplink to set.
+ :type uplink: integer
+ :param iface: The interface for the uplink.
+ :type iface: integer
+
+ """
+ self.primary_node.bmc.fabric_config_set_uplink(uplink=uplink,
+ iface=iface)
+
+ def get_link_stats(self, link=0, async=False):
+ """Get the link_stats for each node in the fabric.
+
+ :param link: The link to get stats for (0-4).
+ :type link: integer
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The link_stats for each link on each node.
+ :rtype: dictionary
+
+ """
+ return self._run_on_all_nodes(async, "get_link_stats", link)
+
+ def get_linkmap(self, async=False):
+ """Get the linkmap for each node in the fabric.
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The linkmap for each node.
+ :rtype: dectionary
+
+ """
+ return self._run_on_all_nodes(async, "get_linkmap")
+
+ def get_routing_table(self, async=False):
+ """Get the routing_table for the fabric.
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The routing_table for the fabric.
+ :rtype: dictionary
+
+ """
+ return self._run_on_all_nodes(async, "get_routing_table")
+
+ def get_depth_chart(self, async=False):
+ """Get the depth_chart for the fabric.
+
+ :param async: Flag that determines if the command result (dictionary)
+ is returned or a Task object (can get status, etc.).
+ :type async: boolean
+
+ :returns: The depth_chart for the fabric.
+ :rtype: dictionary
+
+ """
+ return self._run_on_all_nodes(async, "get_depth_chart")
+
+ def _run_on_all_nodes(self, async, name, *args):
+ """Start a command on all nodes."""
+ tasks = {}
+ for node_id, node in self.nodes.iteritems():
+ tasks[node_id] = self.task_queue.put(getattr(node, name), *args)
+
+ if async:
+ return tasks
+ else:
+ results = {}
+ errors = {}
+ for node_id, task in tasks.iteritems():
+ task.join()
+ if task.status == "Completed":
+ results[node_id] = task.result
+ else:
+ errors[node_id] = task.error
+ if errors:
+ raise CommandFailedError(results, errors)
+ return results
+
+ def _discover_nodes(self, ip_address, username="admin", password="admin"):
+ """Gets the nodes of this fabric by pulling IP info from a BMC."""
+ node = self.node(ip_address=ip_address, username=username,
+ password=password, tftp=self.tftp,
+ ecme_tftp_port=self.ecme_tftp_port,
+ verbose=self.verbose)
+ ipinfo = node.get_fabric_ipinfo()
+ for node_id, node_address in ipinfo.iteritems():
+ self._nodes[node_id] = self.node(ip_address=node_address,
+ username=username,
+ password=password,
+ tftp=self.tftp,
+ ecme_tftp_port=self.ecme_tftp_port,
+ verbose=self.verbose)
+ self._nodes[node_id].node_id = node_id
+
+
+# End of file: ./fabric.py