def _set_power_state(self, state):
        """
        Applies the requested power state on the system.
        :param str state: Supported values are On, ForceOff, ForceRestart,
                          PushPowerButton
        :return: :bool True on success else False
        """
        uri = self.client.get_resource_uris('ComputerSystem.')[0]
        # For Rack server, there would ideally be only one item.

        if self.client.type_path.defs.isgen9:
            r = self.client.post(uri['@odata.id'], {'Action': 'Reset',
                                                    'ResetType': state})
        else:
            pr = self.client.get(uri['@odata.id'])

            if pr.status == 200:
                p = pr.dict['Actions']['#ComputerSystem.Reset']['target']
            else:
                _ = 'Unable to gather resource path to perform {}'.format(state)
                logger.debug(_)
                return False

            r = self.client.post(p, {'Action': 'ComputerSystem.Reset',
                                     'ResetType': state})

        e = self.client.get_message(r)
        if e.get('error_code') == 'Success':
            return True
        elif e.get('error_code') == 'InvalidOperationForSystemState':
            # System was in the requested state hence passing it
            logger.info(e.get('error_info'))
            return True

        return False
Example #2
0
    def _validate_and_set_host(self, host):
        """
        Verifies and adds the target information to the body
        :param dict host: Contains
        :return bool: True if the payload is updated with host information
        """
        attrs = ['ipv4', 'user', 'password']

        if not host.get('os'):
            log.debug('Missing required attribute: os')
            return False

        if not set(attrs).issubset(host.keys()):
            m = 'Found attributes: {}'.format(host.keys())
            m += '\nRequired attributes: {}'.format(attrs)
            log.info(m)
            return False

        if host.get('datacenter'):
            if host.get('manager') is None:
                log.info('Missing required attribute: manager')
                return False

        self.body['host'] = deepcopy(host)
        log.debug('Host information found {}'.format(host))
        return True
    def _verify_host(self, host):
        """
        Verifies all the required attributes of the host is available or not
        :param dict host: Key-value pair of host section
        :return bool: True when all exists else False
        """
        attrs = ['ipv4', 'user', 'password']

        if not set(attrs).issubset(host.keys()):
            m = 'Required attributes: {}'.format(attrs)
            m += '\nFound attributes: {}'.format(host.keys())
            log.info(m)
            return False

        self.host = deepcopy(host)

        return True
    def _verify_network_info(net):
        """
        Verify the key-value pairs of the provided network address
        :param net:
        :return:
        """
        if not net.get('dhcp'):
            if net.get('ipv4', None) is None and net.get('ipv6', None) is None:
                log.info('Keys: ipv4 or ipv6 is required')
                return False

        if net.get('vlan'):
            if net.get('vlan') < 0 or net.get('vlan') > 4095:
                log.info('VLAN ID: {} is invalid.'.format(net['vlan']))
                return False

        return True
Example #5
0
    def _get_network_uri(self, name):
        """
        Retrieve the networkUri from OneView based on the argument
        :param str name: Network name
        :return str: Network's URI corresponding to OV
        """
        p = '?&filter="\'name\'==\'{}\'"'.format(name.lower())
        r = self.fusion_api_get_ethernet_networks(param=p)

        if r.get('count') == 0:
            r = self.fusion_api_get_network_set(param=p)
            if r.get('count') == 0:
                log.info('{} not found in OneView'.format(name))
                return None

        if r.get('count') > 1:
            log.info('Found more than one match for {}'.format(name))
            return None

        log.debug('Retrieved the network uri for {}'.format(name))
        return r.get('members')[0]['uri']
