def do_test_ok_preauth_and_remove(self):
        """
            Test the removal of a preauthorized auth set, verify it's gone from all API results.
        """
        # preauthorize
        preauth_iddata = "{\"mac\":\"preauth-mac\"}"
        preauth_key = "preauth-key"

        r = adm.preauth(preauth_iddata, preauth_key)
        assert r.status_code == 201

        devs = adm.get_devices(2)

        dev_preauth = [d for d in devs if d['device_identity'] == preauth_iddata]
        assert len(dev_preauth) == 1
        dev_preauth = dev_preauth[0]

        # remove from admission
        r = adm.delete_auth_set(dev_preauth['id'])
        assert r.status_code == 204

        # verify removed from admission
        devs = adm.get_devices(1)
        dev_removed = [d for d in devs if d['device_identity'] == preauth_iddata]
        assert len(dev_removed) == 0

        # verify removed from deviceauth
        r = deviceauth.get_device(dev_preauth['id'])
        assert r.status_code == 404

        # verify removed from inventory
        r = inv.get_device(dev_preauth['id'])
        assert r.status_code == 404
def update_image_successful(install_image,
                            regenerate_image_id=True,
                            signed=False,
                            skip_reboot_verification=False,
                            expected_mender_clients=1,
                            pre_upload_callback=lambda: None,
                            pre_deployment_callback=lambda: None,
                            deployment_triggered_callback=lambda: None,
                            compression_type="gzip"):
    """
        Perform a successful upgrade, and assert that deployment status/logs are correct.

        A reboot is performed, and running partitions have been swapped.
        Deployment status will be set as successful for device.
        Logs will not be retrieved, and result in 404.
    """

    previous_inactive_part = Helpers.get_passive_partition()
    with Helpers.RebootDetector() as reboot:
        deployment_id, expected_image_id = common_update_procedure(
            install_image,
            regenerate_image_id,
            signed=signed,
            pre_deployment_callback=pre_deployment_callback,
            deployment_triggered_callback=deployment_triggered_callback,
            compression_type=compression_type)
        reboot.verify_reboot_performed()

    with Helpers.RebootDetector() as reboot:
        try:
            assert Helpers.get_active_partition() == previous_inactive_part
        except AssertionError:
            logs = []
            for d in adm.get_devices():
                logs.append(deploy.get_logs(d["device_id"], deployment_id))

            pytest.fail(
                "device did not flip partitions during update, here are the device logs:\n\n %s"
                % (logs))

        deploy.check_expected_statistics(deployment_id, "success",
                                         expected_mender_clients)

        for d in adm.get_devices():
            deploy.get_logs(d["device_id"], deployment_id, expected_status=404)

        if not skip_reboot_verification:
            reboot.verify_reboot_not_performed()

    assert Helpers.yocto_id_installed_on_machine() == expected_image_id

    deploy.check_expected_status("finished", deployment_id)

    # make sure backend recognizes signed and unsigned images
    artifact_id = deploy.get_deployment(deployment_id)["artifacts"][0]
    artifact_info = deploy.get_artifact_details(artifact_id)
    assert artifact_info[
        "signed"] is signed, "image was not correct recognized as signed/unsigned"

    return deployment_id
    def test_device_decommissioning(self):
        """ Decommission a device successfully """

        if not env.host_string:
            execute(self.test_device_decommissioning, hosts=get_mender_clients())
            return

        adm.check_expected_status("pending", len(get_mender_clients()))
        adm_id = adm.get_devices()[0]["id"]
        device_id = adm.get_devices()[0]["device_id"]

        adm.set_device_status(adm_id, "accepted")

        # wait until inventory is populated
        timeout = time.time() + (60 * 5)
        while time.time() < timeout:
            inventoryJSON = inv.get_devices()
            if "attributes" in inventoryJSON[0]:
                break
            time.sleep(.5)
        else:
            assert False, "never got inventory"

        # decommission actual device
        deviceauth.decommission(device_id)

        # now check that the device no longer exists in admissions
        timeout = time.time() + (60 * 5)
        while time.time() < timeout:
                newAdmissions = adm.get_devices()[0]
                if device_id != newAdmissions["device_id"] \
                   and adm_id != newAdmissions["id"]:
                    logger.info("device [%s] not found in inventory [%s]" % (device_id, str(newAdmissions)))
                    break
                else:
                    logger.info("device [%s] found in inventory..." % (device_id))
                time.sleep(.5)
        else:
            assert False, "decommissioned device still available in admissions"

        # disabled for time being due to new deployment process


        # make sure a deployment to the decommissioned device fails
        # try:
        #    time.sleep(120)  # sometimes deployment microservice hasn't removed the device yet
        #    logger.info("attempting to deploy to decommissioned device: %s" % (device_id))
        #    deployment_id, _ = common_update_procedure(install_image=conftest.get_valid_image(),
        #                                               devices=[device_id],
        #                                               verify_status=False)
        #except AssertionError:
        #    logging.info("Failed to deploy upgrade to rejected device, as expected.")
        #else:
        #    assert False, "No error while trying to deploy to rejected device"

        # authtoken has been removed
        #run("strings /data/mender/mender-store | grep -q 'authtoken' || false")

        """
Exemple #4
0
    def test_device_decommissioning(self):
        """ Decommission a device successfully """

        if not env.host_string:
            execute(self.test_device_decommissioning,
                    hosts=get_mender_clients())
            return

        adm.check_expected_status("pending", len(get_mender_clients()))
        adm_id = adm.get_devices()[0]["id"]
        device_id = adm.get_devices()[0]["device_id"]

        adm.set_device_status(adm_id, "accepted")

        # wait until inventory is populated
        timeout = time.time() + (60 * 5)

        while time.time() < timeout:
            inventoryJSON = inv.get_devices()

            # we haven't gotten an inventory data yet.
            if len(inventoryJSON) == 0:
                continue

            if "attributes" in inventoryJSON[0]:
                break
            time.sleep(.5)
        else:
            assert False, "never got inventory"

        # get all completed decommission_device WFs for reference
        c = Conductor(get_mender_conductor())
        initial_wfs = c.get_decommission_device_wfs(device_id)

        # decommission actual device
        deviceauth.decommission(device_id)

        # check that the workflow completed successfully
        timeout = time.time() + (60 * 5)
        while time.time() < timeout:
            wfs = c.get_decommission_device_wfs(device_id)
            if wfs['totalHits'] == initial_wfs['totalHits'] + 1:
                break
            else:
                logger.info("waiting for decommission_device workflow...")
                time.sleep(.5)
        else:
            assert False, "decommission_device workflow didn't complete for [%s]" % (
                device_id, )

        # check device gone from inventory
        self.check_gone_from_inventory(device_id)

        # check device gone from deviceauth
        self.check_gone_from_deviceauth(device_id)

        # now check that the device no longer exists in admission
        self.check_gone_from_deviceadm(adm_id, device_id)
    def test_clients_exclusive_to_user(self):
        users = [
            {
              "email": "*****@*****.**",
              "password": "******",
              "username": "******",
              "container": "mender-client-exclusive-1",
              "client_id": "",
              "device_id": ""
            },
            {
               "email": "*****@*****.**",
               "password": "******",
               "username": "******",
               "container": "mender-client-exclusive-2",
               "client_id": "",
               "device_id": ""
            }
        ]

        for user in users:
            auth.set_tenant(user["username"], user["email"], user["password"])

            t = auth.current_tenant["tenant_token"]
            new_tenant_client(user["container"], t)
            adm.accept_devices(1)

            # get the new devices client_id and setting it to the our test parameter
            assert len(inv.get_devices()) == 1
            user["client_id"] = inv.get_devices()[0]["id"]
            user["device_id"] = adm.get_devices()[0]["device_id"]

        for user in users:
            # make sure that the correct number of clients appear for the given tenant
            auth.set_tenant(user["username"], user["email"], user["password"])
            assert len(inv.get_devices()) == 1
            assert inv.get_devices()[0]["id"] == user["client_id"]

        for user in users:
            # wait until inventory is populated
            auth.set_tenant(user["username"], user["email"], user["password"])
            deviceauth.decommission(user["client_id"])
            timeout = time.time() + (60 * 5)
            device_id = user["device_id"]
            while time.time() < timeout:
                    newAdmissions = adm.get_devices()[0]
                    if device_id != newAdmissions["device_id"] \
                       and user["client_id"] != newAdmissions["id"]:
                        logger.info("device [%s] not found in inventory [%s]" % (device_id, str(newAdmissions)))
                        break
                    else:
                        logger.info("device [%s] found in inventory..." % (device_id))
                    time.sleep(.5)
            else:
                assert False, "decommissioned device still available in admissions"
Exemple #6
0
    def test_token_validity(self):
        """ verify that only devices with valid tokens can bootstrap
            successfully to a multitenancy setup """

        wrong_token = "wrong-token"

        def wait_until_bootstrap_attempt():
            if not env.host_string:
                return execute(wait_until_bootstrap_attempt,
                               hosts=get_mender_clients())
            ssh_is_opened()

            for i in range(1, 20):
                with settings(hide('everything'), warn_only=True):
                    out = run(
                        'journalctl -u mender | grep "bootstrapped -> authorize-wait"'
                    )
                    if out.succeeded:
                        return True
                    time.sleep(20 / i)
            return False

        def set_correct_tenant_token(token):
            if not env.host_string:
                return execute(set_correct_tenant_token,
                               token,
                               hosts=get_mender_clients())

            run("sed -i 's/%s/%s/g' /etc/mender/mender.conf" %
                (wrong_token, token))
            run("systemctl restart mender")

        auth.reset_auth_token()
        auth.new_tenant("*****@*****.**", "hunter2hunter2")
        token = auth.current_tenant["tenant_token"]

        # create a new client with an incorrect token set
        new_tenant_client("mender-client", wrong_token)

        if wait_until_bootstrap_attempt():
            for _ in range(5):
                time.sleep(5)
                adm.get_devices(
                    expected_devices=0)  # make sure device not seen
        else:
            pytest.fail("failed to bootstrap device")

        # setting the correct token makes the client visible to the backend
        set_correct_tenant_token(token)
        adm.get_devices(expected_devices=1)
Exemple #7
0
    def test_reject_bootstrap(self):
        """Make sure a rejected device does not perform an upgrade, and that it gets it's auth token removed"""
        if not env.host_string:
            execute(self.test_reject_bootstrap, hosts=get_mender_clients())
            return

        # iterate over devices and reject them
        for device in adm.get_devices():
            adm.set_device_status(device["id"], "rejected")
            logging.info("Rejecting DeviceID: %s" % device["id"])

        adm.check_expected_status("rejected", len(get_mender_clients()))

        try:
            deployment_id, _ = common_update_procedure(
                install_image=conftest.get_valid_image())
        except AssertionError:
            logging.info("Failed to deploy upgrade to rejected device.")
            Helpers.verify_reboot_not_performed()

            # authtoken has been removed from mender-store
            run("strings /data/mender/mender-store | grep -q 'authtoken' || false"
                )

        else:
            pytest.fail("No error while trying to deploy to rejected device")

        # re-accept device after test is done
        adm.accept_devices(1)
    def test_update_image_successful(self,
                                     install_image=conftest.get_valid_image(),
                                     regnerate_image_id=True):
        """
            Perform a successful upgrade, and assert that deployment status/logs are correct.

            A reboot is performed, and running partitions have been swapped.
            Deployment status will be set as successful for device.
            Logs will not be retrieved, and result in 404.
        """
        if not env.host_string:
            execute(self.test_update_image_successful,
                    hosts=get_mender_clients(),
                    install_image=install_image,
                    regnerate_image_id=regnerate_image_id)
            return

        previous_inactive_part = Helpers.get_passive_partition()
        deployment_id, expected_image_id = common_update_proceduce(
            install_image, regnerate_image_id)

        Helpers.verify_reboot_performed()
        assert Helpers.get_active_partition() == previous_inactive_part
        deploy.check_expected_status(deployment_id, "success",
                                     len(get_mender_clients()))

        for d in adm.get_devices():
            deploy.get_logs(d["id"], deployment_id, expected_status=404)

        Helpers.verify_reboot_not_performed()
        assert Helpers.yocto_id_installed_on_machine() == expected_image_id
    def do_test_ok_preauth_and_bootstrap(self):
        """
            Test the happy path from preauthorizing a device to a successful bootstrap.
            Verify that the device/auth set appear correctly in admission API results.
        """
        client = get_mender_clients()[0]

        # we'll use the same pub key for the preauth'd device, so get it
        res = execute(Client.get_pub_key, hosts=client)
        preauth_key = res[client].exportKey()

        # stick an extra newline on the key - this is how a device would send it
        preauth_key += '\n'

        # preauthorize a new device
        preauth_iddata = {"mac": "mac-preauth"}
        # serialize manually to avoid an extra space (id data helper doesn't insert one)
        preauth_iddata_str = "{\"mac\":\"mac-preauth\"}"

        r = adm.preauth(preauth_iddata_str, preauth_key)
        assert r.status_code == 201

        # verify the device appears correctly in api results
        devs = adm.get_devices(2)

        dev_preauth = [d for d in devs if d['status'] == 'preauthorized']
        assert len(dev_preauth) == 1
        dev_preauth = dev_preauth[0]
        assert dev_preauth['device_identity'] == preauth_iddata_str
        assert dev_preauth['key'] == preauth_key

        # make one of the existing devices the preauthorized device
        # by substituting id data and restarting
        res = execute(Client.substitute_id_data, preauth_iddata, hosts=client)
        res = execute(Client.restart, hosts=client)

        # verify api results - after some time the device should be 'accepted'
        for _ in range(120):
            time.sleep(15)
            dev_accepted = adm.get_devices_status(status="accepted", expected_devices=2)
            if len([d for d in dev_accepted if d['status'] == 'accepted']) == 1:
                break


        logging.info("devices: " + str(dev_accepted))
        dev_accepted = [d for d in dev_accepted if d['status'] == 'accepted']
        logging.info("accepted devices: " + str(dev_accepted))

        execute(Client.get_logs, hosts=client)

        assert len(dev_accepted) == 1, "looks like the device was never accepted"
        dev_accepted = dev_accepted[0]
        logging.info("accepted device: " + str(dev_accepted))

        assert dev_accepted['device_identity'] == preauth_iddata_str
        assert dev_accepted['key'] == preauth_key

        # verify device was issued a token
        res = execute(Client.have_authtoken, hosts=client)
        assert res[client]
