Esempio n. 1
0
def create_discovered_host(name=None,
                           ip_address=None,
                           mac_address=None,
                           options=None):
    """Creates a discovered host.

    :param str name: Name of discovered host.
    :param str ip_address: A valid ip address.
    :param str mac_address: A valid mac address.
    :param dict options: additional facts to add to discovered host
    :return: dict of ``entities.DiscoveredHost`` facts.
    """
    if name is None:
        name = gen_string('alpha')
    if ip_address is None:
        ip_address = gen_ipaddr()
    if mac_address is None:
        mac_address = gen_mac(multicast=False)
    if options is None:
        options = {}
    facts = {
        'name': name,
        'discovery_bootip': ip_address,
        'discovery_bootif': mac_address,
        'interfaces': 'eth0',
        'ipaddress': ip_address,
        'ipaddress_eth0': ip_address,
        'macaddress': mac_address,
        'macaddress_eth0': mac_address,
    }
    facts.update(options)
    return entities.DiscoveredHost().facts(json={'facts': facts})
Esempio n. 2
0
def _create_discovered_host(name=None, ipaddress=None, macaddress=None):
    """Creates discovered host by uploading few fake facts.

    :param str name: Name of discovered host. If ``None`` then a random
        value will be generated.
    :param str ipaddress: A valid ip address.
        If ``None`` then then a random value will be generated.
    :param str macaddress: A valid mac address.
        If ``None`` then then a random value will be generated.
    :return: A ``dict`` of ``DiscoveredHost`` facts.
    """
    if name is None:
        name = gen_string('alpha')
    if ipaddress is None:
        ipaddress = gen_ipaddr()
    if macaddress is None:
        macaddress = gen_mac(multicast=False)
    return entities.DiscoveredHost().facts(
        json={
            u'facts': {
                u'name': name,
                u'discovery_bootip': ipaddress,
                u'discovery_bootif': macaddress,
                u'interfaces': 'eth0',
                u'ipaddress': ipaddress,
                u'macaddress': macaddress,
                u'macaddress_eth0': macaddress,
                u'ipaddress_eth0': ipaddress,
            }
        })
Esempio n. 3
0
    def test_positive_upload_facts(self):
        """Upload fake facts to create a discovered host

        :id: c1f40204-bbb0-46d0-9b60-e42f00ad1649

        :BZ: 1349364, 1392919

        :Steps:

            1. POST /api/v2/discovered_hosts/facts
            2. Read the created discovered host

        :expectedresults: Host should be created successfully

        :CaseImportance: High

        :CaseLevel: Integration
        """
        for name in valid_data_list():
            with self.subTest(name):
                result = _create_discovered_host(name)
                discovered_host = entities.DiscoveredHost(
                    id=result['id']).read()
                host_name = 'mac{0}'.format(
                    discovered_host.mac.replace(':', ''))
                self.assertEqual(discovered_host.name, host_name)
Esempio n. 4
0
def test_positive_upload_facts():
    """Upload fake facts to create a discovered host

    :id: c1f40204-bbb0-46d0-9b60-e42f00ad1649

    :BZ: 1349364, 1392919

    :Steps:

        1. POST /api/v2/discovered_hosts/facts
        2. Read the created discovered host

    :expectedresults: Host should be created successfully

    :CaseImportance: High

    :CaseLevel: Integration

    :BZ: 1731112
    """
    name = gen_choice(list(valid_data_list().values()))
    result = _create_discovered_host(name)
    discovered_host = entities.DiscoveredHost(id=result['id']).read_json()
    host_name = 'mac{}'.format(discovered_host['mac'].replace(':', ''))
    assert discovered_host['name'] == host_name