Example #6
0
    def configure_network(self, body):
        """
        Calls the appropriate configure network method based on the OS type

        Example:
          @{r}=    RG Configure Networks | <config>

        <config> is a dictionary and the supported key-value pairs are available
        in the respective functions.

        :param dict body: Key-value pairs containing network configuration
        :return list: List of network configuration status
        """
        if not body.get('host'):
            log.info('Target system information is required')
            raise AssertionError('Host information dictionary is missing.')

        t = body.get('host').get('os', None)
        if t is None:
            log.info('Operating System type is required')
            raise AssertionError('Operating system type attribute missing')

        if "redhat" in t.lower() or "red hat" in t.lower() or \
                "rhel" in t.lower():
            return RedHatNetConfig().configure_network(body)
        elif "vmware" in t.lower() or "esx" in t.lower():
            return VMwareNetConfig().configure_network(body)
        else:
            log.info('{} not supported'.format(body['host']['os']))
            raise AssertionError('OS type not supported')
Example #7
0
    def _network_config_generator(self, sp_url, host_info, nets):
        """
        Keyword to generate the required payload for configuring the target
        system networks

        Usage
          ${body}=    Create Payload For OS Networks Configuration |
          ...             <ov_server_profile_url> |
          ...             <host_info> |
          ...             <network_profiles> |

        [Returns]
          A dictionary which would be an input to 'Configure OS Networks'

        :param str sp_url: Target system's OneView server profile URL
        :param dict host_info: Target system's credentials and type
        :param list nets: List of network profiles
        :return:
        """
        sp = self.fusion_api_get_server_profiles(uri=sp_url)

        if sp['status_code'] != 200:
            log.info("Invalid OneView Server Profile URL: {}".format(sp_url))
            return self.body

        if int(sp['type'].split('V')[-1]) < 8:
            self._set_ports(sp.get('connections', list()))
        else:
            self._set_ports(sp.get('connectionSettings').get('connections'))

        if not self._validate_and_set_host(host_info):
            log.info("Invalid target server information: {}".format(host_info))
            return self.body

        for net in nets:
            if self._add_network_profile(net):
                log.debug('{} network configuration created.'.format(net))

        return self.body if len(self.body['config']) else dict()