Exemple #10
0
def update_image_failed(install_image="broken_update.ext4"):
    """
        Perform a upgrade using a broken image (random data)
        The device will reboot, uboot will detect this is not a bootable image, and revert to the previous partition.
        The resulting upgrade will be considered a failure.
    """

    devices_accepted = get_mender_clients()
    original_image_id = Helpers.yocto_id_installed_on_machine()

    previous_active_part = Helpers.get_active_partition()
    deployment_id, _ = common_update_procedure(install_image,
                                               broken_image=True)

    Helpers.verify_reboot_performed()
    assert Helpers.get_active_partition() == previous_active_part

    deploy.check_expected_statistics(deployment_id, "failure",
                                     len(devices_accepted))

    for d in adm.get_devices():
        assert "running rollback image" in deploy.get_logs(
            d["device_id"], deployment_id)

    assert Helpers.yocto_id_installed_on_machine() == original_image_id
    Helpers.verify_reboot_not_performed()

    deploy.check_expected_status("finished", deployment_id)
 def check_gone_from_deviceadm(self, adm_id, device_id):
     admissions = adm.get_devices()[0]
     if device_id != admissions["device_id"] and adm_id != admissions["id"]:
         logger.info(
             "device [%s] successfully removed from admission: [%s]" %
             (device_id, str(admissions)))
     else:
         assert False, "device [%s] not removed from admission: [%s]" % (
             device_id, str(admissions))
