Skip to content

Commit 646bd08

Browse files
author
Juliya Smith
committed
Merge pull request #8 in INT/security-event-cli from juliya.smith/INTEG-698/error-message-for-tcp-port-error to master
* commit '6f8130c85abcc44e3fc353f302648a3bfd37456d': Remove none checks because they will never happen Seperate state modifications to other function in args Set defaults in mian Add docstring for get_logger Format Fix tests Code clean up better error handlin better error handlin Use dest args dto Better error handling: Use OSError instead of socket_error Test for socket error Remove args arg Remove args arg Catch all socket errors
2 parents 0164892 + 6f8130c commit 646bd08

File tree

6 files changed

+126
-67
lines changed

6 files changed

+126
-67
lines changed

c42seceventcli/aed/args.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def get_args():
2727
cli_args = vars(parser.parse_args())
2828
args = _union_cli_args_with_config_file_args(cli_args)
2929
args.cli_parser = parser
30+
args.initialize_args()
3031
args.verify_authority_arg()
3132
args.verify_username_arg()
3233
args.verify_destination_args()
@@ -99,6 +100,14 @@ def __init__(self):
99100
self.begin_date = AEDArgs._get_default_begin_date()
100101
self.end_date = AEDArgs._get_default_end_date()
101102

103+
def initialize_args(self):
104+
self.destination_type = self.destination_type.lower()
105+
try:
106+
self.destination_port = int(self.destination_port)
107+
except ValueError:
108+
msg = "Destination port '{0}' not a base 10 integer.".format(self.destination_port)
109+
self._raise_value_error(msg)
110+
102111
@staticmethod
103112
def _get_default_begin_date():
104113
default_begin_date = datetime.now() - timedelta(days=60)
@@ -118,6 +127,10 @@ def verify_username_arg(self):
118127
self._raise_value_error("Code42 username not provided.")
119128