Esempio n. 5
0
def test_positive_reboot_all_pxe_hosts(_module_user, discovered_host_cleanup,
                                       discovery_settings, provisioning_env):
    """Rebooting all pxe-based discovered hosts

    :id: 69c807f8-5646-4aa6-8b3c-5ecdb69560ed

    :parametrized: yes

    :Setup: Provisioning should be configured and a hosts should be discovered via PXE boot.

    :Steps: PUT /api/v2/discovered_hosts/reboot_all

    :expectedresults: All disdcovered host should be rebooted successfully

    :CaseAutomation: Automated

    :CaseImportance: Medium
    """
    cfg = get_nailgun_config()
    if _module_user:
        cfg.auth = (_module_user[0].login, _module_user[1])

    # open ssh channels and attach them to foreman-tail output
    channel_1, channel_2 = ssh.get_client().invoke_shell(), ssh.get_client(
    ).invoke_shell()
    channel_1.send('foreman-tail\r')
    channel_2.send('foreman-tail\r')

    with LibvirtGuest() as pxe_host_1:
        _assert_discovered_host(pxe_host_1, channel_1, user_config=cfg)
        with LibvirtGuest() as pxe_host_2:
            _assert_discovered_host(pxe_host_2, channel_2, user_config=cfg)
            # reboot_all method leads to general /discovered_hosts/ path, so it doesn't matter
            # what DiscoveredHost object we execute this on
            try:
                entities.DiscoveredHost().reboot_all()
            except simplejson.errors.JSONDecodeError as e:
                if is_open('BZ:1893349'):
                    pass
                else:
                    raise e
            # assert that server receives DHCP discover from hosts PXELinux
            # this means that the hosts got rebooted
            for pxe_host in [(pxe_host_1, channel_1), (pxe_host_2, channel_2)]:
                for pattern in [
                    (
                        f"DHCPDISCOVER from {pxe_host[0].mac}",
                        "DHCPDISCOVER",
                    ),
                    (f"DHCPACK on [0-9.]+ to {pxe_host[0].mac}", "DHCPACK"),
                ]:
                    try:
                        _wait_for_log(pxe_host[1], pattern[0], timeout=30)
                    except TimedOutError:
                        # raise assertion error
                        raise AssertionError(
                            f'Timed out waiting for {pattern[1]} from '
                            f'{pxe_host[0].mac}')
Esempio n. 6
0
    def test_positive_provision_pxe_host_non_admin(self):
        """Provision a pxe-based discovered hosts by non-admin user

        :id: 02144040-6cf6-4251-abaf-b0fad2c83109

        :Setup: Provisioning should be configured and a host should be
            discovered

        :Steps: PUT /api/v2/discovered_hosts/:id

        :expectedresults: Host should be provisioned successfully by non admin user

        :CaseImportance: Critical

        :bz: 1638403
        """
        non_admin = create_org_admin_user(orgs=[self.org.id],
                                          locs=[self.loc.id])
        nonadmin_config = get_nailgun_config(non_admin)
        if not self.configured_env:
            self.__class__.configured_env = configure_env_for_provision(
                org={
                    'id': self.org.id,
                    'name': self.org.name
                },
                loc={
                    'id': self.loc.id,
                    'name': self.loc.name
                },
            )
        with LibvirtGuest() as pxe_host:
            hostname = pxe_host.guest_name
            discovered_host = self._assertdiscoveredhost(
                hostname, nonadmin_config)
            # Provision just discovered host
            discovered_host.hostgroup = entities.HostGroup(
                nonadmin_config,
                id=self.configured_env['hostgroup']['id']).read()
            discovered_host.root_pass = gen_string('alphanumeric')
            discovered_host.update(['hostgroup', 'root_pass'])
            # Assertions
            provisioned_host = entities.Host(nonadmin_config).search(
                query={
                    'search':
                    'name={}.{}'.format(discovered_host.name,
                                        self.configured_env['domain']['name'])
                })[0]
            assert provisioned_host.subnet.read(
            ).name == self.configured_env['subnet']['name']
            assert (provisioned_host.operatingsystem.read().ptable[0].read().
                    name == self.configured_env['ptable']['name'])
            assert (provisioned_host.operatingsystem.read().title ==
                    self.configured_env['os']['title'])
            assert not entities.DiscoveredHost(nonadmin_config).search(
                query={'search': f'name={discovered_host.name}'})