Exemple #12
0
    def test_inventory(self):
        """Test that device reports inventory after having bootstrapped."""

        attempts = 3

        while True:
            attempts = attempts - 1
            try:
                inv_json = inv.get_devices()
                adm_json = adm.get_devices()

                adm_ids = [device['device_id'] for device in adm_json]

                assert (len(inv_json) > 0)

                for device in inv_json:
                    try:
                        # Check that admission and inventory agree.
                        assert (device['id'] in adm_ids)

                        attrs = device['attributes']

                        # Check individual attributes.
                        assert (json.loads(
                            '{"name": "network_interfaces", "value": "eth0"}')
                                in attrs)
                        assert (json.loads(
                            '{"name": "hostname", "value": "vexpress-qemu"}')
                                in attrs)
                        assert (json.loads(
                            '{"name": "device_type", "value": "vexpress-qemu"}'
                        ) in attrs)

                        # Check that all known keys are present.
                        keys = [attr['name'] for attr in attrs]
                        expected_keys = [
                            "hostname", "network_interfaces", "cpu_model",
                            "mem_total_kB", "device_type", "ipv4_eth0",
                            "mac_eth0", "mender_client_version",
                            "artifact_name", "kernel"
                        ]
                        assert (sorted(keys) == sorted(expected_keys))

                    except:
                        print("Exception caught, 'device' json: ", device)
                        raise
                break

            except:
                # This may pass only after the client has had some time to
                # report.
                if attempts > 0:
                    time.sleep(5)
                    continue
                else:
                    raise