120129
def verify_destination_args(self):
130+
self._verify_stdout_destination()
131+
self._verify_server_destination()
132+
133+
def _verify_stdout_destination(self):
121134
if self.destination_type == "stdout" and self.destination is not None:
122135
msg = (
123136
"Destination '{0}' not applicable for stdout. "
@@ -126,10 +139,12 @@ def verify_destination_args(self):
126139
msg = msg.format(self.destination)
127140
self._raise_value_error(msg)
128141

142+
def _verify_file_destination(self):
129143
if self.destination_type == "file" and self.destination is None:
130144
msg = "Missing file name. Try: '--dest path/to/file'."
131145
self._raise_value_error(msg)
132146

147+
def _verify_server_destination(self):
133148
if self.destination_type == "server" and self.destination is None:
134149
msg = "Missing server URL. Try: '--dest https://syslog.example.com'."
135150
self._raise_value_error(msg)

c42seceventcli/aed/main.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from socket import gaierror
2+
from socket import gaierror, herror, timeout
33
from urllib3 import disable_warnings
44
from urllib3.exceptions import InsecureRequestWarning
55
from datetime import datetime, timedelta
@@ -58,51 +58,50 @@ def _create_handlers(args):
5858
handlers.handle_error = error_logger.error
5959
output_format = args.output_format
6060
logger_formatter = _get_log_formatter(output_format)
61+
destination_args = _create_destination_args(args)
6162
logger = _get_logger(
62-
args,
63-
formatter=logger_formatter,
64-
service_name=_SERVICE_NAME,
65-
destination=args.destination,
66-
destination_type=args.destination_type,
67-
destination_port=int(args.destination_port),
68-
destination_protocol=args.destination_protocol,
63+
formatter=logger_formatter, service_name=_SERVICE_NAME, destination_args=destination_args
6964
)
7065
handlers.handle_response = _get_response_handler(logger)
7166
return handlers
7267

7368

74-
def _get_logger(
75-
args,
76-
formatter,
77-
service_name,
78-
destination,
79-
destination_type,
80-
destination_port=514,
81-
destination_protocol="TCP",
82-
):
69+
def _create_destination_args(args):
70+
destination_args = common.DestinationArgs()
71+
destination_args.destination_type = args.destination_type
72+
destination_args.destination = args.destination
73+
destination_args.destination_port = args.destination_port
74+
destination_args.destination_protocol = args.destination_protocol
75+
return destination_args
76+
77+
78+
def _get_logger(formatter, service_name, destination_args):
8379
try:
8480
return common.get_logger(
85-
formatter=formatter,
86-
service_name=service_name,
87-
destination=destination,
88-
destination_type=destination_type,
89-
destination_port=destination_port,
90-
destination_protocol=destination_protocol,
91-
)
92-
except gaierror:
93-
args.cli_parser.print_usage()
94-
print(
95-
"Error with provided server destination arguments: hostname={0}, port={1}, protocol={2}.".format(
96-
destination, destination_port, destination_protocol
97-
)
81+
formatter=formatter, service_name=service_name, destination_args=destination_args
9882
)
83+
except (herror, gaierror, timeout) as ex:
84+
print(repr(ex))
85+
_print_server_args(destination_args)
9986
exit(1)
100-
except IOError:
101-
args.cli_parser.print_usage()
102-
print("Error with provided file path {0}. Try --dest path/to/file.".format(destination))
87+
except IOError as ex:
88+
print(repr(ex))
89+
if ex.errno == 61:
90+
_print_server_args(destination_args)
91+
exit(1)
92+
93+
print("File path: {0}.".format(destination_args.destination))
10394
exit(1)
10495

10596

97+
def _print_server_args(server_args):
98+
print(
99+
"Hostname={0}, port={1}, protocol={2}.".format(
100+
server_args.destination, server_args.destination_port, server_args.destination_protocol
101+
)
102+
)
103+
104+
106105
def _set_up_cursor_store(record_cursor, clear_cursor, handlers):
107106
if record_cursor or clear_cursor:
108107
store = AEDCursorStore()

c42seceventcli/common/util.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,39 +65,45 @@ def get_error_logger(service_name):
6565
return logger
6666

6767

68-
def get_logger(
69-
formatter,
70-
service_name,
71-
destination,
72-
destination_type,
73-
destination_port=514,
74-
destination_protocol="TCP",
75-
):
76-
destination_type = destination_type.lower()
68+
class DestinationArgs(object):
69+
destination_type = None
70+
destination = None
71+
destination_port = None
72+
destination_protocol = None
73+
74+
75+
def get_logger(formatter, service_name, destination_args):
76+
"""Args:
77+
formatter: The formatter for logger.
78+
service_name: The name of the script getting the logger.
79+
Necessary for distinguishing multiple loggers.
80+
destination_args: DTO holding the destination_type, destination, destination_port, and destination_protocol.
81+
Returns:
82+
A logger with the correct handler per destination_type.
83+
For destination_type == stdout, it uses a StreamHandler.
84+
For destination_type == file, it uses a FileHandler.
85+
For destination_type == server, it uses a NoPrioritySyslogHandler.
86+
"""
87+
7788
logger = logging.getLogger("{0}_logger".format(service_name))
78-
handler = _get_log_handler(
79-
destination=destination,
80-
destination_type=destination_type,
81-
destination_port=destination_port,
82-
destination_protocol=destination_protocol,
83-
)
89+
handler = _get_log_handler(destination_args)
8490
handler.setFormatter(formatter)
8591
logger.addHandler(handler)
8692
logger.setLevel(logging.INFO)
8793
return logger
8894

8995

90-
def _get_log_handler(
91-
destination, destination_type, destination_port=514, destination_protocol="TCP"
92-
):
93-
if destination_type == "stdout":
96+
def _get_log_handler(destination_args):
97+
if destination_args.destination_type == "stdout":
9498
return logging.StreamHandler(sys.stdout)
95-
elif destination_type == "server":
99+
elif destination_args.destination_type == "server":
96100
return NoPrioritySysLogHandler(
97-
hostname=destination, port=destination_port, protocol=destination_protocol
101+
hostname=destination_args.destination,
102+
port=destination_args.destination_port,
103+
protocol=destination_args.destination_protocol,
98104
)
99-
elif destination_type == "file":
100-
return logging.FileHandler(filename=destination)
105+
elif destination_args.destination_type == "file":
106+
return logging.FileHandler(filename=destination_args.destination)
101107

102108

103109
def get_stored_password(service_name, username):

tests/aed/test_args.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,18 @@ def test_get_args_calls_sec_args_try_set_with_expected_args(
8484
mock_setter.assert_called_once_with(key, expected_cli_val, expected_config_val)
8585

8686

87-
def test_get_args_when_destination_is_not_none_and_destination_type_is_stdout_raises_value_error(patches):
87+
def test_get_args_when_destination_is_not_none_and_destination_type_is_stdout_raises_value_error(
88+
patches
89+
):
8890
patches.cli_args.destination_type = "stdout"
8991
patches.cli_args.destination = "Delaware"
9092
with pytest.raises(ValueError):
9193
get_args()
9294

9395

94-
def test_get_args_when_destination_is_none_and_destination_type_is_server_raises_value_error(patches):
96+
def test_get_args_when_destination_is_none_and_destination_type_is_server_raises_value_error(
97+
patches
98+
):
9599
patches.cli_args.destination_type = "server"
96100
patches.cli_args.destination = None
97101
with pytest.raises(ValueError):

tests/aed/test_main.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
from datetime import datetime, timedelta
3-
from socket import gaierror
3+
from socket import herror, gaierror, timeout
44

55
from py42 import settings
66
import py42.debug_level as debug_level
@@ -222,30 +222,59 @@ def test_main_when_destination_port_is_set_passes_port_to_get_logger(patches):
222222
expected = 1000
223223
patches.aed_args.destination_port = expected
224224
main.main()
225-
actual = patches.get_logger.call_args[1]["destination_port"]
225+
actual = patches.get_logger.call_args[1]["destination_args"].destination_port
226226
assert actual == expected
227227

228228

229229
def test_main_when_given_destination_protocol_via_cli_passes_port_to_get_logger(patches):
230230
expected = "SOME PROTOCOL"
231231
patches.aed_args.destination_protocol = expected
232232
main.main()
233-
actual = patches.get_logger.call_args[1]["destination_protocol"]
233+
actual = patches.get_logger.call_args[1]["destination_args"].destination_protocol
234234
assert actual == expected
235235

236236

237-
def test_main_when_get_logger_raises_io_error_causes_exit(patches):
237+
def test_main_when_get_logger_raises_io_error_without_errno_61_print_error_about_file_path(
238+
patches, capsys
239+
):
238240
patches.get_logger.side_effect = IOError
239241
with pytest.raises(SystemExit):
240242
main.main()
241243

244+
assert "file path" in capsys.readouterr().out.lower()
245+
246+
247+
def test_main_when_get_logger_raises_io_error_with_errno_61_prints_error_about_hostname(
248+
patches, capsys
249+
):
250+
err = IOError()
251+
err.errno = 61
252+
patches.get_logger.side_effect = err
253+
254+
with pytest.raises(SystemExit):
255+
main.main()
256+
257+
assert "hostname" in capsys.readouterr().out.lower()
258+
242259

243-
def test_main_when_get_logger_raises_gaierror_causes_exit(patches):
260+
def test_main_when_get_logger_raises_h_error_causes_exit(patches):
244261
patches.get_logger.side_effect = gaierror
245262
with pytest.raises(SystemExit):
246263
main.main()
247264

248265

266+
def test_main_when_get_logger_raises_gai_error_causes_exit(patches):
267+
patches.get_logger.side_effect = herror
268+
with pytest.raises(SystemExit):
269+
main.main()
270+
271+
272+
def test_main_when_get_logger_raises_timeout_causes_exit(patches):
273+
patches.get_logger.side_effect = timeout
274+
with pytest.raises(SystemExit):
275+
main.main()
276+
277+
249278
def test_main_when_record_cursor_is_true_overrides_handlers_record_cursor_position(mocker, patches):
250279
expected = mocker.MagicMock()
251280
AEDCursorStore.replace_stored_insertion_timestamp = expected

tests/common/test_common.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from os import path
33
from datetime import datetime, timedelta
44
from logging import StreamHandler, FileHandler
5-
from logging.handlers import RotatingFileHandler
65

76
from c42secevents.logging.handlers import NoPrioritySysLogHandler
87

@@ -15,6 +14,7 @@
1514
get_stored_password,
1615
delete_stored_password,
1716
get_user_project_path,
17+
DestinationArgs,
1818
)
1919

2020

@@ -223,7 +223,9 @@ def test_get_error_logger_uses_rotating_file_with_expected_args(mocker, mock_get
223223

224224
def test_get_logger_when_destination_type_is_stdout_adds_stream_handler_to_logger(mock_get_logger):
225225
service = "TEST_SERVICE"
226-
logger = get_logger(None, service, "Somewhere", "stdout")
226+
args = DestinationArgs()
227+
args.destination_type = "stdout"
228+
logger = get_logger(None, service, args)
227229
actual = type(logger.addHandler.call_args[0][0])
228230
expected = StreamHandler
229231
assert actual == expected
@@ -233,7 +235,9 @@ def test_get_logger_when_destination_type_is_file_adds_file_handler_to_logger(
233235
mock_get_logger, mock_file_handler
234236
):
235237
service = "TEST_SERVICE"
236-
logger = get_logger(None, service, "Somewhere", "file")
238+
args = DestinationArgs()
239+
args.destination_type = "file"
240+
logger = get_logger(None, service, args)
237241
actual = type(logger.addHandler.call_args[0][0])
238242
expected = FileHandler
239243
assert actual == expected
@@ -243,7 +247,9 @@ def test_get_logger_when_destination_type_is_server_adds_no_priority_syslog_hand
243247
mock_get_logger, mock_no_priority_syslog_handler
244248
):
245249
service = "TEST_SERVICE"
246-
logger = get_logger(None, service, "Somewhere", "server")
250+
args = DestinationArgs()
251+
args.destination_type = "server"
252+
logger = get_logger(None, service, args)
247253
actual = type(logger.addHandler.call_args[0][0])
248254
expected = NoPrioritySysLogHandler
249255
assert actual == expected

0 commit comments

Comments
 (0)