Example #8
0
    def _add_network_profile(self, net_profile):
        """
        In conjunction with ports, creates the configuration dictionary
        :param dict net_profile: Network profile information
        :return bool: True when the configuration is added to self.body
        """
        net_types = list()

        if 'redhat' in self.body['host']['os'].lower() or \
                'red hat' in self.body['host']['os'] or \
                'rhel' in self.body['host']['os']:
            net_types = ['ethernet', 'bond', 'team']
        elif 'vmware' in self.body['host']['os'].lower():
            net_types = ['vss', 'vds']

        if not net_profile.get('type') or \
                not net_profile['type'].lower() in net_types:
            log.info('Unknown network config: {}'.format(net_profile['type']))
            log.info('Supported network configurations: {}'.format(net_types))
            return False

        net_uri = self._get_network_uri(net_profile.get('ov_network'))
        if net_uri is None:
            return False

        if net_uri not in self.ports:
            log.info('Network not part of server profile connections {}')
            return False

        self.net_profile = deepcopy(net_profile)

        if 'redhat' in self.body['host']['os'].lower() or \
                'red hat' in self.body['host']['os'] or \
                'rhel' in self.body['host']['os']:
            return self._add_rhel_config(net_profile['ov_network'], net_uri)
        elif 'vmware' in self.body['host']['os'].lower():
            return self._add_vmware_config(net_uri)

        log.debug('Unknown network profile type {}'.format(
            net_profile['type']))
        return False
    def configure_network(self, body):
        """
        Entry point for configuring the network interfaces. Based on the network
        type, the appropriate configurator is executed. Below are the supported
        options

        Input
        ------
        [host]
        ipv4            -| Target system IPv4 address
        os              -| Operating system installed on the target
        user            -| Root privileged account
        password        -| Password of the provided user

        [config]
        ports           -| List of MAC addresses or device names - str
        type            -| Network configuration type - ETHERNET, BOND or TEAM
        name             | Name of the connection required for BOND & TEAM
        bond_opts        | Bond options for BOND network type
        team_opts        | Team options for TEAM network type
        team_port_cfg    | Required for TEAM type - configuration values

        [networks]        | List of items having the below configurations
        vlan             | VLAN ID for the network
        dhcp            -| True when address is received from DHCP server else
        ipv4             | IPv4 network address
        ipv6             | IPv6 network address
        netmask          | Network mask

        -| keys are mandatory

        Output
        -------
        List of { "port": '', "status": <Pass | Fail> }

        :param dict body: Dictionary containing key-values from the above
        :return dict: Status for each network configuration
        """
        if len(body.get('config', list())) == 0:
            log.info('No configurations to be applied')
            return self.result

        if body.get('host', None) is None or not \
                self._verify_host(body['host']):
            return self.result

        if not self._remote_cmd('modprobe bonding && modprobe 8021q'):
            log.info('VLAN and bonding modules missing.')
            return self.result

        if not self._remote_cmd('which nmcli'):
            log.info('Missing required utility: nmcli')
            return self.result

        for c in body['config']:
            if len(c.get('ports', [])) == 0 or len(c.get('networks', [])) == 0 \
                    or c.get('type', None) is None:
                log.info('Missing network information')
                self.result.append({
                    'ports': c.get('ports', 'Unknown'),
                    'status': 'Fail'
                })
                continue

            if c['type'].lower() == 'ethernet':
                self._configure_ethernet(c)
            elif c['type'].lower() == 'bond' or c['type'].lower() == "team":
                if len(c['ports']) != 2:
                    log.info('Incorrect number of interfaces provided.')
                    self.result.append({'ports': c['ports'], 'status': 'Fail'})
                    continue

                if c.get('name', None) is None:
                    log.info('Missing required attribute: name')
                    self.result.append({'ports': c['ports'], 'status': 'Fail'})
                    continue

                if c['type'].lower() == "bond":
                    self._configure_bond(c)
                else:
                    self._configure_team(c)
            else:
                log.info('Unknown network port type: {}'.format(c['ports']))
                self.result.append({'ports': c['ports'], 'status': 'Fail'})

        self._remote_cmd('systemctl restart network.service', False)
        return self.result
    def _configure_team(self, cfg):
        """
        Method to configure network connections of type TEAM
        :param dict cfg: Dict containing information of network connections
        :return: None
        """
        if cfg.get('team_opts') is None:
            log.info('Missing required attribte: team_opts')
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        if cfg.get('team_port_cfg') is None or len(cfg['team_port_cfg']) != 2:
            log.info('Missing required attributes: team_port_cfg')
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        # Create Team Master
        cmd = 'nmcli connection add type team ifname {}'.format(cfg['name'])
        cmd += ' con-name {}'.format(cfg['name'])
        cmd += " team.options '{}'".format(cfg['team_opts'])
        cmd += ' ipv4.method disabled ipv6.method ignore'

        if self._remote_cmd(cmd):
            log.info('{} master configuration succeeded.'.format(cfg['name']))
        else:
            log.info('{} master configuration failed.'.format(cfg['name']))
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        for net in cfg['networks']:
            flag = False
            cname = cfg['name']

            if self._verify_network_info(net):
                vlan_id = 0 if not net.get('vlan') else net['vlan']
                cname += '.{}'.format(vlan_id)
                cmd = 'nmcli connection add type vlan'
                cmd += ' ifname {} con-name {}'.format(cname, cname)
                cmd += ' id {} dev {}'.format(vlan_id, cfg['name'])

                if not net.get('dhcp'):
                    if net.get('ipv4'):
                        cmd += ' ip4 {}'.format(net['ipv4'])
                    else:
                        cmd += ' ip6 {}'.format(net['ipv6'])

                    if net.get('netmask'):
                        b = sum([
                            bin(int(x)).count("1")
                            for x in net['netmask'].split(".")
                        ])
                        cmd += '/{}'.format(b)

                if self._remote_cmd(cmd):
                    flag = True
                    log.info('{} configuration succeeded'.format(cname))
                else:
                    log.info('{} configuration failed'.format(cname))
            else:
                log.info('Incorrect network information {}'.format(net))

            if flag:
                self.result.append({"ports": cname, 'status': 'Pass'})
            else:
                self.result.append({"ports": cname, 'status': 'Fail'})

        # Team master is not connect till all team-ports come on-line
        # This prevents existing connection drops.
        for i in range(len(cfg['ports'])):
            p = self._get_device_info(cfg['ports'][i])
            if p is None:
                log.info('Invalid port: {}'.format(cfg['ports'][i]))
                self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
                return

            cmd = 'nmcli connection add team-slave'
            cmd += ' ifname {} con-name {}-{}'.format(p['device_name'],
                                                      cfg['name'],
                                                      p['device_name'])
            cmd += ' master {}'.format(cfg['name'])
            cmd += " team-port.options '{}'".format(cfg['team_port_cfg'][i])

            if self._remote_cmd(cmd):
                log.info('{}-{} configuration passed'.format(
                    cfg['name'], p['device_name']))
            else:
                log.info('{}-{} configuration failed'.format(
                    cfg['name'], p['device_name']))
                self.result.append({
                    'ports': p['device_name'],
                    'status': 'Fail'
                })
                return

        _ = 'Network configuration completed for port: {}'.format(cfg['ports'])
        log.info(_)
    def _configure_bond(self, cfg):
        """
        Method to configure network connections of type BOND
        :param dict cfg: Dict containing information of network connections
        :return: None
        """
        if cfg.get('bond_opts') is None:
            log.info('Missing required attribute: bond_opts')
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        # Create Bond master
        cmd = 'nmcli connection add type bond ifname {}'.format(cfg['name'])
        cmd += ' con-name {}'.format(cfg['name'])
        cmd += " bond.options '{}'".format(cfg['bond_opts'])
        cmd += ' ipv4.method disabled ipv6.method ignore'

        if not self._remote_cmd(cmd):
            log.info('{} configuration failed.'.format(cfg['name']))
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return
        else:
            log.info('{} configuration succeed.'.format(cfg['name']))

        for net in cfg['networks']:
            flag = False
            cname = cfg['name']

            if self._verify_network_info(net):
                vlan_id = 0 if not net.get('vlan') else net['vlan']
                cname += '.{}'.format(vlan_id)
                cmd = 'nmcli connection add type vlan'
                cmd += ' ifname {} con-name {}'.format(cname, cname)
                cmd += ' id {} dev {}'.format(vlan_id, cfg['name'])

                if not net.get('dhcp'):
                    if net.get('ipv4'):
                        cmd += ' ip4 {}'.format(net['ipv4'])
                    else:
                        cmd += ' ip6 {}'.format(net['ipv6'])

                    if net.get('netmask'):
                        b = sum([
                            bin(int(x)).count("1")
                            for x in net['netmask'].split(".")
                        ])
                        cmd += '/{}'.format(b)

                if self._remote_cmd(cmd):
                    flag = True
                    log.info('{} configuration succeeded'.format(cname))
                else:
                    log.info('{} configuration failed'.format(cname))
            else:
                log.info('Incorrect network information {}'.format(net))

            if flag:
                self.result.append({"ports": cname, 'status': 'Pass'})
            else:
                self.result.append({"ports": cname, 'status': 'Fail'})

        # Bond master is not up till bond-slaves come online. This prevents
        # existing connectivity drops
        for port in cfg['ports']:
            p = self._get_device_info(port)
            if p is None:
                log.info('Invalid port: {}'.format(port))
                self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
                return

            cmd = 'nmcli connection add type bond-slave'
            cmd += ' ifname {} con-name {}-{}'.format(p['device_name'],
                                                      cfg['name'],
                                                      p['device_name'])
            cmd += ' master {}'.format(cfg['name'])

            if not self._remote_cmd(cmd):
                _ = '{} port configuration failed.'.format(p['device_name'])
                log.info(_)
                self.result.append({
                    'ports': p['device_name'],
                    'status': 'Fail'
                })
                return
            else:
                _ = '{} bond slave port configured.'.format(p['device_name'])
                log.info(_)

        _ = 'Network configuration completed for port: {}'.format(cfg['ports'])
        log.info(_)
    def _configure_ethernet(self, cfg):
        """
        Method to configure network connections of type ETHERNET
        :param dict cfg: Dict containing information of network connections
        :return: None
        """
        if len(cfg['ports']) != 1:
            log.info('Invalid number of port provided for Ethernet network.')
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        p = self._get_device_info(cfg['ports'][0])
        if p is None:
            log.info('Invalid port information: {}'.format(cfg['ports']))
            self.result.append({'ports': cfg['ports'], 'status': 'Fail'})
            return

        for net in cfg['networks']:
            flag = False
            cname = p['device_name']

            if self._verify_network_info(net):
                cmd = 'nmcli connection add'

                if net.get('vlan'):
                    cname += '.{}'.format(net['vlan'])
                    cmd += ' type vlan con-name {}'.format(cname)
                    cmd += ' dev {} id {}'.format(p['device_name'],
                                                  net['vlan'])
                else:
                    cmd += ' type ethernet con-name {}'.format(cname)
                    cmd += ' ifname {}'.format(p['device_name'])

                if not net.get('dhcp'):
                    if net.get('ipv4'):
                        cmd += ' ip4 {}'.format(net['ipv4'])
                    else:
                        cmd += ' ip6 {}'.format(net['ipv6'])

                    if net.get('netmask'):
                        b = sum([
                            bin(int(x)).count("1")
                            for x in net['netmask'].split(".")
                        ])
                        cmd += '/{}'.format(b)

                if self._remote_cmd(cmd):
                    flag = True
                    log.info('Network {} configured.'.format(cname))
                else:
                    log.info('Network {} failed.'.format(cname))
            else:
                log.info('Incorrect network information {}'.format(net))

            if flag:
                self.result.append({"ports": cname, 'status': 'Pass'})
            else:
                self.result.append({"ports": cname, 'status': 'Fail'})

        _ = 'Network configuration completed for port: {}'.format(cfg['ports'])
        log.info(_)