Esempio n. 7
0
def test_positive_delete_pxe_host():
    """Delete a pxe-based discovered hosts

    :id: 2ab2ad88-4470-4d4c-8e0b-5892ad8d675e

    :Setup: Provisioning should be configured and a host should be
        discovered

    :Steps: DELETE /api/v2/discovered_hosts/:id

    :expectedresults: Discovered Host should be deleted successfully

    :CaseAutomation: Automated

    :CaseImportance: High
    """
    name = gen_choice(list(valid_data_list().values()))
    result = _create_discovered_host(name)

    entities.DiscoveredHost(id=result['id']).delete()
    search = entities.DiscoveredHost().search(
        query={'search': 'name == {}'.format(result['name'])})
    assert len(search) == 0
Esempio n. 8
0
def test_positive_provision_pxe_host(_module_user, discovery_settings,
                                     provisioning_env):
    """Provision a pxe-based discovered hosts

    :id: e805b9c5-e8f6-4129-a0e6-ab54e5671ddb

    :parametrized: yes

    :Setup: Provisioning should be configured and a host should be
        discovered

    :Steps: PUT /api/v2/discovered_hosts/:id

    :expectedresults: Host should be provisioned successfully

    :CaseImportance: Critical
    """
    cfg = get_nailgun_config()
    if _module_user:
        cfg.auth = (_module_user[0].login, _module_user[1])

    # open a ssh channel and attach it to foreman-tail output
    ssh_client = ssh.get_client()
    with ssh_client.invoke_shell() as channel:
        channel.send('foreman-tail\r')

        with LibvirtGuest() as pxe_host:
            discovered_host = _assert_discovered_host(pxe_host,
                                                      channel,
                                                      user_config=cfg)
            # Provision just discovered host
            discovered_host.hostgroup = entities.HostGroup(
                cfg, id=provisioning_env['hostgroup']['id']).read()
            discovered_host.root_pass = gen_string('alphanumeric')
            discovered_host.update(['hostgroup', 'root_pass'])
            # Assertions
            provisioned_host = entities.Host(cfg).search(
                query={
                    'search':
                    'name={}.{}'.format(discovered_host.name,
                                        provisioning_env['domain']['name'])
                })[0]
            assert provisioned_host.subnet.read(
            ).name == provisioning_env['subnet']['name']
            assert (provisioned_host.operatingsystem.read().ptable[0].read().
                    name == provisioning_env['ptable']['name'])
            assert provisioned_host.operatingsystem.read(
            ).title == provisioning_env['os']['title']
            assert not entities.DiscoveredHost(cfg).search(
                query={'search': f'name={discovered_host.name}'})
Esempio n. 9
0
def test_positive_discovered_host(session):
    """Check if the Discovered Host widget is working in the Dashboard UI

    :id: 74afef58-71f4-49e1-bbb6-6d4355d385f8

    :Steps:

        1. Create a Discovered Host.
        2. Navigate Monitor -> Dashboard
        3. Review the Discovered Host Status.

    :expectedresults: The widget is updated with all details.

    :CaseLevel: Integration
    """
    org = entities.Organization().create()
    loc = entities.Location(organization=[org]).create()
    ipaddress = gen_ipaddr()
    macaddress = gen_mac(multicast=False)
    model = gen_string('alpha', length=5)
    host_name = 'mac{0}'.format(macaddress.replace(':', ''))
    entities.DiscoveredHost().facts(json={
        u'facts': {
            u'name': gen_string('alpha'),
            u'discovery_bootip': ipaddress,
            u'discovery_bootif': macaddress,
            u'interfaces': 'eth0',
            u'ipaddress': ipaddress,
            u'macaddress': macaddress,
            u'macaddress_eth0': macaddress,
            u'ipaddress_eth0': ipaddress,
            u'foreman_organization': org.name,
            u'foreman_location': loc.name,
            u'model': model,
            u'memorysize_mb': 1000,
            u'physicalprocessorcount': 2,
        }
    })

    with session:
        session.organization.select(org_name=org.name)
        session.location.select(loc_name=loc.name)
        values = session.dashboard.read('DiscoveredHosts')
        assert len(values['hosts']) == 1
        assert values['hosts_count'] == '1 Discovered Host'
        assert values['hosts'][0]['Host'] == host_name
        assert values['hosts'][0]['Model'] == model
        assert values['hosts'][0]['CPUs'] == '2'
        assert values['hosts'][0]['Memory'] == '1000 MB'
