def base_test_failure_bad_zip(self): resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) stderr = MagicMock() bundle_open_mock = MagicMock( side_effect=BadZipFile('test bad zip error')) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock): logging_setup.configure_logging(MagicMock(**self.default_args), err_output=stderr) result = conduct_load.load(MagicMock(**self.default_args)) self.assertFalse(result) resolve_bundle_mock.assert_called_with(self.custom_settings, self.bundle_resolve_cache_dir, self.bundle_file, self.offline_mode) bundle_open_mock.assert_called_with( self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) self.assertEqual( as_error( strip_margin( """|Error: Problem with the bundle: test bad zip error |""")), self.output(stderr))
def load_v1(args): log = logging.getLogger(__name__) log.info('Retrieving bundle...') custom_settings = args.custom_settings resolve_cache_dir = args.resolve_cache_dir bundle_name, bundle_file = resolver.resolve_bundle(custom_settings, resolve_cache_dir, args.bundle) configuration_name, configuration_file = (None, None) if args.configuration is not None: log.info('Retrieving configuration...') configuration_name, configuration_file = resolver.resolve_bundle(custom_settings, resolve_cache_dir, args.configuration) bundle_conf = ConfigFactory.parse_string(bundle_utils.conf(bundle_file)) overlay_bundle_conf = None if configuration_file is None else \ ConfigFactory.parse_string(bundle_utils.conf(configuration_file)) with_bundle_configurations = partial(apply_to_configurations, bundle_conf, overlay_bundle_conf) url = conduct_url.url('bundles', args) files = get_payload(bundle_name, bundle_file, with_bundle_configurations) if configuration_file is not None: files.append(('configuration', (configuration_name, open(configuration_file, 'rb')))) log.info('Loading bundle to ConductR...') response = requests.post(url, files=files, timeout=LOAD_HTTP_TIMEOUT) validation.raise_for_status_inc_3xx(response) if log.is_verbose_enabled(): log.verbose(validation.pretty_json(response.text)) response_json = json.loads(response.text) bundle_id = response_json['bundleId'] if args.long_ids else bundle_utils.short_id(response_json['bundleId']) if not args.no_wait: bundle_installation.wait_for_installation(response_json['bundleId'], args) log.info('Bundle loaded.') log.info('Start bundle with: conduct run{} {}'.format(args.cli_parameters, bundle_id)) log.info('Unload bundle with: conduct unload{} {}'.format(args.cli_parameters, bundle_id)) log.info('Print ConductR info with: conduct info{}'.format(args.cli_parameters)) if not log.is_info_enabled() and log.is_quiet_enabled(): log.quiet(response_json['bundleId']) return True
def base_test_success_dcos_mode(self): self.default_args['dcos_mode'] = True self.default_args['command'] = 'dcos conduct' resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) create_multipart_mock = MagicMock(return_value=self.multipart_mock) http_method = self.respond_with(200, self.default_response) stdout = MagicMock() bundle_open_mock = MagicMock(side_effect=lambda p1, p2, p3: (p1, 1)) wait_for_installation_mock = MagicMock() cleanup_old_bundles_mock = MagicMock() input_args = MagicMock(**self.default_args) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.conduct_load.create_multipart', create_multipart_mock), \ patch('conductr_cli.conduct_load.cleanup_old_bundles', cleanup_old_bundles_mock), \ patch('dcos.http.post', http_method), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock), \ patch('conductr_cli.bundle_installation.wait_for_installation', wait_for_installation_mock): logging_setup.configure_logging(input_args, stdout) result = conduct_load.load(input_args) self.assertTrue(result) bundle_open_mock.assert_called_with( self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) resolve_bundle_mock.assert_called_with(self.custom_settings, self.bundle_resolve_cache_dir, self.bundle_file, self.offline_mode) create_multipart_mock.assert_called_with(self.conduct_load_logger, self.default_files) http_method.assert_called_with(self.default_url, data=self.multipart_mock, auth=self.conductr_auth, verify=self.server_verification_file, headers={ 'Content-Type': self.multipart_content_type, 'Host': '127.0.0.1' }) wait_for_installation_mock.assert_called_with(self.bundle_id, input_args) cleanup_old_bundles_mock.assert_called_with( self.bundle_resolve_cache_dir, self.bundle_file_name, excluded=self.bundle_file) self.assertEqual( self.default_output(command=self.default_args['command']), self.output(stdout))
def load(args): """`conduct load` command""" print('Retrieving bundle...') bundle_name, bundle_url = get_url(args.bundle) bundle_file, bundle_headers = urlretrieve(bundle_url) configuration_file, configuration_headers, configuration_name = (None, None, None) if args.configuration is not None: print('Retrieving configuration...') configuration_name, configuration_url = get_url(args.configuration) configuration_file, configuration_headers = urlretrieve(configuration_url) bundle_conf = ConfigFactory.parse_string(bundle_utils.conf(bundle_file)) overlay_bundle_conf = None if configuration_file is None else \ ConfigFactory.parse_string(bundle_utils.conf(configuration_file)) with_bundle_configurations = partial(apply_to_configurations, bundle_conf, overlay_bundle_conf) url = conduct_url.url('bundles', args) files = get_payload(args.api_version, bundle_name, bundle_file, with_bundle_configurations) if configuration_file is not None: files.append(('configuration', (configuration_name, open(configuration_file, 'rb')))) print('Loading bundle to ConductR...') response = requests.post(url, files=files) conduct_logging.raise_for_status_inc_3xx(response) if args.verbose: conduct_logging.pretty_json(response.text) response_json = json.loads(response.text) bundle_id = response_json['bundleId'] if args.long_ids else bundle_utils.short_id(response_json['bundleId']) print('Bundle loaded.') print('Start bundle with: conduct run{} {}'.format(args.cli_parameters, bundle_id)) print('Unload bundle with: conduct unload{} {}'.format(args.cli_parameters, bundle_id)) print('Print ConductR info with: conduct info{}'.format(args.cli_parameters))
def base_test_failure_no_response(self): resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) create_multipart_mock = MagicMock(return_value=self.multipart_mock) http_method = self.raise_read_timeout_error('test reason', self.default_url) stdout = MagicMock() stderr = MagicMock() bundle_open_mock = MagicMock(side_effect=lambda p1, p2, p3: (p1, 1)) input_args = MagicMock(**self.default_args) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.conduct_load.create_multipart', create_multipart_mock), \ patch('requests.post', http_method), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock): logging_setup.configure_logging(input_args, stdout, stderr) result = conduct_load.load(input_args) self.assertFalse(result) bundle_open_mock.assert_called_with( self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) resolve_bundle_mock.assert_called_with(self.custom_settings, self.bundle_resolve_cache_dir, self.bundle_file, self.offline_mode) create_multipart_mock.assert_called_with(self.conduct_load_logger, self.default_files) http_method.assert_called_with(self.default_url, data=self.multipart_mock, auth=self.conductr_auth, verify=self.server_verification_file, headers={ 'Content-Type': self.multipart_content_type, 'Host': '127.0.0.1' }) self.assertEqual( as_error( strip_margin( """|Error: Timed out waiting for response from the server: test reason |Error: One possible issue may be that there are not enough resources or machines with the roles that your bundle requires |""")), self.output(stderr))
def base_test_failure_install_timeout(self): resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) create_multipart_mock = MagicMock(return_value=self.multipart_mock) http_method = self.respond_with(200, self.default_response) stderr = MagicMock() bundle_open_mock = MagicMock(side_effect=lambda p1, p2, p3: (p1, 1)) wait_for_installation_mock = MagicMock( side_effect=WaitTimeoutError('test timeout')) input_args = MagicMock(**self.default_args) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.conduct_load.create_multipart', create_multipart_mock), \ patch('requests.post', http_method), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock), \ patch('conductr_cli.bundle_installation.wait_for_installation', wait_for_installation_mock): logging_setup.configure_logging(input_args, err_output=stderr) result = conduct_load.load(input_args) self.assertFalse(result) bundle_open_mock.assert_called_with( self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) create_multipart_mock.assert_called_with(self.conduct_load_logger, self.default_files) http_method.assert_called_with(self.default_url, data=self.multipart_mock, auth=self.conductr_auth, verify=self.server_verification_file, headers={ 'Content-Type': self.multipart_content_type, 'Host': '127.0.0.1' }) wait_for_installation_mock.assert_called_with(self.bundle_id, input_args) self.assertEqual( as_error( strip_margin("""|Error: Timed out: test timeout |""")), self.output(stderr))
def base_test_failure_invalid_address(self): resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) create_multipart_mock = MagicMock(return_value=self.multipart_mock) http_method = self.raise_connection_error('test reason', self.default_url) stdout = MagicMock() stderr = MagicMock() bundle_open_mock = MagicMock(side_effect=lambda p1, p2, p3: (p1, 1)) input_args = MagicMock(**self.default_args) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.conduct_load.create_multipart', create_multipart_mock), \ patch('requests.post', http_method), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock): logging_setup.configure_logging(input_args, stdout, stderr) result = conduct_load.load(input_args) self.assertFalse(result) bundle_open_mock.assert_called_with( self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) resolve_bundle_mock.assert_called_with(self.custom_settings, self.bundle_resolve_cache_dir, self.bundle_file, self.offline_mode) create_multipart_mock.assert_called_with(self.conduct_load_logger, self.default_files) http_method.assert_called_with(self.default_url, data=self.multipart_mock, auth=self.conductr_auth, verify=self.server_verification_file, headers={ 'Content-Type': self.multipart_content_type, 'Host': '127.0.0.1' }) self.assertEqual( self.default_connection_error.format(self.default_url), self.output(stderr))
def test_success_with_configuration(self): tmpdir, config_file = create_temp_bundle_with_contents({ 'bundle.conf': '{name="overlaid-name"}', 'config.sh': 'echo configuring' }) resolve_bundle_mock = MagicMock(return_value=(self.bundle_file_name, self.bundle_file)) resolve_bundle_configuration_mock = MagicMock( return_value=('config.zip', config_file)) create_multipart_mock = MagicMock(return_value=self.multipart_mock) http_method = self.respond_with(200, self.default_response) stdout = MagicMock() open_mock = MagicMock(return_value=(1, None)) bundle_open_mock = MagicMock(side_effect=lambda p1, p2, p3: (p1, 1)) wait_for_installation_mock = MagicMock() args = self.default_args.copy() args.update({'configuration': config_file}) input_args = MagicMock(**args) with patch('conductr_cli.resolver.resolve_bundle', resolve_bundle_mock), \ patch('conductr_cli.resolver.resolve_bundle_configuration', resolve_bundle_configuration_mock), \ patch('conductr_cli.conduct_load.create_multipart', create_multipart_mock), \ patch('requests.post', http_method), \ patch('conductr_cli.bundle_utils.digest_extract_and_open', open_mock), \ patch('conductr_cli.conduct_load.open_bundle', bundle_open_mock), \ patch('conductr_cli.bundle_installation.wait_for_installation', wait_for_installation_mock): logging_setup.configure_logging(input_args, stdout) result = conduct_load.load(input_args) self.assertTrue(result) self.assertEqual(open_mock.call_args_list, [call(config_file)]) self.assertEqual(bundle_open_mock.call_args_list, [ call(self.bundle_file_name, self.bundle_file, bundle_utils.conf(self.bundle_file)) ]) resolve_bundle_mock.assert_called_with(self.custom_settings, self.bundle_resolve_cache_dir, self.bundle_file, self.offline_mode) resolve_bundle_configuration_mock.assert_called_with( self.custom_settings, self.configuration_resolve_cache_dir, config_file, self.offline_mode) expected_files = self.default_files + [('configuration', ('config.zip', 1))] expected_files[4] = ('bundleName', 'overlaid-name') create_multipart_mock.assert_called_with(self.conduct_load_logger, expected_files) http_method.assert_called_with(self.default_url, data=self.multipart_mock, auth=self.conductr_auth, verify=self.server_verification_file, headers={ 'Content-Type': self.multipart_content_type, 'Host': '127.0.0.1' }) wait_for_installation_mock.assert_called_with(self.bundle_id, input_args) self.assertEqual( self.default_output( downloading_configuration='Retrieving configuration..\n'), self.output(stdout))
def test(self): conf_contents = bundle_utils.conf(self.bundle_path) self.assertEqual(conf_contents, 'bundle conf contents')
def load_v1(args): log = logging.getLogger(__name__) log.info('Retrieving bundle...') custom_settings = args.custom_settings resolve_cache_dir = args.resolve_cache_dir bundle_name, bundle_file = resolver.resolve_bundle(custom_settings, resolve_cache_dir, args.bundle) configuration_name, configuration_file = (None, None) if args.configuration is not None: log.info('Retrieving configuration...') configuration_name, configuration_file = resolver.resolve_bundle( custom_settings, resolve_cache_dir, args.configuration) bundle_conf = ConfigFactory.parse_string(bundle_utils.conf(bundle_file)) overlay_bundle_conf = None if configuration_file is None else \ ConfigFactory.parse_string(bundle_utils.conf(configuration_file)) with_bundle_configurations = partial(apply_to_configurations, bundle_conf, overlay_bundle_conf) url = conduct_url.url('bundles', args) files = get_payload(bundle_name, bundle_file, with_bundle_configurations) if configuration_file is not None: files.append(('configuration', (configuration_name, open(configuration_file, 'rb')))) log.info('Loading bundle to ConductR...') # At the time when this comment is being written, we need to pass the Host header when making HTTP request due to # a bug with requests python library not working properly when IPv6 address is supplied: # https://github.com/kennethreitz/requests/issues/3002 # The workaround for this problem is to explicitly set the Host header when making HTTP request. # This fix is benign and backward compatible as the library would do this when making HTTP request anyway. response = requests.post(url, files=files, timeout=LOAD_HTTP_TIMEOUT, headers=conduct_url.request_headers(args)) validation.raise_for_status_inc_3xx(response) if log.is_verbose_enabled(): log.verbose(validation.pretty_json(response.text)) response_json = json.loads(response.text) bundle_id = response_json[ 'bundleId'] if args.long_ids else bundle_utils.short_id( response_json['bundleId']) if not args.no_wait: bundle_installation.wait_for_installation(response_json['bundleId'], args) log.info('Bundle loaded.') log.info('Start bundle with: conduct run{} {}'.format( args.cli_parameters, bundle_id)) log.info('Unload bundle with: conduct unload{} {}'.format( args.cli_parameters, bundle_id)) log.info('Print ConductR info with: conduct info{}'.format( args.cli_parameters)) if not log.is_info_enabled() and log.is_quiet_enabled(): log.quiet(response_json['bundleId']) return True
def load_v1(args): log = logging.getLogger(__name__) log.info('Retrieving bundle..') custom_settings = args.custom_settings bundle_resolve_cache_dir = args.bundle_resolve_cache_dir configuration_cache_dir = args.configuration_resolve_cache_dir validate_cache_dir_permissions(bundle_resolve_cache_dir, configuration_cache_dir, log) initial_bundle_file_name, bundle_file = resolver.resolve_bundle( custom_settings, bundle_resolve_cache_dir, args.bundle, args.offline_mode) configuration_file_name, configuration_file = (None, None) if args.configuration is not None: log.info('Retrieving configuration..') configuration_file_name, configuration_file = \ resolver.resolve_bundle_configuration(custom_settings, configuration_cache_dir, args.configuration, args.offline_mode) bundle_conf_text = bundle_utils.conf(bundle_file) bundle_conf = ConfigFactory.parse_string(bundle_conf_text) bundle_file_name, bundle_open_file = open_bundle(initial_bundle_file_name, bundle_file, bundle_conf_text) overlay_bundle_conf = None if configuration_file is None else \ ConfigFactory.parse_string(bundle_utils.conf(configuration_file)) with_bundle_configurations = partial(apply_to_configurations, bundle_conf, overlay_bundle_conf) url = conduct_url.url('bundles', args) files = get_payload(bundle_file_name, bundle_open_file, with_bundle_configurations) if configuration_file is not None: open_configuration_file, config_digest = bundle_utils.digest_extract_and_open( configuration_file) files.append(('configuration', (configuration_file_name, open_configuration_file))) # TODO: Delete the bundle configuration file. # Currently, this results into a permission error on Windows. # Therefore, the deletion is disabled for now. # Issue: https://github.com/typesafehub/conductr-cli/issues/175 # if configuration_file and os.path.exists(configuration_file): # os.remove(configuration_file) log.info('Loading bundle to ConductR..') multipart = create_multipart(log, files) response = conduct_request.post( args.dcos_mode, conductr_host(args), url, data=multipart, auth=args.conductr_auth, verify=args.server_verification_file, headers={'Content-Type': multipart.content_type}) validation.raise_for_status_inc_3xx(response) if log.is_verbose_enabled(): log.verbose(validation.pretty_json(response.text)) response_json = json.loads(response.text) bundle_id = response_json[ 'bundleId'] if args.long_ids else bundle_utils.short_id( response_json['bundleId']) if not args.no_wait: bundle_installation.wait_for_installation(response_json['bundleId'], args) cleanup_old_bundles(bundle_resolve_cache_dir, bundle_file_name, excluded=bundle_file) log.info('Bundle loaded.') if not args.disable_instructions: log.info('Start bundle with: {} run{} {}'.format( args.command, args.cli_parameters, bundle_id)) log.info('Unload bundle with: {} unload{} {}'.format( args.command, args.cli_parameters, bundle_id)) log.info('Print ConductR info with: {} info{}'.format( args.command, args.cli_parameters)) log.info('Print bundle info with: {} info{} {}'.format( args.command, args.cli_parameters, bundle_id)) if not log.is_info_enabled() and log.is_quiet_enabled(): log.quiet(response_json['bundleId']) return True
def load_v1(args): log = logging.getLogger(__name__) log.info('Retrieving bundle..') custom_settings = args.custom_settings resolve_cache_dir = args.resolve_cache_dir validate_cache_dir_permissions(resolve_cache_dir, log) bundle_file_name, bundle_file = resolver.resolve_bundle(custom_settings, resolve_cache_dir, args.bundle) configuration_file_name, configuration_file = (None, None) if args.configuration is not None: log.info('Retrieving configuration..') configuration_file_name, configuration_file = resolver.resolve_bundle_configuration(custom_settings, resolve_cache_dir, args.configuration) bundle_conf = ConfigFactory.parse_string(bundle_utils.conf(bundle_file)) overlay_bundle_conf = None if configuration_file is None else \ ConfigFactory.parse_string(bundle_utils.conf(configuration_file)) with_bundle_configurations = partial(apply_to_configurations, bundle_conf, overlay_bundle_conf) url = conduct_url.url('bundles', args) files = get_payload(bundle_file_name, bundle_file, with_bundle_configurations) if configuration_file is not None: files.append(('configuration', (configuration_file_name, open(configuration_file, 'rb')))) # TODO: Delete the bundle configuration file. # Currently, this results into a permission error on Windows. # Therefore, the deletion is disabled for now. # Issue: https://github.com/typesafehub/conductr-cli/issues/175 # if configuration_file and os.path.exists(configuration_file): # os.remove(configuration_file) log.info('Loading bundle to ConductR..') multipart = create_multipart(log, files) response = conduct_request.post(args.dcos_mode, conductr_host(args), url, data=multipart, auth=args.conductr_auth, verify=args.server_verification_file, headers={'Content-Type': multipart.content_type}) validation.raise_for_status_inc_3xx(response) if log.is_verbose_enabled(): log.verbose(validation.pretty_json(response.text)) response_json = json.loads(response.text) bundle_id = response_json['bundleId'] if args.long_ids else bundle_utils.short_id(response_json['bundleId']) if not args.no_wait: bundle_installation.wait_for_installation(response_json['bundleId'], args) cleanup_old_bundles(resolve_cache_dir, bundle_file_name, excluded=bundle_file) log.info('Bundle loaded.') if not args.disable_instructions: log.info('Start bundle with: {} run{} {}'.format(args.command, args.cli_parameters, bundle_id)) log.info('Unload bundle with: {} unload{} {}'.format(args.command, args.cli_parameters, bundle_id)) log.info('Print ConductR info with: {} info{}'.format(args.command, args.cli_parameters)) if not log.is_info_enabled() and log.is_quiet_enabled(): log.quiet(response_json['bundleId']) return True