Example #13
0
    def _add_vmware_config(self, uri):
        """
        Creates the network configuration for VMware based systems
        :param str uri: OneView's networkUri
        :return bool: True when network configuration is appended to body
        """
        if self.net_profile.get('name') is None:
            log.info('Virtual Switch name is required')
            return False

        if self.net_profile.get('type').lower() == 'vds':
            attrs = ['manager', 'datacenter', 'cluster']

            if not set(attrs).issubset(self.body['host'].keys()):
                m = 'Missing required attributes.'
                m += "Additional required attributes are\t{}".format(attrs)
                log.info(m)
                return False

        cfg = dict({
            'name': self.net_profile['name'],
            'type': self.net_profile['type'],
            'ports': self.ports[uri]
        })

        nets = list()
        if 'ethernet-network' in uri:
            n = self._get_network_addr(uri, True)
            if n is None:
                return False

            if self.net_profile.get('networks') and \
                    self.net_profile['networks'].get(n['vlan']):
                if 'policy' in self.net_profile['networks'][n['vlan']]:
                    n['policy'] = \
                        self.net_profile['network'][n['vlan']]['policy']

                if 'vmk' in self.net_profile['network'][n['vlan']]:
                    n['vmk'] = self.net_profile['network'][n['vlan']]['vmk']
                else:
                    # No vmkernel port would be created
                    n['vmk'] = False
            else:
                n['vmk'] = False

            # VLAN is configured on the downlink port
            del n['vlan']
            nets.append(n)
        elif 'network-set' in uri:
            ns = self.fusion_api_get_network_set(uri=uri)
            if ns.get('nativeNetworkUri'):
                n = self._get_network_addr(ns['nativeNetworkUri'], True)
                if n is not None:
                    if self.net_profile.get('networks') and \
                            self.net_profile['networks'].get(n['vlan']):
                        if 'policy' in self.net_profile['networks'][n['vlan']]:
                            n['policy'] = \
                                self.net_profile['networks'][n['vlan']]['policy']

                        if 'vmk' in self.net_profile['networks'][n['vlan']]:
                            n['vmk'] = \
                                self.net_profile['networks'][n['vlan']]['vmk']
                        else:
                            n['vmk'] = False
                    else:
                        n['vmk'] = False

                    del n['vlan']
                    nets.append(n)

            for u in ns.get('networkUris', []):
                if u == ns.get('nativeNetworkUri'):
                    log.debug('Ignoring this network as it is a native one.')
                    continue

                n = self._get_network_addr(u, True)
                if n is None:
                    continue

                if self.net_profile.get('networks') and \
                        self.net_profile['networks'].get(n['vlan']):
                    if 'policy' in self.net_profile['networks'][n['vlan']]:
                        n['policy'] = \
                            self.net_profile['networks'][n['vlan']]['policy']

                    if 'vmk' in self.net_profile['networks'][n['vlan']]:
                        n['vmk'] = \
                            self.net_profile['networks'][n['vlan']]['vmk']
                    else:
                        n['vmk'] = False
                else:
                    n['vmk'] = False

                nets.append(n)

            cfg['active'] = self.net_profile.get('active', len(cfg['ports']))
        else:
            log.info('Unsupported network connection {}'.format(uri))
            log.info('Supported types: vss, vds')

        if nets:
            cfg['networks'] = nets
            self.body['config'].append(cfg)
            log.debug('Network config: {}'.format(cfg))
            return True

        log.debug('No network information was retrieved... skipping')
        return False