Esempio n. 10
0
    def test_positive_provision_pxe_host(self):
        """Provision a pxe-based discovered hosts

        :id: e805b9c5-e8f6-4129-a0e6-ab54e5671ddb

        :Setup: Provisioning should be configured and a host should be
            discovered

        :Steps: PUT /api/v2/discovered_hosts/:id

        :expectedresults: Host should be provisioned successfully

        :CaseImportance: Critical
        """
        if not self.configured_env:
            self.__class__.configured_env = configure_env_for_provision(
                org={
                    'id': self.org.id,
                    'name': self.org.name
                },
                loc={
                    'id': self.loc.id,
                    'name': self.loc.name
                },
            )
        with LibvirtGuest() as pxe_host:
            hostname = pxe_host.guest_name
            discovered_host = self._assertdiscoveredhost(hostname)
            # Provision just discovered host
            discovered_host.hostgroup = entities.HostGroup(
                id=self.configured_env['hostgroup']['id']).read()
            discovered_host.root_pass = gen_string('alphanumeric')
            discovered_host.update(['hostgroup', 'root_pass'])
            # Assertions
            provisioned_host = entities.Host().search(
                query={
                    'search':
                    'name={}.{}'.format(discovered_host.name,
                                        self.configured_env['domain']['name'])
                })[0]
            assert provisioned_host.subnet.read(
            ).name == self.configured_env['subnet']['name']
            assert (provisioned_host.operatingsystem.read().ptable[0].read().
                    name == self.configured_env['ptable']['name'])
            assert (provisioned_host.operatingsystem.read().title ==
                    self.configured_env['os']['title'])
            assert not entities.DiscoveredHost().search(
                query={'search': f'name={discovered_host.name}'})
Esempio n. 11
0
    def _assertdiscoveredhost(self, hostname, user_config=None):
        """Check if host is discovered and information about it can be
        retrieved back

        Introduced a delay of 300secs by polling every 10 secs to get expected
        host
        """
        default_config = entity_mixins.DEFAULT_SERVER_CONFIG
        for _ in range(30):
            discovered_host = entities.DiscoveredHost(
                user_config
                or default_config).search(query={'search': f'name={hostname}'})
            if discovered_host:
                break
            time.sleep(10)
        else:
            raise HostNotDiscoveredException(
                f"The host {hostname} is not discovered within 300 seconds")
        return discovered_host[0]
Esempio n. 12
0
def test_positive_auto_provision_pxe_host(_module_user, module_org,
                                          module_location, discovery_settings,
                                          provisioning_env):
    """Auto provision a pxe-based host by executing discovery rules

    :id: c93fd7c9-41ef-4eb5-8042-f72e87e67e10

    :parametrized: yes

    :Setup: Provisioning should be configured and a host should be
        discovered

    :Steps: POST /api/v2/discovered_hosts/:id/auto_provision

    :expectedresults: Selected Host should be auto-provisioned successfully

    :CaseAutomation: Automated

    :CaseImportance: Critical
    """
    cfg = get_nailgun_config()
    if _module_user:
        cfg.auth = (_module_user[0].login, _module_user[1])

    # open a ssh channel and attach it to foreman-tail output
    ssh_client = ssh.get_client()
    with ssh_client.invoke_shell() as channel:
        channel.send('foreman-tail\r')

        with LibvirtGuest() as pxe_host:
            discovered_host = _assert_discovered_host(pxe_host,
                                                      channel,
                                                      user_config=cfg)
            # Provision just discovered host
            discovered_host.hostgroup = entities.HostGroup(
                cfg, id=provisioning_env['hostgroup']['id']).read()

            # create a discovery rule that will match hosts MAC address
            entities.DiscoveryRule(
                name=gen_string('alphanumeric'),
                search_=f"mac = {discovered_host.mac}",
                organization=[module_org],
                location=[module_location],
                hostgroup=entities.HostGroup(
                    cfg, id=provisioning_env['hostgroup']['id']).read(),
            ).create()
            # Auto-provision the host
            discovered_host.auto_provision()

            # Assertions
            provisioned_host = entities.Host(cfg).search(
                query={
                    'search':
                    'name={}.{}'.format(discovered_host.name,
                                        provisioning_env['domain']['name'])
                })[0]
            assert provisioned_host.subnet.read(
            ).name == provisioning_env['subnet']['name']
            assert (provisioned_host.operatingsystem.read().ptable[0].read().
                    name == provisioning_env['ptable']['name'])
            assert provisioned_host.operatingsystem.read(
            ).title == provisioning_env['os']['title']
            assert not entities.DiscoveredHost(cfg).search(
                query={'search': f'name={discovered_host.name}'})
