Skip to content

Commit

Permalink
Add cancel cli and documentation. Closes #148.
Browse files Browse the repository at this point in the history
  • Loading branch information
chambridge committed Nov 9, 2017
1 parent cf1023c commit 2b8fd30
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 3 deletions.
27 changes: 25 additions & 2 deletions docs/source/man.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ Use the ``qpc scan`` command to run discovery and inspection scans on the networ

Required. Contains the name of the network profile to use to run the scan.

``--max-concurrency=concurrency``
``--max-concurrency=concurrency``

The number of parallel system scans. If not provided the default of 50 is utilized.
The number of parallel system scans. If not provided the default of 50 is utilized.

Listing and Showing Scans
~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -258,6 +258,29 @@ The ``qpc scan show`` command is the same as the ``qpc scan list`` command, exce
Required. Contains the scan identifier to display.


Controlling Scans
~~~~~~~~~~~~~~~~~

When scans are queued and running you may have the need to control the execution of scans due to various factors.

The ``qpc scan pause`` command will hault the execution of a scan, but allow for it to be restarted at a later time.

**qpc scan pause --id=** *scan_identifier*

``--id=scan_identifier``

Required. Contains the scan identifier to pause.


The ``qpc scan cancel`` command will cancel the execution of a scan.

**qpc scan cancel --id=** *scan_identifier*

``--id=scan_identifier``

Required. Contains the scan identifier to cancel.


Options for All Commands
------------------------

Expand Down
4 changes: 3 additions & 1 deletion qpc/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from qpc.scan.list import ScanListCommand
from qpc.scan.show import ScanShowCommand
from qpc.scan.pause import ScanPauseCommand
from qpc.scan.cancel import ScanCancelCommand
from qpc.translation import _
import qpc.messages as messages
from . import __version__
Expand Down Expand Up @@ -71,7 +72,8 @@ def __init__(self, name='cli', usage=None, shortdesc=None,

self._add_subcommand(scan.SUBCOMMAND,
[ScanStartCommand, ScanListCommand,
ScanShowCommand, ScanPauseCommand])
ScanShowCommand, ScanPauseCommand,
ScanCancelCommand])
ensure_data_dir_exists()
ensure_config_dir_exists()

Expand Down
1 change: 1 addition & 0 deletions qpc/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
SCAN_LIST_NO_SCANS = 'No scans exist yet.'
SCAN_STARTED = 'Scan "%s" started'
SCAN_PAUSED = 'Scan "%s" paused'
SCAN_CANCELED = 'Scan "%s" canceled'

VERBOSITY_HELP = 'Verbose mode. Use up to -vvvv for more verbosity.'

Expand Down
1 change: 1 addition & 0 deletions qpc/scan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
LIST = 'list'
SHOW = 'show'
PAUSE = 'pause'
CANCEL = 'cancel'


SCAN_URI = '/api/v1/scans/'
Expand Down
48 changes: 48 additions & 0 deletions qpc/scan/cancel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
"""ScanCancelCommand is used to cancel a specific system scan."""

from __future__ import print_function
from requests import codes
from qpc.clicommand import CliCommand
import qpc.scan as scan
from qpc.request import PUT
from qpc.translation import _
import qpc.messages as messages


# pylint: disable=too-few-public-methods
class ScanCancelCommand(CliCommand):
"""Defines the cancel command.
This command is for cancel a specific scan to gather facts.
"""

SUBCOMMAND = scan.SUBCOMMAND
ACTION = scan.CANCEL

def __init__(self, subparsers):
"""Create command."""
# pylint: disable=no-member
CliCommand.__init__(self, self.SUBCOMMAND, self.ACTION,
subparsers.add_parser(self.ACTION), PUT,
scan.SCAN_URI, [codes.ok])
self.parser.add_argument('--id', dest='id', metavar='ID',
help=_(messages.SCAN_ID_HELP), required=True)

def _validate_args(self):
CliCommand._validate_args(self)
if self.args.id:
self.req_path = self.req_path + str(self.args.id) + '/cancel/'

def _handle_response_success(self):
print(_(messages.SCAN_CANCELED % (self.args.id,)))
100 changes: 100 additions & 0 deletions qpc/scan/tests_cancel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
"""Test the CLI module."""

import unittest
import sys
from io import StringIO
from argparse import ArgumentParser, Namespace
import requests
import requests_mock
from qpc.tests_utilities import HushUpStderr, redirect_stdout
from qpc.request import BASE_URL, CONNECTION_ERROR_MSG, SSL_ERROR_MSG
from qpc.scan import SCAN_URI
from qpc.scan.cancel import ScanCancelCommand

PARSER = ArgumentParser()
SUBPARSER = PARSER.add_subparsers(dest='subcommand')


class ScanCancelCliTests(unittest.TestCase):
"""Class for testing the scan cancel commands for qpc."""

def setUp(self):
"""Create test setup."""
# Temporarily disable stderr for these tests, CLI errors clutter up
# nosetests command.
self.orig_stderr = sys.stderr
sys.stderr = HushUpStderr()

def tearDown(self):
"""Remove test setup."""
# Restore stderr
sys.stderr = self.orig_stderr

def test_cancel_scan_ssl_err(self):
"""Testing the cancel scan command with a connection error."""
scan_out = StringIO()
url = BASE_URL + SCAN_URI + '1/cancel/'
with requests_mock.Mocker() as mocker:
mocker.put(url, exc=requests.exceptions.SSLError)
nsc = ScanCancelCommand(SUBPARSER)
args = Namespace(id='1')
with self.assertRaises(SystemExit):
with redirect_stdout(scan_out):
nsc.main(args)
self.assertEqual(scan_out.getvalue(), SSL_ERROR_MSG)

def test_cancel_scan_conn_err(self):
"""Testing the cancel scan command with a connection error."""
scan_out = StringIO()
url = BASE_URL + SCAN_URI + '1/cancel/'
with requests_mock.Mocker() as mocker:
mocker.put(url, exc=requests.exceptions.ConnectTimeout)
nsc = ScanCancelCommand(SUBPARSER)
args = Namespace(id='1')
with self.assertRaises(SystemExit):
with redirect_stdout(scan_out):
nsc.main(args)
self.assertEqual(scan_out.getvalue(),
CONNECTION_ERROR_MSG)

def test_cancel_scan_internal_err(self):
"""Testing the cancel scan command with an internal error."""
scan_out = StringIO()
url = BASE_URL + SCAN_URI + '1/cancel/'
with requests_mock.Mocker() as mocker:
mocker.put(url, status_code=500, json={'error': ['Server Error']})
nsc = ScanCancelCommand(SUBPARSER)
args = Namespace(id='1')
with self.assertRaises(SystemExit):
with redirect_stdout(scan_out):
nsc.main(args)
self.assertEqual(scan_out.getvalue(), 'Server Error')

def test_cancel_scan_data(self):
"""Testing the cancel scan command successfully with stubbed data."""
scan_out = StringIO()
url = BASE_URL + SCAN_URI + '1/cancel/'
scan_entry = {'id': 1,
'profile': {
'id': 1,
'name': 'scan1'},
'scan_type': 'host',
'status': 'completed'}
with requests_mock.Mocker() as mocker:
mocker.put(url, status_code=200, json=scan_entry)
nsc = ScanCancelCommand(SUBPARSER)
args = Namespace(id='1')
with redirect_stdout(scan_out):
nsc.main(args)
expected = 'Scan "1" canceled\n'
self.assertEqual(scan_out.getvalue(), expected)

0 comments on commit 2b8fd30

Please sign in to comment.