def edit_scan(self, scan_id, title=None, description=None, configuration=None): """Edits the given Scan process and saves the changes in the database. All database changes occur in an atomic transaction. An argument of None for a field indicates that the field should not change. :param scan_id: The unique identifier of the Scan process to edit :type scan_id: int :param title: The human-readable name of this Scan process :type title: string :param description: A description of this Scan process :type description: string :param configuration: The Strike process configuration :type configuration: dict :raises :class:`ingest.scan.configuration.exceptions.InvalidScanConfiguration`: If the configuration is invalid. """ scan = Scan.objects.select_for_update().get(pk=scan_id) if scan.job: raise ScanIngestJobAlreadyLaunched # Validate the configuration, no exception is success if configuration: config = ScanConfiguration(configuration) config.validate() scan.configuration = config.get_dict() # Update editable fields if title: scan.title = title if description: scan.description = description scan.save()
def create_scan(self, name, title, description, configuration, dry_run=True): """Creates a new Scan process with the given configuration and returns the new Scan model. All changes to the database will occur in an atomic transaction. :param name: The identifying name of this Scan process :type name: string :param title: The human-readable name of this Scan process :type title: string :param description: A description of this Scan process :type description: string :param configuration: The Scan configuration :type configuration: dict :param dry_run: Whether the scan will execute as a dry run :type dry_run: bool :returns: The new Scan process :rtype: :class:`ingest.models.Scan` :raises :class:`ingest.scan.configuration.exceptions.InvalidScanConfiguration`: If the configuration is invalid. """ # Validate the configuration, no exception is success config = ScanConfiguration(configuration) config.validate() scan = Scan() scan.name = name scan.title = title scan.description = description scan.configuration = config.get_dict() scan.save() return scan
def test_edit_simple(self): """Tests editing only the basic attributes of a Scan process""" json_data = { 'title': 'Title EDIT', 'description': 'Description EDIT', } url = rest_util.get_url('/scans/%d/' % self.scan.id) response = self.client.generic('PATCH', url, json.dumps(json_data), 'application/json') self.assertEqual(response.status_code, status.HTTP_200_OK, response.content) result = json.loads(response.content) self.assertTrue(isinstance(result, dict), 'result must be a dictionary') self.assertEqual(result['id'], self.scan.id) self.assertEqual(result['title'], 'Title EDIT') self.assertEqual(result['description'], 'Description EDIT') self.assertDictEqual( result['configuration'], ScanConfiguration(self.scan.configuration).get_dict()) scan = Scan.objects.get(pk=self.scan.id) self.assertEqual(scan.title, 'Title EDIT') self.assertEqual(scan.description, 'Description EDIT')
def test_edit_config(self): """Tests editing the configuration of a Scan process""" config = { 'version': '1.0', 'workspace': 'raw', 'scanner': {'type': 'dir', 'transfer_suffix': '_tmp'}, 'files_to_ingest': [{ 'data_types': ['test'], 'filename_regex': '.*txt', 'new_file_path': 'my_path', 'new_workspace': 'raw', }], } json_data = { 'configuration': config, } url = rest_util.get_url('/scans/%d/' % self.scan.id) response = self.client.generic('PATCH', url, json.dumps(json_data), 'application/json') self.assertEqual(response.status_code, status.HTTP_200_OK, response.content) result = json.loads(response.content) self.assertEqual(result['id'], self.scan.id) self.assertEqual(result['title'], self.scan.title) self.assertDictEqual(result['configuration'], ScanConfiguration(config).get_dict()) scan = Scan.objects.get(pk=self.scan.id) self.assertEqual(scan.title, self.scan.title) self.assertDictEqual(scan.configuration, config)
def get_scan_configuration(self): """Returns the configuration for this Scan process :returns: The configuration for this Scan process :rtype: :class:`ingest.scan.configuration.scan_configuration.ScanConfiguration` """ return ScanConfiguration(self.configuration)
def post(self, request): """Validates a new Scan process and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ configuration = rest_util.parse_dict(request, 'configuration') # Validate the Scan configuration try: config = ScanConfiguration(configuration) warnings = config.validate() except InvalidScanConfiguration as ex: logger.exception('Unable to validate Scan configuration.') raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def test_bare_min(self): """Tests calling ScanConfiguration constructor with bare minimum JSON""" # No exception is success ScanConfiguration({ 'workspace': self.workspace.name, 'scanner': { 'type': 'dir' }, 'files_to_ingest': [{ 'filename_regex': '.*txt' }], })
def get_configuration(self): """Returns the scan configuration represented by this JSON :returns: The scan configuration :rtype: :class:`ingest.scan.configuration.scan_configuration.ScanConfiguration`: """ config = ScanConfiguration() config.scanner_type = self._configuration['scanner']['type'] config.scanner_config = self._configuration['scanner'] config.recursive = self._configuration['recursive'] config.file_handler = self._file_handler config.workspace = self._configuration['workspace'] config.config_dict = self._configuration return config
def test_validate_bad_scanner_type(self): """Tests calling ScanConfiguration.validate() with a bad scanner type""" config = { 'workspace': self.workspace.name, 'scanner': { 'type': 'BAD' }, 'files_to_ingest': [{ 'filename_regex': '.*txt', }], } self.assertRaises(InvalidScanConfiguration, ScanConfiguration(config).validate)
def test_validate_mismatched_scanner_type(self): """Tests calling ScanConfiguration.validate() with a scanner type that does not match the broker type""" config = { 'workspace': self.workspace.name, 'scanner': { 'type': 's3', 'sqs_name': 'my-sqs', }, 'files_to_ingest': [{ 'filename_regex': '.*txt', }], } self.assertRaises(InvalidScanConfiguration, ScanConfiguration(config).validate)
def test_validate_workspace_not_active(self): """Tests calling ScanConfiguration.validate() with a new workspace that is not active""" config = { 'workspace': self.workspace.name, 'scanner': { 'type': 'dir' }, 'files_to_ingest': [{ 'filename_regex': '.*txt', 'new_workspace': self.inactive_workspace.name, }], } self.assertRaises(InvalidScanConfiguration, ScanConfiguration(config).validate)
def test_successful_all(self): """Tests calling ScanConfiguration constructor successfully with all information""" config = { 'workspace': self.workspace.name, 'scanner': { 'type': 'dir' }, 'files_to_ingest': [{ 'filename_regex': '.*txt', 'data_types': ['one', 'two'], 'new_file_path': os.path.join('my', 'path'), 'new_workspace': self.workspace.name, }], } # No exception is success ScanConfiguration(config)
def test_validate_recursive_invalid_type(self): """Tests calling ScanConfiguration.validate() with recursive set to invalid type""" config = { 'workspace': self.workspace.name, 'scanner': { 'type': 'dir' }, 'recursive': 'true', 'files_to_ingest': [{ 'filename_regex': '.*txt', 'new_workspace': self.inactive_workspace.name, }], } with self.assertRaises(InvalidScanConfiguration): ScanConfiguration(config).validate()