Esempio n. 13
0
def discovered_host_cleanup():
    hosts = entities.DiscoveredHost().search()
    for host in hosts:
        host.delete()
Esempio n. 14
0
def _assert_discovered_host(host, channel=None, user_config=None):
    """Check if host is discovered and information about it can be
    retrieved back

    Introduced a delay of 300secs by polling every 10 secs to get expected
    host
    """
    # assert that server receives DHCP discover from hosts PXELinux
    for pattern in [
        (
            f"DHCPDISCOVER from {host.mac}",
            "DHCPDISCOVER",
        ),
        (f"DHCPACK on [0-9.]+ to {host.mac}", "DHCPACK"),
    ]:
        try:
            dhcp_pxe = _wait_for_log(channel, pattern[0], timeout=10)
        except TimedOutError:
            # raise assertion error
            raise AssertionError(f'Timed out waiting for {pattern[1]} from VM')

    groups = re.search('DHCPACK on (\\d.+) to', dhcp_pxe.out)
    assert len(groups.groups()) == 1, 'Unable to parse bootloader ip address'
    pxe_ip = groups.groups()[0]

    # assert that server retrieves pxelinux config over TFTP
    for pattern in [
        (f'Client {pxe_ip} finished pxelinux.0', 'pxelinux.0'),
        (f'Client {pxe_ip} finished pxelinux.cfg/default',
         'pxelinux.cfg/default'),
        (f'Client {pxe_ip} finished boot/fdi-image/vmlinuz0',
         'fdi-image/vmlinuz0'),
        (f'Client {pxe_ip} finished boot/fdi-image/initrd0.img',
         'fdi-image/initrd0.img'),
    ]:
        try:
            _wait_for_log(channel, pattern[0], timeout=20)
        except TimedOutError:
            # raise assertion error
            raise AssertionError(
                f'Timed out waiting for VM (tftp) to fetch {pattern[1]}')

    # assert that server receives DHCP discover from FDI
    for pattern in [
        (
            f"DHCPDISCOVER from {host.mac}",
            "DHCPDISCOVER",
        ),
        (f"DHCPACK on [0-9.]+ to {host.mac}", "DHCPACK"),
    ]:
        try:
            dhcp_fdi = _wait_for_log(channel, pattern[0], timeout=30)
        except TimedOutError:
            # raise assertion error
            raise AssertionError(f'Timed out waiting for {pattern[1]} from VM')
    groups = re.search('DHCPACK on (\\d.+) to', dhcp_fdi.out)
    assert len(groups.groups()) == 1, 'Unable to parse FDI ip address'
    fdi_ip = groups.groups()[0]

    # finally, assert that the FDI successfully uploaded its facts to the server
    try:
        facts_fdi = _wait_for_log(
            channel,
            f'\\[I\\|app\\|[a-z0-9]+\\] Started POST '
            f'"/api/v2/discovered_hosts/facts" for {fdi_ip}',
            timeout=60,
        )
    except TimedOutError:
        # raise assertion error
        raise AssertionError('Timed out waiting for /facts POST request')
    groups = re.search('\\[I\\|app\\|([a-z0-9]+)\\]', facts_fdi.out)
    assert len(groups.groups()) == 1, 'Unable to parse POST request UUID'
    req_id = groups.groups()[0]

    try:
        _wait_for_log(channel,
                      f'\\[I\\|app\\|{req_id}\\] Completed 201 Created')
    except TimedOutError:
        # raise assertion error
        raise AssertionError('Timed out waiting for "/facts" 201 response')

    default_config = entity_mixins.DEFAULT_SERVER_CONFIG

    try:
        wait_for(
            lambda: len(
                entities.DiscoveredHost(user_config or default_config).search(
                    query={'search': f'name={host.guest_name}'})) > 0,
            timeout=20,
            delay=2,
            logger=logger,
        )
    except TimedOutError:
        raise AssertionError(
            'Timed out waiting for discovered_host to appear on satellite')
    discovered_host = entities.DiscoveredHost(
        user_config
        or default_config).search(query={'search': f'name={host.guest_name}'})
    return discovered_host[0]
