def test_multi_tenancy_deployment_aborting(self, enterprise_no_client, valid_image): """ 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": "******", "username": "******", "container": "mender-client-deployment-aborting-1", }] for user in users: auth.new_tenant(user["username"], user["email"], user["password"]) t = auth.current_tenant["tenant_token"] enterprise_no_client.new_tenant_client(user["container"], t) auth_v2.accept_devices(1) for user in users: deployment_id, _ = common_update_procedure(valid_image) deploy.abort(deployment_id) deploy.check_expected_statistics(deployment_id, "aborted", 1) mender_device = MenderDevice( enterprise_no_client.get_mender_client_by_container_name( user["container"])) mender_device.run( 'journalctl -u %s | grep "deployment aborted at the backend"' % mender_device.get_client_service_name(), wait=600, )
def setup_ent_compat(request): env = container_factory.get_compatibility_setup(enterprise=True) request.addfinalizer(env.teardown) env.setup() env.tenant = create_org( "Mender", "*****@*****.**", "correcthorse", containers_namespace=env.name, container_manager=env, ) env.user = env.tenant.users[0] env.populate_clients(tenant_token=env.tenant.tenant_token) clients = env.get_mender_clients() assert len(clients) > 0, "Failed to setup clients" env.devices = [] for client in clients: dev = MenderDevice(client) dev.ssh_is_opened() env.devices.append(dev) return env
def setup_test_filetransfer_limits(self, standard_setup_one_client): """Tests the file transfer features""" # accept the device devauth.accept_devices(1) # list of devices devices = list( set([ device["id"] for device in devauth.get_devices_status("accepted") ])) assert 1 == len(devices) # wait for the device to connect via websocket auth = authentication.Authentication() wait_for_connect(auth, devices[0]) # device ID and auth token devid = devices[0] authtoken = auth.get_auth_token() mender_device = MenderDevice( standard_setup_one_client.get_mender_clients()[0]) mender_device.ssh_is_opened() return mender_device, devid, auth
def __create_tenant_and_container(self, container_manager): auth.new_tenant("admin", "*****@*****.**", "hunter2hunter2") token = auth.current_tenant["tenant_token"] container_manager.new_tenant_client("tenant-container", token) mender_device = MenderDevice(container_manager.get_mender_clients()[0]) mender_device.ssh_is_opened() container_manager.device = mender_device
def __create_tenant_and_container(self, container_manager): uuidv4 = str(uuid.uuid4()) auth.new_tenant( "test.mender.io-" + uuidv4, "some.user+" + uuidv4 + "@example.com", "hunter2hunter2", ) token = auth.current_tenant["tenant_token"] container_manager.new_tenant_client("tenant-container", token) mender_device = MenderDevice(container_manager.get_mender_clients()[0]) mender_device.ssh_is_opened() container_manager.device = mender_device
def enterprise_two_clients_bootstrapped_with_gateway(request): env = container_factory.get_enterprise_setup_with_gateway(num_clients=0) request.addfinalizer(env.teardown) env.setup() reset_mender_api(env) tenant = create_tenant(env) tenant = create_tenant(env) new_tenant_client(env, "mender-client-1", tenant["tenant_token"], network="mender_local") new_tenant_client(env, "mender-client-2", tenant["tenant_token"], network="mender_local") env.device_group.ssh_is_opened() env.start_tenant_mender_gateway(tenant["tenant_token"]) env.device_gateway = MenderDevice( env.get_mender_gateways(network="mender").pop()) env.device_gateway.ssh_is_opened() devauth_tenant = DeviceAuthV2(env.auth) # Three devices: two client devices and the gateway device (which also runs mender client) devauth_tenant.accept_devices(3) devices = devauth_tenant.get_devices_status("accepted") assert 3 == len(devices) return env
def new_tenant_client(test_env, name: str, tenant: str, docker: bool = False, network: str = "mender") -> MenderDevice: """Create new Mender client in the test environment with the given name for the given tenant. The passed test_env must implement new_tenant_client and/or new_tenant_docker_client. This helper attaches the recently created Mender client to the test environment, so that systemd logs can be printed on test failures. """ pre_existing_clients = set(test_env.get_mender_clients(network=network)) if docker: test_env.new_tenant_docker_client(name, tenant) else: test_env.new_tenant_client(name, tenant) all_clients = set(test_env.get_mender_clients(network=network)) new_client = all_clients - pre_existing_clients assert len(new_client) == 1 device = MenderDevice(new_client.pop()) if hasattr(test_env, "device_group"): test_env.device_group.append(device) else: test_env.device = device test_env.device_group = MenderDeviceGroup( test_env.get_mender_clients(network=network)) return device
def connected_device(env): uuidv4 = str(uuid.uuid4()) tname = "test.mender.io-{}".format(uuidv4) email = "some.user+{}@example.com".format(uuidv4) u = User("", email, "whatsupdoc") cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org(tname, u.name, u.pwd, plan="enterprise") update_tenant( tid, addons=["troubleshoot"], container_manager=get_container_manager(), ) tenant = cli.get_tenant(tid) tenant = json.loads(tenant) ttoken = tenant["tenant_token"] auth = Authentication(name="enterprise-tenant", username=u.name, password=u.pwd) auth.create_org = False auth.reset_auth_token() devauth = DeviceAuthV2(auth) env.new_tenant_client("mender-client", ttoken) device = MenderDevice(env.get_mender_clients()[0]) devauth.accept_devices(1) devices = devauth.get_devices_status("accepted") assert 1 == len(devices) wait_for_connect(auth, devices[0]["id"]) devconn = DeviceConnect(auth, devauth) return device, devconn
def setup_ent_mtls(request): env = container_factory.get_mtls_setup() request.addfinalizer(env.teardown) env.setup() mtls_username = "******" mtls_password = "******" env.tenant = create_org( "Mender", mtls_username, mtls_password, containers_namespace=env.name, container_manager=env, ) env.user = env.tenant.users[0] env.start_mtls_ambassador() reset_mender_api(env) auth.username = mtls_username auth.password = mtls_password auth.multitenancy = True auth.current_tenant = env.tenant env.stop_api_gateway() # start a new mender client env.new_mtls_client("mender-client", env.tenant.tenant_token) env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() env.start_api_gateway() return env
def test_filetransfer(self, enterprise_no_client): u = User("", "*****@*****.**", "whatsupdoc") cli = CliTenantadm(containers_namespace=enterprise_no_client.name) tid = cli.create_org("os-tenant", u.name, u.pwd, plan="os") # FT requires "troubleshoot" update_tenant( tid, addons=["troubleshoot"], container_manager=get_container_manager(), ) tenant = cli.get_tenant(tid) tenant = json.loads(tenant) auth = authentication.Authentication(name="os-tenant", username=u.name, password=u.pwd) auth.create_org = False auth.reset_auth_token() devauth_tenant = DeviceAuthV2(auth) enterprise_no_client.new_tenant_client("configuration-test-container", tenant["tenant_token"]) mender_device = MenderDevice( enterprise_no_client.get_mender_clients()[0]) mender_device.ssh_is_opened() devauth_tenant.accept_devices(1) devices = list( set([ device["id"] for device in devauth_tenant.get_devices_status("accepted") ])) assert 1 == len(devices) wait_for_connect(auth, devices[0]) authtoken = auth.get_auth_token() super().test_filetransfer(devices[0], authtoken, content_assertion="ServerURL")
def setup_os_compat(request): env = container_factory.get_compatibility_setup() request.addfinalizer(env.teardown) env.setup() env.user = create_user( "*****@*****.**", "correcthorse", containers_namespace=env.name ) env.populate_clients() clients = env.get_mender_clients() assert len(clients) > 0, "Failed to setup clients" env.devices = [] for client in clients: dev = MenderDevice(client) dev.ssh_is_opened() env.devices.append(dev) return env
def standard_setup_one_client_bootstrapped_with_gateway(request): env = container_factory.get_standard_setup_with_gateway(num_clients=1) request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice( env.get_mender_clients(network="mender_local")[0]) env.device.ssh_is_opened() env.device_gateway = MenderDevice( env.get_mender_gateways(network="mender")[0]) env.device_gateway.ssh_is_opened() reset_mender_api(env) # Two devices: the client device and the gateway device (which also runs mender client) devauth.accept_devices(2) env.auth = auth return env
def standard_setup_one_client(request): env = container_factory.getStandardSetup(num_clients=1) request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) return env
def standard_setup_one_client_bootstrapped_impl(request): env = container_factory.getStandardSetup(num_clients=1) request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) devauth.accept_devices(1) return env
def standard_setup_one_docker_client_bootstrapped(request): env = container_factory.getDockerClientSetup() request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) auth_v2.accept_devices(1) return env
def standard_setup_with_short_lived_token(request): env = container_factory.getShortLivedTokenSetup() request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) auth.reset_auth_token() auth_v2.accept_devices(1) return env
def setup_failover(request): env = container_factory.getFailoverServerSetup() request.addfinalizer(env.teardown) env.setup() reset_mender_api(env) env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() auth.reset_auth_token() auth_v2.accept_devices(1) return env
def standard_setup_with_signed_artifact_client(request): env = container_factory.getSignedArtifactClientSetup() request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) auth.reset_auth_token() devauth.accept_devices(1) return env
def setup_mender_connect_1_0(self, request): self.env = container_factory.getMenderClient_2_5() request.addfinalizer(self.env.teardown) self.env.setup() self.env.populate_clients(replicas=1) clients = self.env.get_mender_clients() assert len(clients) == 1, "Failed to setup client" self.env.device = MenderDevice(clients[0]) self.env.device.ssh_is_opened() reset_mender_api(self.env) yield self.env
def _make_tenant(self, plan, env): tname = "tenant-{}".format(plan) email = "user@{}.com".format(tname) cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org(tname, email, "correcthorse", plan) tenant = cli.get_tenant(tid) tenant = json.loads(tenant) ttoken = tenant["tenant_token"] # the cli now sets all addons to 'enabled' - # disable them for initial 'all disabled' state update_tenant( tenant["id"], addons=[], container_manager=get_container_manager(), ) auth = Authentication(name=tname, username=email, password="******") auth.create_org = False auth.reset_auth_token() devauth = DeviceAuthV2(auth) env.new_tenant_client("test-container-{}".format(plan), ttoken) device = MenderDevice(env.get_mender_clients()[0]) devauth.accept_devices(1) devices = list( set([ device["id"] for device in devauth.get_devices_status("accepted") ])) assert 1 == len(devices) tenant = Tenant(tname, tid, ttoken) u = User("", email, "correcthorse") tenant.users.append(u) tenant.device = device tenant.device_id = devices[0] tenant.auth = auth tenant.devauth = devauth return tenant
def test_multi_tenancy_deployment(self, enterprise_no_client, valid_image): """ 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": "******", "username": "******", "container": "mender-client-deployment-1", "fail": False, }, { "email": "*****@*****.**", "password": "******", "username": "******", "container": "mender-client-deployment-2", "fail": True, }, ] for user in users: auth.new_tenant(user["username"], user["email"], user["password"]) t = auth.current_tenant["tenant_token"] enterprise_no_client.new_tenant_client(user["container"], t) auth_v2.accept_devices(1) for user in users: auth.new_tenant(user["username"], user["email"], user["password"]) assert len(inv.get_devices()) == 1 mender_device = MenderDevice( enterprise_no_client.get_mender_client_by_container_name( user["container"])) host_ip = enterprise_no_client.get_virtual_network_host_ip() if user["fail"]: update_image_failed(mender_device, host_ip) else: update_image( mender_device, host_ip, install_image=valid_image, skip_reboot_verification=True, )
def docker_env(self, request): env = container_factory.get_mender_client_2_5() request.addfinalizer(env.teardown) env.setup() env.populate_clients(replicas=1) clients = env.get_mender_clients() assert len(clients) == 1, "Failed to setup client" env.device = MenderDevice(clients[0]) env.device.ssh_is_opened() reset_mender_api(env) devauth.accept_devices(1) env.devconnect = devconnect yield env
def setup_with_legacy_client(request): # The legacy 1.7.0 client was only built for qemux86-64, so skip tests using # it when running other platforms. if conftest.machine_name != "qemux86-64": pytest.skip("Test only works with qemux86-64, and this is %s" % conftest.machine_name) env = container_factory.getLegacyClientSetup() request.addfinalizer(env.teardown) env.setup() env.device = MenderDevice(env.get_mender_clients()[0]) env.device.ssh_is_opened() reset_mender_api(env) auth_v2.accept_devices(1) return env
def standard_setup_two_clients_bootstrapped_with_gateway(request): env = container_factory.getStandardSetupWithGateway(num_clients=2) request.addfinalizer(env.teardown) env.setup() env.device_group = MenderDeviceGroup( env.get_mender_clients(network="mender_local")) env.device_group.ssh_is_opened() env.device_gateway = MenderDevice( env.get_mender_gateways(network="mender")[0]) env.device_gateway.ssh_is_opened() reset_mender_api(env) # Three devices: two client devices and the gateway device (which also runs mender client) devauth.accept_devices(3) env.auth = auth return env
def prepare_env(self, env, user_name): u = User("", user_name, "whatsupdoc") cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org("monitor-tenant", u.name, u.pwd, plan="enterprise") # at the moment we do not have a notion of a monitor add-on in the # backend, but this will be needed here, see MEN-4809 # update_tenant( # tid, addons=["monitor"], container_manager=get_container_manager(), # ) tenant = cli.get_tenant(tid) tenant = json.loads(tenant) auth = authentication.Authentication( name="monitor-tenant", username=u.name, password=u.pwd ) auth.create_org = False auth.reset_auth_token() devauth_tenant = DeviceAuthV2(auth) env.new_tenant_client("configuration-test-container", tenant["tenant_token"]) env.device = mender_device = MenderDevice(env.get_mender_clients()[0]) mender_device.ssh_is_opened() devauth_tenant.accept_devices(1) devices = list( set( [ device["id"] for device in devauth_tenant.get_devices_status("accepted") ] ) ) assert 1 == len(devices) devid = devices[0] authtoken = auth.get_auth_token() return devid, authtoken, auth, mender_device
def connected_device(self, env): u = User("", "*****@*****.**", "whatsupdoc") cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org("enterprise-tenant", u.name, u.pwd, "enterprise") update_tenant( tid, addons=["troubleshoot"], container_manager=get_container_manager(), ) tenant = cli.get_tenant(tid) tenant = json.loads(tenant) ttoken = tenant["tenant_token"] auth = Authentication(name="enterprise-tenant", username=u.name, password=u.pwd) auth.create_org = False auth.reset_auth_token() devauth = DeviceAuthV2(auth) env.new_tenant_client("configuration-test-container", ttoken) device = MenderDevice(env.get_mender_clients()[0]) devauth.accept_devices(1) devices = list( set([ device["id"] for device in devauth.get_devices_status("accepted") ])) assert 1 == len(devices) wait_for_connect(auth, devices[0]) devconn = DeviceConnect(auth, devauth) return device, devconn
def test_configuration(self, enterprise_no_client): """Tests the deployment and reporting of the configuration The tests set the configuration of a device and verifies the new configuration is reported back to the back-end. """ env = enterprise_no_client # Create an enterprise plan tenant u = User("", "*****@*****.**", "whatsupdoc") cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org("enterprise-tenant", u.name, u.pwd, plan="enterprise") tenant = cli.get_tenant(tid) tenant = json.loads(tenant) ttoken = tenant["tenant_token"] logger.info(f"tenant json: {tenant}") tenant = Tenant("tenant", tid, ttoken) tenant.users.append(u) # And authorize the user to the tenant account auth = Authentication(name="enterprise-tenant", username=u.name, password=u.pwd) auth.create_org = False auth.reset_auth_token() devauth_tenant = DeviceAuthV2(auth) # Add a client to the tenant enterprise_no_client.new_tenant_client("configuration-test-container", tenant.tenant_token) mender_device = MenderDevice( enterprise_no_client.get_mender_clients()[0]) mender_device.ssh_is_opened() devauth_tenant.accept_devices(1) # list of devices devices = list( set([ device["id"] for device in devauth_tenant.get_devices_status("accepted") ])) assert 1 == len(devices) wait_for_connect(auth, devices[0]) # set and verify the device's configuration # retry to skip possible race conditions between update poll and update trigger for _ in redo.retrier(attempts=3, sleeptime=1): set_and_verify_config({"key": "value"}, devices[0], auth.get_auth_token()) forced = was_update_forced(mender_device) if forced: return assert False, "the update check was never triggered"
def test_token_validity(self, enterprise_no_client): """ verify that only devices with valid tokens can bootstrap successfully to a multitenancy setup """ wrong_token = "wrong-token" auth.reset_auth_token() auth.new_tenant("admin", "*****@*****.**", "hunter2hunter2") token = auth.current_tenant["tenant_token"] # create a new client with an incorrect token set enterprise_no_client.new_tenant_client("mender-client", wrong_token) mender_device = MenderDevice(enterprise_no_client.get_mender_clients()[0]) mender_device.ssh_is_opened() client_service_name = mender_device.get_client_service_name() mender_device.run( 'journalctl -u %s | grep "authentication request rejected server error message: Unauthorized"' % client_service_name, wait=70, ) for _ in range(5): time.sleep(5) devauth.get_devices(expected_devices=0) # make sure device not seen # setting the correct token makes the client visible to the backend mender_device.run( "sed -i 's/%s/%s/g' /etc/mender/mender.conf" % (wrong_token, token) ) mender_device.run("systemctl restart %s" % client_service_name) devauth.get_devices(expected_devices=1)
def test_deployment_retry_failed_update(self, enterprise_no_client): """Tests that a client installing a deployment created with a retry limit This is done through setting up a new tenant on the enterprise plan, with a device bootstrapped to the tenant. Then an Artifact is created which contains a script, for the script update module. The script will store a retry-count in a temp-file on the device, and fail, as long as the retry-count < 3. On the third go, the script will, pass, and along with it, so should the update. """ env = enterprise_no_client # Create an enterprise plan tenant u = User("", "*****@*****.**", "whatsupdoc") cli = CliTenantadm(containers_namespace=env.name) tid = cli.create_org("enterprise-tenant", u.name, u.pwd, plan="enterprise") tenant = cli.get_tenant(tid) tenant = json.loads(tenant) ttoken = tenant["tenant_token"] logger.info(f"tenant json: {tenant}") tenant = Tenant("tenant", tid, ttoken) tenant.users.append(u) # And authorize the user to the tenant account auth = Authentication(name="enterprise-tenant", username=u.name, password=u.pwd) auth.create_org = False auth.reset_auth_token() devauth = DeviceAuthV2(auth) deploy = Deployments(auth, devauth) # Add a client to the tenant enterprise_no_client.new_tenant_client("retry-test-container", tenant.tenant_token) devauth.accept_devices(1) device = MenderDevice(env.get_mender_clients()[0]) with tempfile.NamedTemporaryFile() as tf: artifact = make_script_artifact("retry-artifact", conftest.machine_name, tf.name) deploy.upload_image(artifact) devices = list( set([ device["id"] for device in devauth.get_devices_status("accepted") ])) assert len(devices) == 1 deployment_id = deploy.trigger_deployment( "retry-test", artifact_name="retry-artifact", devices=devices, retries=3) logger.info(deploy.get_deployment(deployment_id)) # Now just wait for the update to succeed deploy.check_expected_statistics(deployment_id, "success", 1) deploy.check_expected_status("finished", deployment_id) # Verify the update was actually installed on the device out = device.run("mender -show-artifact").strip() assert out == "retry-artifact" # Verify the number of attempts taken to install the update out = device.run("cat /tmp/retry-attempts").strip() assert out == "3"
def test_update_provides_depends(self, enterprise_no_client): """ Perform two consecutive updates, the first adds virtual provides to the artifact and the second artifact depends on these provides. """ # Create tenant user auth.reset_auth_token() auth.new_tenant("admin", "*****@*****.**", "secret-service", "enterprise") token = auth.current_tenant["tenant_token"] # Create client setup with tenant token enterprise_no_client.new_tenant_docker_client("mender-client", token) mender_device = MenderDevice( enterprise_no_client.get_mender_clients()[0]) host_ip = enterprise_no_client.get_virtual_network_host_ip() # Wait for ssh to be open mender_device.ssh_is_opened() # Check that the device has authorized with the backend. devauth.get_devices(expected_devices=1) devauth.accept_devices(1) assert len(devauth.get_devices_status("accepted")) == 1 # Update client with and artifact with custom provides def prepare_provides_artifact(artifact_file, artifact_id): cmd = ( # Package tests folder in the artifact, just a random folder. "directory-artifact-gen -o %s -n %s -t docker-client -d /tmp/test_file_update_module tests -- --provides rootfs-image.directory.foo:bar" % (artifact_file, artifact_id)) logger.info("Executing: " + cmd) subprocess.check_call(cmd, shell=True) return artifact_file deployment_id, _ = common_update_procedure( make_artifact=prepare_provides_artifact, # We use verify_status=False, because update module updates are so # quick that it sometimes races past the 'inprogress' status without # the test framework having time to register it. That's not really # the part we're interested in though, so just skip it. verify_status=False, ) deploy.check_expected_status("finished", deployment_id) # Issue another update which depends on the custom provides def prepare_depends_artifact(artifact_file, artifact_id): cmd = ( # Package tests folder in the artifact, just a random folder. "directory-artifact-gen -o %s -n %s -t docker-client -d /tmp/test_file_update_module tests -- --depends rootfs-image.directory.foo:bar" % (artifact_file, artifact_id)) logger.info("Executing: " + cmd) subprocess.check_call(cmd, shell=True) return artifact_file deployment_id, _ = common_update_procedure( make_artifact=prepare_depends_artifact, verify_status=False, ) deploy.check_expected_status("finished", deployment_id) # Issue a third update with the same update as previous, this time # with insufficient provides -> no artifact status deployment_id, _ = common_update_procedure( make_artifact=prepare_depends_artifact, verify_status=False) # Retry for at most 60 seconds checking for deployment status update stat = None noartifact = 0 for i in range(60): time.sleep(1) stat = deploy.get_statistics(deployment_id) if stat.get("noartifact") == 1: noartifact = 1 break assert stat is not None assert noartifact == 1