def test_scan_with_options(self, mock_run): """Setup second scan with scan and source options.""" # setup source with paramiko option for scan source_options = SourceOptions() source_options.save() self.source = Source(name='source2', port=22, options=source_options, hosts='["1.2.3.4"]') self.source.save() self.source.credentials.add(self.cred) # setup scan with options extended = ExtendedProductSearchOptions() extended.save() scan_options = ScanOptions(enabled_extended_product_search=extended) scan_options.save() self.scan_job, self.scan_task = create_scan_job( self.source, ScanTask.SCAN_TYPE_INSPECT, 'scan2', scan_options=scan_options) # run scan scanner = InspectTaskRunner(self.scan_job, self.scan_task) scanner.connect_scan_task = self.connect_scan_task scanner._inspect_scan(self.host_list) mock_run.assert_called_with(ANY)
def setUp(self): """Create test case setup.""" self.cred = Credential(name='cred1', username='******', password='******', sudo_password='******', ssh_keyfile='keyfile') self.cred.save() self.source = Source(name='source1', port=22) self.source.save() self.source.credentials.add(self.cred) self.host = HostRange(host_range='1.2.3.4', source_id=self.source.id) self.host.save() self.source.hosts.add(self.host) self.scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_CONNECT) self.scan_task.systems_failed = 0 self.scan_task.save() self.scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_CONNECT) self.scan_job.save() self.scan_job.sources.add(self.source) self.scan_job.tasks.add(self.scan_task) scan_options = ScanOptions() scan_options.save() self.scan_job.options = scan_options self.scan_job.save() self.conn_results = ConnectionResults(scan_job=self.scan_job) self.conn_results.save()
def test_get_extra_vars_false(self): """Tests the get_extra_vars method with all False.""" extended = ExtendedProductSearchOptions() extended.save() disabled = DisabledOptionalProductsOptions( jboss_eap=True, jboss_fuse=True, jboss_brms=True) disabled.save() scan_options = ScanOptions( disabled_optional_products=disabled, enabled_extended_product_search=extended) scan_options.save() scan_job, _ = create_scan_job(self.source, ScanTask.SCAN_TYPE_INSPECT, scan_options=scan_options) extra_vars = scan_job.options.get_extra_vars() expected_vars = {'jboss_eap': False, 'jboss_fuse': False, 'jboss_brms': False, 'jboss_eap_ext': False, 'jboss_fuse_ext': False, 'jboss_brms_ext': False} self.assertEqual(extra_vars, expected_vars)
def create(self, validated_data): """Create a scan job.""" options = validated_data.pop('options', None) scanjob = super().create(validated_data) if options: options = ScanOptions.objects.create(**options) else: options = ScanOptions() options.save() scanjob.options = options scanjob.save() return scanjob
def test_get_extra_vars(self): """Tests the get_extra_vars method with empty dict.""" scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_INSPECT) scan_job.save() scan_options = ScanOptions() scan_options.disable_optional_products = {} scan_options.save() scan_job.options = scan_options scan_job.save() extra_vars = scan_job.get_extra_vars() expected_vars = { 'jboss_eap': True, 'jboss_fuse': True, 'jboss_brms': True } self.assertEqual(extra_vars, expected_vars)
def run_with_result_store(self, manager_interrupt, result_store): """Run with a given ConnectResultStore.""" serializer = SourceSerializer(self.scan_task.source) source = serializer.data if self.scan_job.options is not None: forks = self.scan_job.options.max_concurrency else: forks = ScanOptions.get_default_forks() if self.scan_task.source.options is not None: use_paramiko = self.scan_task.source.options.use_paramiko else: use_paramiko = False connection_port = source['port'] credentials = source['credentials'] remaining_hosts = result_store.remaining_hosts() for cred_id in credentials: check_manager_interrupt(manager_interrupt.value) credential = Credential.objects.get(pk=cred_id) if not remaining_hosts: message = 'Skipping credential %s. No remaining hosts.' % \ credential.name self.scan_task.log_message(message) break message = 'Attempting credential %s.' % credential.name self.scan_task.log_message(message) try: scan_message, scan_result = _connect(manager_interrupt, self.scan_task, remaining_hosts, result_store, credential, connection_port, forks, use_paramiko) if scan_result != ScanTask.COMPLETED: return scan_message, scan_result except AnsibleRunnerException as ansible_error: remaining_hosts_str = ', '.join(result_store.remaining_hosts()) error_message = 'Connect scan task failed with credential %s.'\ ' Error: %s Hosts: %s' %\ (credential.name, ansible_error, remaining_hosts_str) return error_message, ScanTask.FAILED remaining_hosts = result_store.remaining_hosts() logger.debug('Failed systems: %s', remaining_hosts) for host in remaining_hosts: # We haven't connected to these hosts with any # credentials, so they have failed. result_store.record_result(host, self.scan_task.source, None, SystemConnectionResult.FAILED) return None, ScanTask.COMPLETED
def test_queue_task(self): """Test create queue state change.""" # Cannot use util because its testing queue # Create scan configuration scan = Scan(name='test', scan_type=ScanTask.SCAN_TYPE_INSPECT) scan.save() # Add source to scan scan.sources.add(self.source) options_to_use = ScanOptions() options_to_use.save() scan.options = options_to_use scan.save() # Create Job scan_job = ScanJob(scan=scan) scan_job.save() # Job in created state self.assertEqual(scan_job.status, ScanTask.CREATED) tasks = scan_job.tasks.all() self.assertEqual(len(tasks), 0) # Queue job to run scan_job.queue() # Job should be in pending state self.assertEqual(scan_job.status, ScanTask.PENDING) # Queue should have created scan tasks tasks = scan_job.tasks.all() self.assertEqual(len(tasks), 2) # Validate connect task created and correct connect_task = tasks[0] self.assertEqual(connect_task.scan_type, ScanTask.SCAN_TYPE_CONNECT) self.assertEqual(connect_task.status, ScanTask.PENDING) # Validate inspect task created and correct inspect_task = tasks[1] self.assertEqual(inspect_task.scan_type, ScanTask.SCAN_TYPE_INSPECT) self.assertEqual(inspect_task.status, ScanTask.PENDING)
def test_get_extra_vars_missing_extended_search(self): """Tests the get_extra_vars with disabled products None.""" extended = ExtendedProductSearchOptions() extended.save() scan_options = ScanOptions( enabled_extended_product_search=extended) scan_options.save() scan_job, _ = create_scan_job(self.source, ScanTask.SCAN_TYPE_INSPECT, scan_options=scan_options) extra_vars = scan_job.options.get_extra_vars() expected_vars = {'jboss_eap': True, 'jboss_fuse': True, 'jboss_brms': True, 'jboss_eap_ext': False, 'jboss_fuse_ext': False, 'jboss_brms_ext': False} self.assertEqual(extra_vars, expected_vars)
def test_get_extra_vars_missing_disable_product(self): """Tests the get_extra_vars with extended search None.""" disabled = DisabledOptionalProductsOptions() disabled.save() scan_options = ScanOptions( disabled_optional_products=disabled) scan_options.save() scan_job, _ = create_scan_job(self.source, ScanTask.SCAN_TYPE_INSPECT, scan_options=scan_options) extra_vars = scan_job.options.get_extra_vars() expected_vars = {'jboss_eap': True, 'jboss_fuse': True, 'jboss_brms': True, 'jboss_eap_ext': False, 'jboss_fuse_ext': False, 'jboss_brms_ext': False} self.assertEqual(extra_vars, expected_vars)
def create(self, request, *args, **kwargs): """Create a source.""" response = super().create(request, args, kwargs) # Modify json for response json_source = response.data source_id = json_source.get('id') if not source_id or (source_id and not isinstance(source_id, int)): error = {'id': [_(messages.COMMON_ID_INV)]} raise ValidationError(error) get_object_or_404(self.queryset, pk=source_id) # Create expanded host cred JSON expand_credential(json_source) # check to see if a connection scan was requested # through query parameter scan = request.query_params.get('scan', False) # If the scan was requested, create a connection scan if scan: if is_boolean(scan): if convert_to_boolean(scan): # Grab the source id source_id = response.data['id'] # Define the scan options object scan_options = ScanOptions() scan_options.save() # Create the scan job scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_CONNECT, options=scan_options) scan_job.save() # Add the source scan_job.sources.add(source_id) scan_job.save() # Start the scan start_scan.send(sender=self.__class__, instance=scan_job) else: error = {'scan': [_(messages.SOURCE_CONNECTION_SCAN)]} raise ValidationError(error) return response
def test_hosts_facts(self, mock_pool): """Test the hosts_facts method.""" scan_options = ScanOptions(max_concurrency=10) scan_options.save() scan_job, scan_task = create_scan_job(self.source, ScanTask.SCAN_TYPE_INSPECT, scan_name='test_62', scan_options=scan_options) scan_task.update_stats('TEST_SAT.', sys_scanned=0) api = SatelliteSixV2(scan_job, scan_task) job_conn_result = JobConnectionResult() job_conn_result.save() connection_results = TaskConnectionResult( job_connection_result=job_conn_result) connection_results.save() api.connect_scan_task.connection_result = connection_results api.connect_scan_task.connection_result.save() sys_result = SystemConnectionResult( name='sys1_1', status=SystemInspectionResult.SUCCESS, task_connection_result=api.connect_scan_task.connection_result) sys_result.save() api.connect_scan_task.save() hosts_url = 'https://{sat_host}:{port}/api/v2/hosts' with requests_mock.Mocker() as mocker: url = construct_url(url=hosts_url, sat_host='1.2.3.4') jsonresult = { 'total': 1, 'subtotal': 1, 'page': 1, 'per_page': 100, 'results': [{ 'id': 10, 'name': 'sys10' }] } # noqa mocker.get(url, status_code=200, json=jsonresult) api.hosts_facts(Value('i', ScanJob.JOB_RUN)) inspect_result = scan_task.inspection_result self.assertEqual(len(inspect_result.systems.all()), 1)
def run_with_result_store(self, result_store): """Run with a given ConnectResultStore.""" serializer = SourceSerializer(self.scan_task.source) source = serializer.data if self.scan_job.options is None: forks = ScanOptions.get_default_forks() else: forks = self.scan_job.options.max_concurrency connection_port = source['port'] credentials = source['credentials'] remaining_hosts = result_store.remaining_hosts() for cred_id in credentials: credential = Credential.objects.get(pk=cred_id) if not remaining_hosts: message = 'Skipping credential %s. No remaining hosts.' % \ credential.name self.scan_task.log_message(message) break message = 'Attempting credential %s.' % credential.name self.scan_task.log_message(message) cred_data = CredentialSerializer(credential).data callback = ConnectResultCallback(result_store, credential, self.scan_task.source) try: connect(remaining_hosts, callback, cred_data, connection_port, forks=forks) except AnsibleError as ansible_error: remaining_hosts_str = ', '.join(result_store.remaining_hosts()) error_message = 'Connect scan task failed with credential %s.'\ ' Error: %s Hosts: %s' %\ (credential.name, ansible_error, remaining_hosts_str) return error_message, ScanTask.FAILED remaining_hosts = result_store.remaining_hosts() logger.debug('Failed systems: %s', remaining_hosts) for host in remaining_hosts: # We haven't connected to these hosts with any # credentials, so they have failed. result_store.record_result(host, self.scan_task.source, None, SystemConnectionResult.FAILED) return None, ScanTask.COMPLETED
def test_get_extra_vars_missing_options(self): """Tests the get_default_extra_vars.""" extra_vars = ScanOptions.get_default_extra_vars() expected_vars = { 'jboss_eap': True, 'jboss_fuse': True, 'jboss_brms': True, 'jboss_ws': True, 'jboss_eap_ext': False, 'jboss_fuse_ext': False, 'jboss_brms_ext': False, 'jboss_ws_ext': False } self.assertEqual(extra_vars, expected_vars)
def setUp(self): """Create test case setup.""" self.cred = Credential(name='cred1', username='******', password='******', ssh_keyfile='keyfile', become_method='sudo', become_user='******', become_password='******') self.cred.save() self.source = Source(name='source1', port=22) self.source.save() self.source.credentials.add(self.cred) self.source.hosts = '["1.2.3.4"]' self.source.save() self.scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_CONNECT, start_time=datetime.utcnow()) self.scan_task.update_stats('TEST NETWORK CONNECT.', sys_failed=0) self.scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_CONNECT) self.scan_job.save() self.scan_job.sources.add(self.source) self.scan_job.tasks.add(self.scan_task) scan_options = ScanOptions() scan_options.save() self.scan_job.options = scan_options self.scan_job.save() self.conn_results = JobConnectionResult() self.conn_results.save() self.scan_job.connection_results = self.conn_results self.scan_job.save()
def __init__(self, scan_job, scan_task): """Set context for interface.""" self.scan_job = scan_job if scan_job.options is None: self.max_concurrency = ScanOptions.get_default_forks() else: self.max_concurrency = scan_job.options.max_concurrency if scan_task.scan_type == ScanTask.SCAN_TYPE_CONNECT: self.connect_scan_task = scan_task self.inspect_scan_task = None else: self.connect_scan_task = scan_task.prerequisites.first() self.inspect_scan_task = scan_task self.source = scan_task.source
def setUp(self): """Create test setup.""" management.call_command('flush', '--no-input') self.cred = Credential.objects.create(name='cred1', username='******', password='******', become_password=None, ssh_keyfile=None) self.cred_for_upload = self.cred.id self.source = Source(name='source1', source_type='network', port=22) self.source.save() self.source2 = Source(name='source2', source_type='network', port=22) self.source2.save() self.source2.credentials.add(self.cred) self.concurrency = ScanOptions.get_default_forks()
class ScanOptionsSerializer(NotEmptySerializer): """Serializer for the ScanOptions model.""" max_concurrency = IntegerField(required=False, min_value=1, max_value=200, default=ScanOptions.get_default_forks()) disabled_optional_products = DisableOptionalProductsOptionsSerializer( required=False) enabled_extended_product_search = ExtendedProductSearchOptionsSerializer( required=False) class Meta: """Metadata for serializer.""" model = ScanOptions fields = [ 'max_concurrency', 'disabled_optional_products', 'enabled_extended_product_search' ]
def _inspect_scan(self, manager_interrupt, connected, roles=DEFAULT_ROLES, base_ssh_executable=None, ssh_timeout=None): """Execute the host scan with the initialized source. :param manager_interrupt: Signal used to communicate termination of scan :param connected: list of (host, credential) pairs to inspect :param roles: list of roles to execute :param base_ssh_executable: ssh executable, or None for 'ssh'. Will be wrapped with a timeout before being passed to Ansible. :param ssh_timeout: string in the format of the 'timeout' command. Timeout for individual tasks. :returns: An array of dictionaries of facts """ connection_port = self.scan_task.source.port if self.scan_task.source.options is not None: use_paramiko = self.scan_task.source.options.use_paramiko else: use_paramiko = None if self.scan_job.options is not None: forks = self.scan_job.options.max_concurrency extra_vars = self.scan_job.options.get_extra_vars() else: forks = ScanOptions.get_default_forks() extra_vars = ScanOptions.get_default_extra_vars() if extra_vars.get(ScanOptions.EXT_PRODUCT_SEARCH_DIRS) is None: extra_vars[ScanOptions.EXT_PRODUCT_SEARCH_DIRS] = \ ' '.join(DEFAULT_SCAN_DIRS) ssh_executable = os.path.abspath( os.path.join(os.path.dirname(__file__), '../../../bin/timeout_ssh')) base_ssh_executable = base_ssh_executable or 'ssh' ssh_timeout = ssh_timeout or settings.QPC_SSH_INSPECT_TIMEOUT # pylint: disable=line-too-long # the ssh arg is required for become-pass because # ansible checks for an exact string match of ssh # anywhere in the command array # See https://github.com/ansible/ansible/blob/stable-2.3/lib/ansible/plugins/connection/ssh.py#L490-L500 # noqa # timeout_ssh will remove the ssh argument before running the command ssh_args = [ '--executable=' + base_ssh_executable, '--timeout=' + ssh_timeout, 'ssh' ] group_names, inventory = _construct_scan_inventory( connected, connection_port, forks, ssh_executable=ssh_executable, ssh_args=ssh_args) inventory_file = write_inventory(inventory) error_msg = '' log_message = 'START INSPECT PROCESSING GROUPS'\ ' with use_paramiko: %s, '\ '%d forks and extra_vars=%s' % (use_paramiko, forks, extra_vars) self.scan_task.log_message(log_message) scan_result = ScanTask.COMPLETED scan_message = 'success' for idx, group_name in enumerate(group_names): if manager_interrupt.value == ScanJob.JOB_TERMINATE_CANCEL: raise NetworkCancelException() if manager_interrupt.value == ScanJob.JOB_TERMINATE_PAUSE: raise NetworkPauseException() log_message = 'START INSPECT PROCESSING GROUP %d of %d' % ( (idx + 1), len(group_names)) self.scan_task.log_message(log_message) callback =\ InspectResultCallback( scan_task=self.scan_task) playbook = { 'name': 'scan systems for product fingerprint facts', 'hosts': group_name, 'gather_facts': False, 'roles': roles } result = run_playbook(inventory_file, callback, playbook, extra_vars, use_paramiko, forks=forks) if result != TaskQueueManager.RUN_OK: new_error_msg = _construct_error_msg(result) callback.finalize_failed_hosts() if result not in [ TaskQueueManager.RUN_UNREACHABLE_HOSTS, TaskQueueManager.RUN_FAILED_HOSTS ]: error_msg += '{}\n'.format(new_error_msg) if error_msg != '': raise AnsibleError(error_msg) return scan_message, scan_result
def setUp(self): """Create test case setup.""" self.cred = Credential(name='cred1', username='******', password='******', sudo_password=None, ssh_keyfile=None) self.cred.save() self.source = Source(name='source1', port=22) self.source.save() self.source.credentials.add(self.cred) self.host = HostRange(host_range='1.2.3.4', source_id=self.source.id) self.host.save() self.source.hosts.add(self.host) self.connect_scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_CONNECT, status=ScanTask.COMPLETED) self.connect_scan_task.systems_failed = 0 self.connect_scan_task.save() self.inspect_scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_INSPECT) self.inspect_scan_task.systems_failed = 0 self.inspect_scan_task.save() self.inspect_scan_task.prerequisites.add(self.connect_scan_task) self.inspect_scan_task.save() self.scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_INSPECT) self.scan_job.save() self.scan_job.tasks.add(self.connect_scan_task) self.scan_job.tasks.add(self.inspect_scan_task) scan_options = ScanOptions() scan_options.save() self.scan_job.options = scan_options self.scan_job.save() self.fact_endpoint = 'http://testserver' + reverse('facts-list') self.conn_results = ConnectionResults(scan_job=self.scan_job) self.conn_results.save() self.conn_result = ConnectionResult(scan_task=self.connect_scan_task, source=self.source) self.conn_result.save() success_sys = SystemConnectionResult( name='1.2.3.4', credential=self.cred, status=SystemConnectionResult.SUCCESS) success_sys.save() failed_sys = SystemConnectionResult( name='1.1.1.2', status=SystemConnectionResult.FAILED) failed_sys.save() self.conn_result.systems.add(success_sys) self.conn_result.systems.add(failed_sys) self.conn_result.save() self.conn_results.results.add(self.conn_result) self.conn_results.save() self.inspect_results = InspectionResults(scan_job=self.scan_job) self.inspect_results.save()
def _inspect_scan(self, connected, roles=DEFAULT_ROLES, base_ssh_executable=None, ssh_timeout=None): """Execute the host scan with the initialized source. :param connected: list of (host, credential) pairs to inspect :param roles: list of roles to execute :param base_ssh_executable: ssh executable, or None for 'ssh'. Will be wrapped with a timeout before being passed to Ansible. :param ssh_timeout: string in the format of the 'timeout' command. Timeout for individual tasks. :returns: An array of dictionaries of facts """ playbook = {'name': 'scan systems for product fingerprint facts', 'hosts': 'all', 'gather_facts': False, 'strategy': 'free', 'roles': roles} connection_port = self.scan_task.source.port if self.scan_job.options is not None: forks = self.scan_job.options.max_concurrency extra_vars = self.scan_job.options.get_extra_vars() else: forks = ScanOptions.get_default_forks() extra_vars = ScanOptions.get_default_extra_vars() if extra_vars.get(ScanOptions.EXT_PRODUCT_SEARCH_DIRS) is None: extra_vars[ScanOptions.EXT_PRODUCT_SEARCH_DIRS] = \ ' '.join(DEFAULT_SCAN_DIRS) ssh_executable = os.path.abspath( os.path.join(os.path.dirname(__file__), '../../../bin/timeout_ssh')) base_ssh_executable = base_ssh_executable or 'ssh' ssh_timeout = ssh_timeout or DEFAULT_TIMEOUT ssh_args = ['--executable=' + base_ssh_executable, '--timeout=' + ssh_timeout] group_names, inventory = _construct_scan_inventory( connected, connection_port, forks, ssh_executable=ssh_executable, ssh_args=ssh_args) inventory_file = write_inventory(inventory) error_msg = '' log_message = 'START PROCESSING GROUPS with %d forks' \ ' and extra_vars=%s' % (forks, extra_vars) self.scan_task.log_message(log_message) scan_result = ScanTask.COMPLETED scan_message = 'success' for idx, group_name in enumerate(group_names): log_message = 'START PROCESSING GROUP %d of %d' % ( (idx + 1), len(group_names)) self.scan_task.log_message(log_message) callback =\ InspectResultCallback( scan_task=self.scan_task) playbook = {'name': 'scan systems for product fingerprint facts', 'hosts': group_name, 'gather_facts': False, 'roles': roles} result = run_playbook( inventory_file, callback, playbook, extra_vars, forks=forks) if result != TaskQueueManager.RUN_OK: new_error_msg = _construct_error_msg(result) callback.finalize_failed_hosts() if result != TaskQueueManager.RUN_UNREACHABLE_HOSTS and \ result != TaskQueueManager.RUN_FAILED_HOSTS: error_msg += '{}\n'.format(new_error_msg) if error_msg != '': raise AnsibleError(error_msg) return scan_message, scan_result
def setUp(self): """Create test case setup.""" self.cred = Credential( name='cred1', username='******', password='******', ssh_keyfile='keyfile', become_method='sudo', become_user='******', become_password='******') self.cred.save() # Source with excluded hosts self.source = Source( name='source1', hosts='["1.2.3.4", "1.2.3.5"]', exclude_hosts='["1.2.3.5", "1.2.3.6"]', source_type='network', port=22) self.source.save() self.source.credentials.add(self.cred) self.source.save() self.scan_job, self.scan_task = create_scan_job( self.source, ScanTask.SCAN_TYPE_CONNECT) self.scan_task.update_stats('TEST NETWORK CONNECT.', sys_failed=0) # Source without excluded hosts self.source2 = Source( name='source2', hosts='["1.2.3.4"]', source_type='network', port=22) self.source2.save() self.source2.credentials.add(self.cred) self.source2.save() self.scan_job2, self.scan_task2 = create_scan_job( self.source2, ScanTask.SCAN_TYPE_CONNECT, 'source2',) self.scan_task2.update_stats('TEST NETWORK CONNECT.', sys_failed=0) # Scans with options & no excluded hosts source_options = SourceOptions(use_paramiko=True) source_options.save() self.source3 = Source( name='source3', hosts='["1.2.3.4","1.2.3.5","1.2.3.6"]', source_type='network', port=22, options=source_options) self.source3.save() self.source3.credentials.add(self.cred) self.source3.save() scan_options = ScanOptions(max_concurrency=2) scan_options.save() self.scan_job3, self.scan_task3 = create_scan_job( self.source3, ScanTask.SCAN_TYPE_CONNECT, 'source3', scan_options) self.scan_task3.update_stats('TEST NETWORK CONNECT.', sys_failed=0) self.concurrency = ScanOptions.get_default_forks()
def _inspect_scan(self, manager_interrupt, connected, base_ssh_executable=None, ssh_timeout=None): """Execute the host scan with the initialized source. :param manager_interrupt: Signal used to communicate termination of scan :param connected: list of (host, credential) pairs to inspect :param roles: list of roles to execute :param base_ssh_executable: ssh executable, or None for 'ssh'. Will be wrapped with a timeout before being passed to Ansible. :param ssh_timeout: string in the format of the 'timeout' command. Timeout for individual tasks. :returns: An array of dictionaries of facts Note: base_ssh_executable & ssh_timeout are parameters that are only used for testing. """ # pylint: disable=too-many-locals,too-many-arguments # pylint: disable=too-many-branches,too-many-statements connection_port = self.scan_task.source.port if self.scan_task.source.options is not None: use_paramiko = self.scan_task.source.options.use_paramiko else: use_paramiko = False if self.scan_job.options is not None: forks = self.scan_job.options.max_concurrency extra_vars = self.scan_job.options.get_extra_vars() else: forks = ScanOptions.get_default_forks() extra_vars = ScanOptions.get_default_extra_vars() if extra_vars.get(ScanOptions.EXT_PRODUCT_SEARCH_DIRS) is None: extra_vars[ScanOptions.EXT_PRODUCT_SEARCH_DIRS] = \ ' '.join(DEFAULT_SCAN_DIRS) ssh_executable = os.path.abspath( os.path.join(os.path.dirname(__file__), '../../../bin/timeout_ssh')) base_ssh_executable = base_ssh_executable or 'ssh' ssh_timeout = ssh_timeout or settings.QPC_SSH_INSPECT_TIMEOUT # pylint: disable=line-too-long # the ssh arg is required for become-pass because # ansible checks for an exact string match of ssh # anywhere in the command array # See https://github.com/ansible/ansible/blob/stable-2.3/lib/ansible/plugins/connection/ssh.py#L490-L500 # noqa # timeout_ssh will remove the ssh argument before running the command ssh_args = [ '--executable=' + base_ssh_executable, '--timeout=' + ssh_timeout, 'ssh' ] group_names, inventory = _construct_scan_inventory( connected, connection_port, forks, ssh_executable=ssh_executable, ssh_args=ssh_args) inventory_file = write_to_yaml(inventory) error_msg = None log_message = 'START INSPECT PROCESSING GROUPS'\ ' with use_paramiko: %s, '\ '%d forks and extra_vars=%s' % (use_paramiko, forks, extra_vars) self.scan_task.log_message(log_message) scan_result = ScanTask.COMPLETED # Build Ansible Runner Dependencies for idx, group_name in enumerate(group_names): check_manager_interrupt(manager_interrupt.value) log_message = 'START INSPECT PROCESSING GROUP %d of %d' % ( (idx + 1), len(group_names)) self.scan_task.log_message(log_message) call = InspectResultCallback(self.scan_task, manager_interrupt) # Build Ansible Runner Parameters runner_settings = { 'idle_timeout': int(settings.NETWORK_INSPECT_JOB_TIMEOUT), 'job_timeout': int(settings.NETWORK_INSPECT_JOB_TIMEOUT), 'pexpect_timeout': 5 } playbook_path = os.path.join(settings.BASE_DIR, 'scanner/network/runner/inspect.yml') extra_vars['variable_host'] = group_name cmdline_list = [] vault_file_path = '--vault-password-file=%s' % ( settings.DJANGO_SECRET_PATH) cmdline_list.append(vault_file_path) forks_cmd = '--forks=%s' % (forks) cmdline_list.append(forks_cmd) if use_paramiko: cmdline_list.append('--connection=paramiko') all_commands = ' '.join(cmdline_list) if int(settings.ANSIBLE_LOG_LEVEL) == 0: quiet_bool = True verbosity_lvl = 0 else: quiet_bool = False verbosity_lvl = int(settings.ANSIBLE_LOG_LEVEL) try: runner_obj = ansible_runner.run( quiet=quiet_bool, settings=runner_settings, inventory=inventory_file, extravars=extra_vars, event_handler=call.event_callback, cancel_callback=call.cancel_callback, playbook=playbook_path, cmdline=all_commands, verbosity=verbosity_lvl) except Exception as error: error_msg = error raise AnsibleRunnerException(error_msg) final_status = runner_obj.status if final_status != 'successful': if final_status == 'canceled': interrupt = manager_interrupt.value if interrupt == ScanJob.JOB_TERMINATE_CANCEL: msg = log_messages.NETWORK_PLAYBOOK_STOPPED % ( 'INSPECT', 'canceled') else: msg = log_messages.NETWORK_PLAYBOOK_STOPPED % ( 'INSPECT', 'paused') self.scan_task.log_message(msg) check_manager_interrupt(interrupt) if final_status not in ['unreachable', 'failed']: if final_status == 'timeout': error_msg = log_messages.NETWORK_TIMEOUT_ERR else: error_msg = log_messages.NETWORK_UNKNOWN_ERR scan_result = ScanTask.FAILED call.finalize_failed_hosts() return error_msg, scan_result
def setUp(self): """Create test case setup.""" self.cred = Credential( name='cred1', username='******', password='******', ssh_keyfile=None, become_method=None, become_user=None, become_password=None) self.cred.save() hc_serializer = CredentialSerializer(self.cred) self.cred_data = hc_serializer.data self.source = Source( name='source1', port=22, hosts='["1.2.3.4"]') self.source.save() self.source.credentials.add(self.cred) self.host_list = [('1.2.3.4', self.cred_data)] self.connect_scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_CONNECT, status=ScanTask.COMPLETED, start_time=datetime.utcnow()) self.connect_scan_task.update_stats( 'TEST NETWORK CONNECT.', sys_failed=0) self.inspect_scan_task = ScanTask(source=self.source, scan_type=ScanTask.SCAN_TYPE_INSPECT, start_time=datetime.utcnow()) self.inspect_scan_task.update_stats( 'TEST NETWORK INSPECT.', sys_failed=0) self.inspect_scan_task.prerequisites.add(self.connect_scan_task) self.inspect_scan_task.save() self.scan_job = ScanJob(scan_type=ScanTask.SCAN_TYPE_INSPECT) self.scan_job.save() self.scan_job.tasks.add(self.connect_scan_task) self.scan_job.tasks.add(self.inspect_scan_task) scan_options = ScanOptions() scan_options.disable_optional_products = {'jboss_eap': False, 'jboss_fuse': False, 'jboss_brms': False} scan_options.save() self.scan_job.options = scan_options self.scan_job.save() self.fact_endpoint = 'http://testserver' + reverse('facts-list') self.conn_results = JobConnectionResult() self.conn_results.save() self.scan_job.connection_results = self.conn_results self.conn_result = TaskConnectionResult( scan_task=self.connect_scan_task, source=self.source) self.conn_result.save() success_sys = SystemConnectionResult( name='1.2.3.4', credential=self.cred, status=SystemConnectionResult.SUCCESS) success_sys.save() failed_sys = SystemConnectionResult( name='1.1.1.2', status=SystemConnectionResult.FAILED) failed_sys.save() self.conn_result.systems.add(success_sys) self.conn_result.systems.add(failed_sys) self.conn_result.save() self.conn_results.results.add(self.conn_result) self.conn_results.save() self.scan_job.connection_results = self.conn_results self.inspect_results = JobInspectionResult() self.inspect_results.save() self.scan_job.inspection_results = self.inspect_results self.scan_job.save()