Esempio n. 15
0
    def test_positive_provision_pxe_host_dhcp_change(self, discovery_settings,
                                                     provisioning_env):
        """Discovered host is provisioned in dhcp range defined in subnet entity

        :id: 7ab654de-16dd-4a8b-946d-f6adde310340

        :bz: 1367549

        :Setup: Provisioning should be configured and a host should be
            discovered

        :Steps:
            1. Set some dhcp range in dhcpd.conf in satellite.
            2. Create subnet entity in satellite with a range different from whats defined
                in `dhcpd.conf`.
            3. Create Hostgroup with the step 2 subnet.
            4. Discover a new host in satellite.
            5. Provision a host with the hostgroup created in step 3.

        :expectedresults:
            1. The discovered host should be discovered with range defined in dhcpd.conf
            2. But provisoning the discovered host should acquire an IP from dhcp range
                defined in subnet entity.

        :CaseImportance: Critical
        """
        subnet = entities.Subnet(id=provisioning_env['subnet']['id']).read()
        # Updating satellite subnet component and dhcp conf ranges
        # Storing now for restoring later
        old_sub_from = subnet.from_
        old_sub_to = subnet.to
        old_sub_to_4o = old_sub_to.split('.')[-1]
        # Calculating Subnet's new `from` range in Satellite Subnet Component
        new_subnet_from = subnet.from_[:subnet.from_.rfind('.') +
                                       1] + str(int(old_sub_to_4o) - 9)
        # Same time, calculating dhcp confs new `to` range
        new_dhcp_conf_to = subnet.to[:subnet.to.rfind('.') +
                                     1] + str(int(old_sub_to_4o) - 10)

        cfg = get_nailgun_config()
        ssh_client = ssh.get_client()
        with ssh_client.invoke_shell() as channel:
            channel.send('foreman-tail\r')
            try:
                # updating the ranges in component and in dhcp.conf
                subnet.from_ = new_subnet_from
                subnet.update(['from_'])
                ssh_client.exec_command(
                    f'cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd_backup.conf && '
                    f'sed -ie \'s/{subnet.to}/{new_dhcp_conf_to}/\' /etc/dhcp/dhcpd.conf && '
                    f'systemctl restart dhcpd')
                with LibvirtGuest() as pxe_host:
                    discovered_host = _assert_discovered_host(
                        pxe_host, channel, cfg)
                    # Assert Discovered host discovered within dhcp.conf range before provisioning
                    assert int(discovered_host.ip.split('.')[-1]) <= int(
                        new_dhcp_conf_to.split('.')[-1])
                    # Provision just discovered host
                    discovered_host.hostgroup = entities.HostGroup(
                        id=provisioning_env['hostgroup']['id']).read()
                    discovered_host.root_pass = gen_string('alphanumeric')
                    discovered_host.update(['hostgroup', 'root_pass'])
                    # Assertions
                    provisioned_host = entities.Host().search(
                        query={
                            'search':
                            'name={}.{}'.format(
                                discovered_host.name,
                                provisioning_env['domain']['name'])
                        })[0]
                    assert int(provisioned_host.ip.split('.')[-1]) >= int(
                        new_subnet_from.split('.')[-1])
                    assert int(provisioned_host.ip.split('.')[-1]) <= int(
                        old_sub_to_4o)
                    assert not entities.DiscoveredHost().search(
                        query={'search': f'name={discovered_host.name}'})
            finally:
                subnet.from_ = old_sub_from
                subnet.update(['from_'])
                ssh_client.exec_command(
                    'mv /etc/dhcp/dhcpd_backup.conf /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf'
                )