def test_takes_lock_when_running(self): clock = Clock() deferToThread = self.patch(boot_images, "deferToThread") deferToThread.return_value = pause(1, clock) # Lock is acquired when import is started. import_boot_images(sentinel.sources, factory.make_simple_http_url()) self.assertTrue(concurrency.boot_images.locked) # Lock is released once the download is done. clock.advance(1) self.assertFalse(concurrency.boot_images.locked)
def test_restarts_maas_rackd_service(self): url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertThat( self.mock_call_and_check, MockCallsMatch( call(["systemctl", "stop", "maas-rackd"]), call(["systemctl", "enable", "maas-rackd"]), call(["systemctl", "start", "maas-rackd"]), ), )
def test__prompts_user_for_secret(self): url = factory.make_simple_http_url() expected_previous_value = factory.make_bytes() set_shared_secret_on_filesystem(expected_previous_value) InstallSharedSecretScript_mock = self.patch( register_command, "InstallSharedSecretScript") args = self.make_args(url=url, secret=None) register_command.run(args) observed = get_shared_secret_from_filesystem() self.expectThat(expected_previous_value, Equals(observed)) self.expectThat(InstallSharedSecretScript_mock.run, MockCalledOnceWith(args))
def test_download_is_initiated_in_new_thread(self): clock = Clock() maas_meta_last_modified = self.patch( tftppath, "maas_meta_last_modified" ) one_week = timedelta(minutes=15).total_seconds() maas_meta_last_modified.return_value = clock.seconds() - one_week http_proxy = factory.make_simple_http_url() https_proxy = factory.make_simple_http_url() rpc_client = Mock() client_call = Mock() client_call.side_effect = [ defer.succeed(dict(sources=sentinel.sources)), defer.succeed( dict(http=urlparse(http_proxy), https=urlparse(https_proxy)) ), ] rpc_client.getClientNow.return_value = defer.succeed(client_call) rpc_client.maas_url = factory.make_simple_http_url() # We could patch out 'import_boot_images' instead here but I # don't do that for 2 reasons: # 1. It requires spinning the reactor again before being able to # test the result. # 2. It means there's no thread to clean up after the test. deferToThread = self.patch(boot_images, "deferToThread") deferToThread.return_value = defer.succeed(None) service = ImageDownloadService(rpc_client, sentinel.tftp_root, clock) service.startService() self.assertThat( deferToThread, MockCalledOnceWith( _run_import, sentinel.sources, rpc_client.maas_url, http_proxy=http_proxy, https_proxy=https_proxy, ), )
def test_update_last_image_sync_end_to_end_import_not_performed(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateLastImageSync) protocol.UpdateLastImageSync.return_value = succeed({}) self.addCleanup((yield connecting)) self.patch_autospec(boot_resources, 'import_images') boot_resources.import_images.return_value = False sources, hosts = make_sources() maas_url = factory.make_simple_http_url() yield boot_images.import_boot_images(sources, maas_url) self.assertThat( boot_resources.import_images, MockCalledOnceWith(fix_sources_for_cluster(sources, maas_url))) self.assertThat(protocol.UpdateLastImageSync, MockNotCalled())
def test_process_node_tags_integration(self): self.useFixture( ClusterConfigurationFixture( maas_url=factory.make_simple_http_url())) get_hw_system1 = factory.make_response( http.client.OK, bson.BSON.encode({"lshw": b"<node />"}), "application/bson", ) get_hw_system2 = factory.make_response( http.client.OK, bson.BSON.encode({"lshw": b"<not-node />"}), "application/bson", ) mock_get = self.patch(MAASClient, "get") mock_get.side_effect = [get_hw_system1, get_hw_system2] mock_post = self.patch(MAASClient, "post") mock_post.return_value = factory.make_response( http.client.OK, b'{"added": 1, "removed": 1}', "application/json") tag_name = factory.make_name("tag") tag_definition = "//lshw:node" tag_nsmap = {"lshw": "lshw"} rack_id = factory.make_name("rack") tags.process_node_tags( rack_id, [{ "system_id": "system-id1" }, { "system_id": "system-id2" }], tag_name, tag_definition, tag_nsmap, self.fake_client(), ) tag_url = "/MAAS/api/2.0/tags/%s/" % (tag_name, ) self.assertThat( mock_post, MockCalledOnceWith( tag_url, as_json=True, op="update_nodes", rack_controller=rack_id, definition=tag_definition, add=["system-id1"], remove=["system-id2"], ), )
def test__add_to_waiting_if_lock_already_held(self): yield concurrency.boot_images.acquire() deferToThread = self.patch(boot_images, 'deferToThread') deferToThread.return_value = defer.succeed(None) maas_url = factory.make_simple_http_url() d = import_boot_images(sentinel.sources, maas_url) self.assertEqual(1, len(concurrency.boot_images.waiting)) concurrency.boot_images.release() yield d self.assertThat( deferToThread, MockCalledOnceWith(_run_import, sentinel.sources, maas_url, http_proxy=None, https_proxy=None))
def test___prompts_user_for_url(self): expected_url = factory.make_simple_http_url() secret = factory.make_bytes() stdin = self.patch(register_command, "stdin") stdin.isatty.return_value = True input = self.patch(register_command, "input") input.return_value = expected_url register_command.run(self.make_args(url=None, secret=to_hex(secret))) with ClusterConfiguration.open() as config: observed = config.maas_url self.expectThat(input, MockCalledOnceWith("MAAS region controller URL: ")) self.expectThat([expected_url], Equals(observed))
def test_update_last_image_sync_always_updated(self): get_maas_id = self.patch(boot_images, "get_maas_id") get_maas_id.return_value = factory.make_string() getRegionClient = self.patch(boot_images, "getRegionClient") _run_import = self.patch_autospec(boot_images, '_run_import') _run_import.return_value = False maas_url = factory.make_simple_http_url() yield boot_images._import_boot_images(sentinel.sources, maas_url) self.assertThat( _run_import, MockCalledOnceWith(sentinel.sources, maas_url, None, None)) self.assertThat(getRegionClient, MockCalledOnceWith()) self.assertThat(get_maas_id, MockCalledOnceWith()) client = getRegionClient.return_value self.assertThat( client, MockCalledOnceWith(UpdateLastImageSync, system_id=get_maas_id()))
def test_never_more_than_one_waiting(self): yield concurrency.boot_images.acquire() deferToThread = self.patch(boot_images, "deferToThread") deferToThread.return_value = defer.succeed(None) maas_url = factory.make_simple_http_url() d = import_boot_images(sentinel.sources, maas_url) self.assertIsNone(import_boot_images(sentinel.sources, maas_url)) self.assertEqual(1, len(concurrency.boot_images.waiting)) concurrency.boot_images.release() yield d self.assertThat( deferToThread, MockCalledOnceWith( _run_import, sentinel.sources, maas_url, http_proxy=None, https_proxy=None, ), )
def test_process_node_tags_integration(self): self.useFixture( ClusterConfigurationFixture( maas_url=factory.make_simple_http_url())) get_hw_system1 = factory.make_response( http.client.OK, bson.BSON.encode({'lshw': b'<node />'}), 'application/bson', ) get_hw_system2 = factory.make_response( http.client.OK, bson.BSON.encode({'lshw': b'<not-node />'}), 'application/bson', ) mock_get = self.patch(MAASClient, 'get') mock_get.side_effect = [get_hw_system1, get_hw_system2] mock_post = self.patch(MAASClient, 'post') mock_post.return_value = factory.make_response( http.client.OK, b'{"added": 1, "removed": 1}', 'application/json', ) tag_name = factory.make_name('tag') tag_definition = '//lshw:node' tag_nsmap = {"lshw": "lshw"} rack_id = factory.make_name('rack') tags.process_node_tags(rack_id, [{ "system_id": "system-id1" }, { "system_id": "system-id2" }], tag_name, tag_definition, tag_nsmap, self.fake_client()) tag_url = '/MAAS/api/2.0/tags/%s/' % (tag_name, ) self.assertThat( mock_post, MockCalledOnceWith(tag_url, as_json=True, op='update_nodes', rack_controller=rack_id, definition=tag_definition, add=['system-id1'], remove=['system-id2']))
def test_update_last_image_sync_end_to_end(self): get_maas_id = self.patch(boot_images, "get_maas_id") get_maas_id.return_value = factory.make_string() fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateLastImageSync) protocol.UpdateLastImageSync.return_value = succeed({}) self.addCleanup((yield connecting)) self.patch_autospec(boot_resources, "import_images") boot_resources.import_images.return_value = True sources, hosts = make_sources() maas_url = factory.make_simple_http_url() yield boot_images.import_boot_images(sources, maas_url) self.assertThat( boot_resources.import_images, MockCalledOnceWith(fix_sources_for_cluster(sources, maas_url)), ) self.assertThat( protocol.UpdateLastImageSync, MockCalledOnceWith(protocol, system_id=get_maas_id()), )
def test__show_service_start_error(self): url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) mock_call_and_check = self.patch(register_command, 'call_and_check') mock_call_and_check.side_effect = [ call(), call(), ExternalProcessError(1, 'systemctl start', 'mock error'), ] mock_stderr = self.patch(register_command.stderr, 'write') with ExpectedException(SystemExit): register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertThat( mock_stderr, MockCallsMatch( call('Unable to enable and start the maas-rackd service.'), call('\n'), call('Failed with error: mock error.'), call('\n'), ))
def test__show_service_stop_error(self): url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) mock_call_and_check = self.patch(register_command, "call_and_check") mock_call_and_check.side_effect = [ ExternalProcessError(1, "systemctl stop", "mock error"), call(), call(), ] mock_stderr = self.patch(register_command.stderr, "write") with ExpectedException(SystemExit): register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertThat( mock_stderr, MockCallsMatch( call("Unable to stop maas-rackd service."), call("\n"), call("Failed with error: mock error."), call("\n"), ), )
def test_accepts_all_args(self): all_test_arguments = cluster_config_command.all_arguments default_arg_values = { '--region-url': None, '--uuid': None, '--init': False, '--tftp-port': None, '--tftp-root': None, '--debug': None, } failures = {} # Try all cardinalities of combinations of arguments for r in range(len(all_test_arguments) + 1): for test_arg_names in combinations(all_test_arguments, r): test_values = { '--region-url': factory.make_simple_http_url(), '--uuid': str(uuid.uuid4()), '--init': '', '--tftp-port': str(factory.pick_port()), '--tftp-root': factory.make_string(), '--debug': str(factory.pick_bool()), } # Build a query dictionary for the given combination of args args_under_test = [] for param_name in test_arg_names: args_under_test.append(param_name) if param_name != '--init': args_under_test.append(test_values[param_name]) parser = ArgumentParser() cluster_config_command.add_arguments(parser) # If both init and uuid are passed, argparse will generate # a nice ArgumentError exception, which unfortunately, # gets caught and sent to exit. if '--init' in test_arg_names and '--uuid' in test_arg_names: expected_exception = ExpectedException(SystemExit, '2') with expected_exception, patch('sys.stderr'): parser.parse_known_args(args_under_test) else: # Otherwise, parsed args with defaults as usual observed_args = vars(parser.parse_args(args_under_test)) expected_args = {} for param_name in all_test_arguments: parsed_param_name = param_name[2:].replace('-', '_') if param_name not in test_arg_names: expected_args[parsed_param_name] = \ default_arg_values[param_name] else: expected_args[parsed_param_name] = \ observed_args[parsed_param_name] if expected_args != observed_args: failures[str(test_arg_names)] = { 'expected_args': expected_args, 'observed_args': observed_args, } error_message = io.StringIO() error_message.write("One or more key / value argument list(s)" "passed in the query string (expected_args)" "to the API do not match the values in " "the returned query string. This " "means that some arguments were " "dropped / added / changed by the " "the function, which is incorrect " "behavior. The list of incorrect " "arguments is as follows: \n") pp = pprint.PrettyPrinter(depth=3, stream=error_message) pp.pprint(failures) self.assertDictEqual({}, failures, error_message.getvalue())
def test_config_set_maas_url_sets_url(self): expected = factory.make_simple_http_url() cluster_config_command.run(self.make_args(region_url=expected)) with ClusterConfiguration.open() as config: observed = config.maas_url self.assertEqual([expected], observed)
def test__deletes_maas_id_file(self): self.useFixture(MAASIDFixture(factory.make_string())) url = factory.make_simple_http_url() secret = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(secret))) self.assertIsNone(get_maas_id())
def setUp(self): super().setUp() self.mock_url = factory.make_simple_http_url()
def test___sets_secret(self): url = factory.make_simple_http_url() expected = factory.make_bytes() register_command.run(self.make_args(url=url, secret=to_hex(expected))) observed = get_shared_secret_from_filesystem() self.assertEqual(expected, observed)
def test_set_maas_url_accepts_hostnames(self): config = ClusterConfiguration({}) example_url = factory.make_simple_http_url() config.maas_url = example_url self.assertEqual([example_url], config.maas_url) self.assertEqual({"maas_url": [example_url]}, config.store)
def setUp(self): super(TestEvaluateTag, self).setUp() self.mock_url = factory.make_simple_http_url()
def setUp(self): super(TestEvaluateTag, self).setUp() self.mock_url = factory.make_simple_http_url() self.useFixture(ClusterConfigurationFixture(maas_url=self.mock_url))
def fake_client(self): return MAASClient(None, None, factory.make_simple_http_url())
def test_allows_ipv4_addresses_in_ipv6_format(self): name = "[::ffff:%s]" % factory.make_ipv4_address() url = factory.make_simple_http_url(netloc=name, port=factory.pick_bool()) self.assertEqual(url, self.validator.to_python(url), "url: %s" % url)
def test_run_import_sets_GPGHOME(self): home = factory.make_name("home") self.patch(boot_images, "get_maas_user_gpghome").return_value = home fake = self.patch_boot_resources_function() _run_import(sources=[], maas_url=factory.make_simple_http_url()) self.assertEqual(home, fake.env["GNUPGHOME"])
def test_set_maas_url_accepts_hostnames(self): config = RegionConfiguration({}) example_url = factory.make_simple_http_url() config.maas_url = example_url self.assertEqual(example_url, config.maas_url) self.assertEqual({"maas_url": example_url}, config.store)
def test_run_import_accepts_sources_parameter(self): fake = self.patch(boot_resources, "import_images") sources, _ = make_sources() _run_import(sources=sources, maas_url=factory.make_simple_http_url()) self.assertThat(fake, MockCalledOnceWith(sources))
def test_run_import_calls_reload_boot_images(self): fake_reload = self.patch(boot_images, "reload_boot_images") self.patch(boot_resources, "import_images") sources, _ = make_sources() _run_import(sources=sources, maas_url=factory.make_simple_http_url()) self.assertThat(fake_reload, MockCalledOnceWith())
def test_set_maas_url_rejects_bare_ipv6_addresses(self): config = RegionConfiguration({}) example_url = factory.make_simple_http_url( netloc=factory.make_ipv6_address()) with ExpectedException(formencode.api.Invalid): config.maas_url = example_url
def test_get_dns_server_address_raises_if_hostname_doesnt_resolve(self): url = maastesting_factory.make_simple_http_url() self.useFixture(RegionConfigurationFixture(maas_url=url)) self.patch(zonegenerator, 'get_maas_facing_server_addresses', FakeMethod(failure=socket.error)) self.assertRaises(UnresolvableHost, get_dns_server_address)