Exemple #13
0
    def do_test_ok_preauth_and_remove(self):
        """
            Test the removal of a preauthorized auth set, verify it's gone from all API results.
        """
        # preauthorize
        preauth_iddata = "{\"mac\":\"preauth-mac\"}"
        preauth_key = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzogVU7RGDilbsoUt/DdH
VJvcepl0A5+xzGQ50cq1VE/Dyyy8Zp0jzRXCnnu9nu395mAFSZGotZVr+sWEpO3c
yC3VmXdBZmXmQdZqbdD/GuixJOYfqta2ytbIUPRXFN7/I7sgzxnXWBYXYmObYvdP
okP0mQanY+WKxp7Q16pt1RoqoAd0kmV39g13rFl35muSHbSBoAW3GBF3gO+mF5Ty
1ddp/XcgLOsmvNNjY+2HOD5F/RX0fs07mWnbD7x+xz7KEKjF+H7ZpkqCwmwCXaf0
iyYyh1852rti3Afw4mDxuVSD7sd9ggvYMc0QHIpQNkD4YWOhNiE1AB0zH57VbUYG
UwIDAQAB
-----END PUBLIC KEY-----
'''

        r = adm.preauth(preauth_iddata, preauth_key)
        assert r.status_code == 201

        devs = adm.get_devices(2)

        dev_preauth = [d for d in devs if d['device_identity'] == preauth_iddata]
        assert len(dev_preauth) == 1
        dev_preauth = dev_preauth[0]

        # remove from admission
        r = adm.delete_auth_set(dev_preauth['id'])
        assert r.status_code == 204

        # verify removed from admission
        devs = adm.get_devices(1)
        dev_removed = [d for d in devs if d['device_identity'] == preauth_iddata]
        assert len(dev_removed) == 0

        # verify removed from deviceauth
        r = deviceauth.get_device(dev_preauth['id'])
        assert r.status_code == 404

        # verify removed from inventory
        r = inv.get_device(dev_preauth['id'])
        assert r.status_code == 404
    def do_test_fail_preauth_existing(self):
        """
           Test 'conflict' response when an identity data set already exists.
        """
        # wait for the device to appear
        devs = adm.get_devices(1)
        dev = devs[0]

        # try to preauthorize the same id data, new key
        r = adm.preauth(dev['device_identity'], 'preauth-key')
        assert r.status_code == 409
Exemple #15
0
    def accept_devices(self):
        adm.check_expected_status("pending", len(get_mender_clients()))

        # iterate over devices and accept them
        for d in adm.get_devices():
            adm.set_device_status(d["id"], "accepted")
            logging.info("Accepting DeviceID: %s" % d["id"])

        # make sure all devices are accepted
        adm.check_expected_status("accepted", len(get_mender_clients()))

        # print all device ids
        for device in adm.get_devices_status("accepted"):
            logging.info("Accepted DeviceID: %s" % device["id"])
Exemple #16
0
def update_image_successful(
        install_image=conftest.get_valid_image(), regenerate_image_id=True):
    """
        Perform a successful upgrade, and assert that deployment status/logs are correct.

        A reboot is performed, and running partitions have been swapped.
        Deployment status will be set as successful for device.
        Logs will not be retrieved, and result in 404.
    """

    previous_inactive_part = Helpers.get_passive_partition()
    deployment_id, expected_image_id = common_update_procedure(
        install_image, regenerate_image_id)

    Helpers.verify_reboot_performed()

    try:
        assert Helpers.get_active_partition() == previous_inactive_part
    except AssertionError:
        logs = []
        for d in adm.get_devices():
            logs.append(deploy.get_logs(d["device_id"], deployment_id))

        pytest.fail(
            "device did not flip partitions during update, here are the device logs:\n\n %s"
            % (logs))

    deploy.check_expected_statistics(deployment_id, "success",
                                     len(get_mender_clients()))

    for d in adm.get_devices():
        deploy.get_logs(d["device_id"], deployment_id, expected_status=404)

    Helpers.verify_reboot_not_performed()
    assert Helpers.yocto_id_installed_on_machine() == expected_image_id

    deploy.check_expected_status("finished", deployment_id)
Exemple #17
0
    def test_multi_tenancy_setup(self):
        """ Simply make sure we are able to run the multi tenancy setup and
           bootstrap 2 different devices to different tenants """

        auth.reset_auth_token()

        users = [
            {
                "email": "*****@*****.**",
                "password": "******",
                "container": "mender-client"
            },
            {
                "email": "*****@*****.**",
                "password": "******",
                "container": "client2"
            },
        ]

        for user in users:
            auth.new_tenant(user["email"], user["password"])
            t = auth.current_tenant["tenant_token"]
            new_tenant_client(user["container"], t)

            print "sleeping"
            time.sleep(1000)

            adm.accept_devices(1)
            print adm.get_devices()

            self.perform_update()

        # deploy to each device
        for user in users:
            auth.set_tenant(user["email"], user["password"])
            t = auth.current_tenant["tenant_token"]
            adm.accept_devices(1)
Exemple #18
0
    def accept_devices(self):
        adm.check_expected_status("pending", len(get_mender_clients()))

        # iterate over devices and accept them
        for d in adm.get_devices():
            adm.set_device_status(d["id"], "accepted")
            logging.info("Accepting DeviceID: %s" % d["id"])

        # make sure all devices are accepted
        adm.check_expected_status("accepted", len(get_mender_clients()))

        # make sure mender-store contains authtoken
        run("strings /data/mender/mender-store | grep -q 'authtoken'")

        # print all device ids
        for device in adm.get_devices_status("accepted"):
            logging.info("Accepted DeviceID: %s" % device["id"])
Exemple #19
0
    def abort_deployment(self, abort_step=None, mender_performs_reboot=False):
        """
            Trigger a deployment, and cancel it within 15 seconds, make sure no deployment is performed.

            Args:
                mender_performs_reboot: if set to False, a manual reboot is performed and
                                            checks are performed.
                                        if set to True, wait until device is rebooted.
        """
        if not env.host_string:
            execute(self.abort_deployment,
                    abort_step=abort_step,
                    mender_performs_reboot=mender_performs_reboot,
                    hosts=get_mender_clients())
            return

        install_image=conftest.get_valid_image()
        expected_partition = Helpers.get_active_partition()
        expected_image_id = Helpers.yocto_id_installed_on_machine()
        with Helpers.RebootDetector() as reboot:
            deployment_id, _ = common_update_procedure(install_image, verify_status=False)

            if abort_step is not None:
                deploy.check_expected_statistics(deployment_id, abort_step, len(get_mender_clients()))
            deploy.abort(deployment_id)
            deploy.check_expected_statistics(deployment_id, "aborted", len(get_mender_clients()))

            # no deployment logs are sent by the client, is this expected?
            for d in adm.get_devices():
                deploy.get_logs(d["device_id"], deployment_id, expected_status=404)

            if mender_performs_reboot:
                # If Mender performs reboot, we need to wait for it to reboot
                # back into the original filesystem.
                reboot.verify_reboot_performed(number_of_reboots=2)
            else:
                # Else we reboot ourselves, just to make sure that we have not
                # unintentionally switched to the new partition.
                reboot.verify_reboot_not_performed()
                run("( sleep 10 ; reboot ) 2>/dev/null >/dev/null &")
                reboot.verify_reboot_performed()

        assert Helpers.get_active_partition() == expected_partition
        assert Helpers.yocto_id_installed_on_machine() == expected_image_id
        deploy.check_expected_status("finished", deployment_id)
Exemple #20
0
    def ip_to_device_id_map(clients):
        # Get admission data, which includes device identity.
        adm_devices = adm.get_devices(expected_devices=len(clients))

        # Collect identity of each client.
        ret = execute(run, "/usr/share/mender/identity/mender-device-identity", hosts=clients)

        # Calculate device identities.
        identity_to_ip = {}
        for client in clients:
            identity_to_ip[Helpers.identity_script_to_identity_string(ret[client])] = client

        # Match them.
        ip_to_device_id = {}
        for device in adm_devices:
            ip_to_device_id[identity_to_ip[device['device_identity']]] = device['device_id']

        return ip_to_device_id
    def test_reject_bootstrap(self):
        """Make sure a rejected device does not perform an upgrade, and that it gets it's auth token removed"""
        if not env.host_string:
            execute(self.test_reject_bootstrap, hosts=get_mender_clients())
            return

        # iterate over devices and reject them
        for device in adm.get_devices():
            adm.set_device_status(device["id"], "rejected")
            logging.info("Rejecting DeviceID: %s" % device["id"])

        adm.check_expected_status("rejected", len(get_mender_clients()))

        with Helpers.RebootDetector() as reboot:
            try:
                deployment_id, _ = common_update_procedure(
                    install_image=conftest.get_valid_image())
            except AssertionError:
                logging.info("Failed to deploy upgrade to rejected device.")
                reboot.verify_reboot_not_performed()

            else:
                # use assert to fail, so we can get backend logs
                pytest.fail(
                    "no error while trying to deploy to rejected device")
                return

        finished = False
        # wait until auththoken is removed from file
        for _ in range(10):
            with settings(abort_exception=Exception):
                try:
                    run("journalctl -u mender -l -n 3 | grep -q 'authentication request rejected'"
                        )
                except:
                    time.sleep(30)
                else:
                    finished = True
                    break

        adm.accept_devices(1)

        if not finished:
            pytest.fail("failed to remove authtoken from mender-store file")
    def test_unsigned_artifact_fails_deployment(self, standard_setup_with_signed_artifact_client):
        """
            Make sure that an unsigned image fails, and is handled by the backend.
            Notice that this test needs a fresh new version of the backend, since
            we installed a signed image earlier without a verification key in mender.conf
        """
        if not env.host_string:
            execute(self.test_unsigned_artifact_fails_deployment,
                    standard_setup_with_signed_artifact_client,
                    hosts=get_mender_clients())
            return

        deployment_id, _ = common_update_procedure(install_image=conftest.get_valid_image())
        deploy.check_expected_status("finished", deployment_id)
        deploy.check_expected_statistics(deployment_id, "failure", 1)

        for d in adm.get_devices():
            assert "expecting signed artifact, but no signature file found" in \
                deploy.get_logs(d["device_id"], deployment_id)
    def abort_deployment(self, abort_step=None, mender_performs_reboot=False):
        """
            Trigger a deployment, and cancel it within 15 seconds, make sure no deployment is performed.

            Args:
                mender_performs_reboot: if set to False, a manual reboot is performed and
                                            checks are performed.
                                        if set to True, wait until device is rebooted.
        """
        if not env.host_string:
            execute(self.abort_deployment,
                    abort_step=abort_step,
                    mender_performs_reboot=mender_performs_reboot,
                    hosts=get_mender_clients())
            return

        install_image = conftest.get_valid_image()
        expected_partition = Helpers.get_active_partition()
        expected_image_id = Helpers.yocto_id_installed_on_machine()
        token = Helpers.place_reboot_token()
        deployment_id, _ = common_update_procedure(install_image,
                                                   verify_status=False)

        if abort_step is not None:
            deploy.check_expected_statistics(deployment_id, abort_step,
                                             len(get_mender_clients()))
        deploy.abort(deployment_id)
        deploy.check_expected_statistics(deployment_id, "aborted",
                                         len(get_mender_clients()))

        # no deployment logs are sent by the client, is this expected?
        for d in adm.get_devices():
            deploy.get_logs(d["device_id"], deployment_id, expected_status=404)

        if not mender_performs_reboot:
            token.verify_reboot_not_performed()
            run("( sleep 10 ; reboot ) 2>/dev/null >/dev/null &")

        token.verify_reboot_performed()

        assert Helpers.get_active_partition() == expected_partition
        assert Helpers.yocto_id_installed_on_machine() == expected_image_id
        deploy.check_expected_status("finished", deployment_id)
Exemple #24
0
    def do_test_fail_preauth_existing(self):
        """
           Test 'conflict' response when an identity data set already exists.
        """
        # wait for the device to appear
        devs = adm.get_devices(1)
        dev = devs[0]

        # try to preauthorize the same id data, new key
        preauth_key = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzogVU7RGDilbsoUt/DdH
VJvcepl0A5+xzGQ50cq1VE/Dyyy8Zp0jzRXCnnu9nu395mAFSZGotZVr+sWEpO3c
yC3VmXdBZmXmQdZqbdD/GuixJOYfqta2ytbIUPRXFN7/I7sgzxnXWBYXYmObYvdP
okP0mQanY+WKxp7Q16pt1RoqoAd0kmV39g13rFl35muSHbSBoAW3GBF3gO+mF5Ty
1ddp/XcgLOsmvNNjY+2HOD5F/RX0fs07mWnbD7x+xz7KEKjF+H7ZpkqCwmwCXaf0
iyYyh1852rti3Afw4mDxuVSD7sd9ggvYMc0QHIpQNkD4YWOhNiE1AB0zH57VbUYG
UwIDAQAB
-----END PUBLIC KEY-----
'''
        r = adm.preauth(dev['device_identity'], preauth_key)
        assert r.status_code == 409
