# 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
[docs]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
[docs] 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
[docs] 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
[docs] 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]
[docs] 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()
[docs] 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()
[docs] 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")
[docs] 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)
[docs] 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")
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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")
[docs] 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")
[docs] 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)
[docs] 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)
[docs] 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")
[docs] 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)
[docs] 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")
[docs] 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")
[docs] 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")
[docs] 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")
[docs] 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)
[docs] 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()
[docs] 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)
[docs] 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()
[docs] 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()
[docs] 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()
[docs] 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()
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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()
[docs] 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)
[docs] 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()
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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")
[docs] 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")
[docs] 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