예제 #1
0
    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))
예제 #2
0
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
예제 #3
0
    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))
예제 #4
0
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))
예제 #5
0
    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))
예제 #6
0
    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))
예제 #7
0
    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))
예제 #8
0
    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')
예제 #10
0
 def test(self):
     conf_contents = bundle_utils.conf(self.bundle_path)
     self.assertEqual(conf_contents, 'bundle conf contents')
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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