Exemple #25
0
 def test_decommissioning_post_upgrade(self):
     # assertion error occurs here on decommissioning fail
     for device in adm.get_devices(10):
         deviceauth.decommission(device["device_id"])
    def test_inventory(self):
        """Test that device reports inventory after having bootstrapped."""

        attempts = 10

        while True:
            attempts = attempts - 1
            try:
                inv_json = inv.get_devices()
                adm_json = adm.get_devices()

                adm_ids = [device['device_id'] for device in adm_json]

                assert (len(inv_json) > 0)

                for device in inv_json:
                    try:
                        # Check that admission and inventory agree.
                        assert (device['id'] in adm_ids)

                        attrs = device['attributes']

                        # Check individual attributes.
                        network_interfaces = [
                            elem for elem in attrs
                            if elem['name'] == "network_interfaces"
                        ]
                        assert len(network_interfaces) == 1
                        network_interfaces = network_interfaces[0]
                        if type(network_interfaces['value']) is str:
                            assert any(network_interfaces['value'] == iface
                                       for iface in ["eth0", "enp0s3"])
                        else:
                            assert any(iface in network_interfaces['value']
                                       for iface in ["eth0", "enp0s3"])
                        assert (json.loads(
                            '{"name": "hostname", "value": "%s"}' %
                            conftest.machine_name) in attrs)
                        assert (json.loads(
                            '{"name": "device_type", "value": "%s"}' %
                            conftest.machine_name) in attrs)

                        # Check that all known keys are present.
                        keys = [str(attr['name']) for attr in attrs]
                        expected_keys = [
                            "hostname",
                            "network_interfaces",
                            "cpu_model",
                            "mem_total_kB",
                            "device_type",
                            ["ipv4_enp0s3", "ipv6_enp0s3",
                             "ipv4_eth0"],  # Multiple possibilities
                            ["mac_enp0s3", "mac_eth0"],
                            "mender_client_version",
                            "artifact_name",
                            "kernel"
                        ]
                        for key in expected_keys:
                            if type(key) is list:
                                assert any([subkey in keys for subkey in key])
                            else:
                                assert key in keys

                    except:
                        print("Exception caught, 'device' json: ", device)
                        raise
                break

            except:
                # This may pass only after the client has had some time to
                # report.
                if attempts > 0:
                    time.sleep(5)
                    continue
                else:
                    raise
    def test_device_decommissioning(self, standard_setup_one_client):
        """ Decommission a device successfully """

        if not env.host_string:
            execute(self.test_device_decommissioning,
                    standard_setup_one_client,
                    hosts=get_mender_clients())
            return

        adm.check_expected_status("pending", len(get_mender_clients()))
        adm_id = adm.get_devices()[0]["id"]
        device_id = adm.get_devices()[0]["device_id"]

        adm.set_device_status(adm_id, "accepted")

        # wait until inventory is populated
        timeout = time.time() + (60 * 5)
        while time.time() < timeout:
            inventoryJSON = inv.get_devices()
            if "attributes" in inventoryJSON[0]:
                break
            time.sleep(.5)
        else:
            pytest.fail("never got inventory")

        # decommission actual device
        deviceauth.decommission(device_id)

        # now check that the device no longer exists in admissions
        timeout = time.time() + (60 * 5)
        while time.time() < timeout:
            newAdmissions = adm.get_devices()[0]
            if device_id != newAdmissions["device_id"] \
               and adm_id != newAdmissions["id"]:
                logger.info("device [%s] not found in inventory [%s]" %
                            (device_id, str(newAdmissions)))
                break
            else:
                logger.info("device [%s] found in inventory..." % (device_id))
            time.sleep(.5)
        else:
            pytest.fail("decommissioned device still available in admissions")

        # make sure a deployment to the decommissioned device fails
        try:
            time.sleep(
                120
            )  # sometimes deployment microservice hasn't removed the device yet
            logger.info("attempting to deploy to decommissioned device: %s" %
                        (device_id))
            deployment_id, _ = common_update_procedure(
                install_image=conftest.get_valid_image(),
                devices=[device_id],
                verify_status=False)
        except AssertionError:
            logging.info("Failed to deploy upgrade to rejected device")
            # authtoken has been removed
            run("strings /data/mender/mender-store | grep -q 'authtoken' || false"
                )
        else:
            pytest.fail("No error while trying to deploy to rejected device")
        """
            at this point, the device will re-appear, since it's actually still
            online, and not actually decomissioned
        """
        adm.check_expected_status("pending", len(get_mender_clients()))

        # make sure inventory is empty as well
        assert len(inv.get_devices()) == 0
Exemple #28
0
    ret = subprocess.call(["docker-compose",
                           "-p", "testprod",
                           "-f", "docker-compose.yml",
                           "-f", "docker-compose.storage.minio.yml",
                           "-f", "./production-testing-env.yml",
                           "up", "-d"],
                          cwd="../")

    assert ret == 0, "failed to start docker-compose"

if args.deploy:
    # create account for management api
    auth.get_auth_token()

    # wait for 10 devices to be available
    devices = adm.get_devices(10)
    assert len(devices) == 10

    # accept all devices
    for d in devices:
        adm.set_device_status(d["id"], "accepted")

    # make sure artifact tool in current workdir is being used
    os.environ["PATH"] = os.path.dirname(os.path.realpath(__file__)) + "/downloaded-tools" + os.pathsep + os.environ["PATH"]

    # perform upgrade
    devices_to_update = list(set([device["device_id"] for device in adm.get_devices_status("accepted", expected_devices=10)]))
    deployment_id, artifact_id = common_update_procedure("core-image-full-cmdline-vexpress-qemu.ext4", device_type="test", devices=devices_to_update)

    print("deployment_id=%s" % deployment_id)
    print("artifact_id=%s" % artifact_id)