Example #14
0
    def _add_rhel_config(self, name, uri):
        """
        Creates the network configuration for RHEL based systems
        :param str name: Name of the network name
        :param str uri: OneView's networkUri
        :return bool: True when network configuration is appended to body
        """
        port_count = len(self.ports[uri])
        if self.net_profile['type'].lower() == 'ethernet' and port_count != 1:
            _ = 'Invalid number of ports {}'.format(name)
            log.info(_)
            return False

        if (self.net_profile['type'].lower() == 'bond' or
            self.net_profile['type'].lower() == 'team') and \
                port_count != 2:
            _ = 'Invalid number of port for {}'.format(name)
            log.info(_)
            return False

        cfg = {
            'name': self.net_profile.get('name', name),
            'type': self.net_profile['type'],
            'ports': self.ports[uri]
        }

        if self.net_profile['type'].lower() == 'bond':
            cfg.update({'bond_opts': self.net_profile['bond_opts']})
        elif self.net_profile['type'].lower() == 'team':
            cfg.update({
                'team_opts': self.net_profile['team_opts'],
                'team_port_cfg': self.net_profile['team_port_cfg']
            })

        nets = list()
        if 'ethernet-network' in uri:
            n = self._get_network_addr(uri)
            if n is not None:
                # VLAN is configured on the interconnect
                if n.get('vlan'):
                    # Removing VLAN as it is a single network and Oneview
                    # configures the same on the interconnect downlink port
                    del n['vlan']

                nets.append(n)
        elif 'network-set' in uri:
            r = self.fusion_api_get_network_set(uri=uri)
            if r.get('nativeNetworkUri'):
                n = self._get_network_addr(r['nativeNetworkUri'])
                if n is not None:
                    if n.get('vlan'):
                        # Removing VLAN as it is native to network set and
                        # configured by Oneview on the interconnect downlink
                        del n['vlan']

                    nets.append(n)

            for u in r.get('networkUris', []):
                if u == r.get('nativeNetworkUri'):
                    log.debug('Ignoring this network as it is native')
                    continue

                n = self._get_network_addr(u)
                if n is not None:
                    nets.append(n)
        else:
            log.info('Unknown OneView network connection: {}'.format(uri))
            log.info('Supported types: ethernet, network-set')
            return False

        if nets:
            cfg['networks'] = deepcopy(nets)
            self.body['config'].append(cfg)
            log.debug('Network config: {}'.format(cfg))
            return True

        log.debug('No network information retrieved... skipping')
        return False