1
0

test_btmp.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. # coding: utf-8
  2. # Python libs
  3. from __future__ import absolute_import
  4. import datetime
  5. import logging
  6. # Salt libs
  7. import salt.beacons.btmp as btmp
  8. from salt.ext import six
  9. from tests.support.mixins import LoaderModuleMockMixin
  10. from tests.support.mock import MagicMock, mock_open, patch
  11. # Salt testing libs
  12. from tests.support.unit import TestCase, skipIf
  13. # pylint: disable=import-error
  14. try:
  15. import dateutil.parser as dateutil_parser # pylint: disable=unused-import
  16. _TIME_SUPPORTED = True
  17. except ImportError:
  18. _TIME_SUPPORTED = False
  19. raw = b"\x06\x00\x00\x00Nt\x00\x00ssh:notty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00garet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00::1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xc7\xc2Y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
  20. pack = (
  21. 6,
  22. 29774,
  23. b"ssh:notty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
  24. b"\x00\x00\x00\x00",
  25. b"garet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
  26. b"::1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
  27. 0,
  28. 0,
  29. 0,
  30. 1505937373,
  31. 0,
  32. 0,
  33. 0,
  34. 0,
  35. 16777216,
  36. )
  37. log = logging.getLogger(__name__)
  38. class BTMPBeaconTestCase(TestCase, LoaderModuleMockMixin):
  39. """
  40. Test case for salt.beacons.[s]
  41. """
  42. def setup_loader_modules(self):
  43. return {btmp: {"__context__": {"btmp.loc": 2}, "__salt__": {}}}
  44. def test_non_list_config(self):
  45. config = {}
  46. ret = btmp.validate(config)
  47. self.assertEqual(ret, (False, "Configuration for btmp beacon must be a list."))
  48. def test_empty_config(self):
  49. config = [{}]
  50. ret = btmp.validate(config)
  51. self.assertEqual(ret, (True, "Valid beacon configuration"))
  52. def test_no_match(self):
  53. config = [
  54. {
  55. "users": {
  56. "gareth": {
  57. "time_range": {
  58. "end": "09-22-2017 5pm",
  59. "start": "09-22-2017 3pm",
  60. }
  61. }
  62. }
  63. }
  64. ]
  65. ret = btmp.validate(config)
  66. self.assertEqual(ret, (True, "Valid beacon configuration"))
  67. with patch("salt.utils.files.fopen", mock_open(b"")) as m_open:
  68. ret = btmp.beacon(config)
  69. call_args = next(six.itervalues(m_open.filehandles))[0].call.args
  70. assert call_args == (btmp.BTMP, "rb"), call_args
  71. assert ret == [], ret
  72. def test_invalid_users(self):
  73. config = [{"users": ["gareth"]}]
  74. ret = btmp.validate(config)
  75. self.assertEqual(
  76. ret, (False, "User configuration for btmp beacon must be a dictionary.")
  77. )
  78. def test_invalid_groups(self):
  79. config = [{"groups": ["docker"]}]
  80. ret = btmp.validate(config)
  81. self.assertEqual(
  82. ret, (False, "Group configuration for btmp beacon must be a dictionary.")
  83. )
  84. def test_default_invalid_time_range(self):
  85. config = [{"defaults": {"time_range": {"start": "3pm"}}}]
  86. ret = btmp.validate(config)
  87. self.assertEqual(
  88. ret,
  89. (
  90. False,
  91. "The time_range parameter for btmp beacon must contain start & end options.",
  92. ),
  93. )
  94. def test_users_invalid_time_range(self):
  95. config = [{"users": {"gareth": {"time_range": {"start": "3pm"}}}}]
  96. ret = btmp.validate(config)
  97. self.assertEqual(
  98. ret,
  99. (
  100. False,
  101. "The time_range parameter for btmp beacon must contain start & end options.",
  102. ),
  103. )
  104. def test_groups_invalid_time_range(self):
  105. config = [{"groups": {"docker": {"time_range": {"start": "3pm"}}}}]
  106. ret = btmp.validate(config)
  107. self.assertEqual(
  108. ret,
  109. (
  110. False,
  111. "The time_range parameter for btmp beacon must contain start & end options.",
  112. ),
  113. )
  114. def test_match(self):
  115. with patch("salt.utils.files.fopen", mock_open(read_data=raw)):
  116. with patch("struct.unpack", MagicMock(return_value=pack)):
  117. config = [{"users": {"garet": {}}}]
  118. ret = btmp.validate(config)
  119. self.assertEqual(ret, (True, "Valid beacon configuration"))
  120. _expected = [
  121. {
  122. "addr": 1505937373,
  123. "exit_status": 0,
  124. "inittab": "",
  125. "hostname": "::1",
  126. "PID": 29774,
  127. "session": 0,
  128. "user": "garet",
  129. "time": 0,
  130. "line": "ssh:notty",
  131. "type": 6,
  132. }
  133. ]
  134. ret = btmp.beacon(config)
  135. self.assertEqual(ret, _expected)
  136. @skipIf(not _TIME_SUPPORTED, "dateutil.parser is missing.")
  137. def test_match_time(self):
  138. with patch("salt.utils.files.fopen", mock_open(read_data=raw)):
  139. mock_now = datetime.datetime(2017, 9, 22, 16, 0, 0, 0)
  140. with patch("datetime.datetime", MagicMock()), patch(
  141. "datetime.datetime.now", MagicMock(return_value=mock_now)
  142. ):
  143. with patch("struct.unpack", MagicMock(return_value=pack)):
  144. config = [
  145. {
  146. "users": {
  147. "garet": {
  148. "time_range": {
  149. "end": "09-22-2017 5pm",
  150. "start": "09-22-2017 3pm",
  151. }
  152. }
  153. }
  154. }
  155. ]
  156. ret = btmp.validate(config)
  157. self.assertEqual(ret, (True, "Valid beacon configuration"))
  158. _expected = [
  159. {
  160. "addr": 1505937373,
  161. "exit_status": 0,
  162. "inittab": "",
  163. "hostname": "::1",
  164. "PID": 29774,
  165. "session": 0,
  166. "user": "garet",
  167. "time": 0,
  168. "line": "ssh:notty",
  169. "type": 6,
  170. }
  171. ]
  172. ret = btmp.beacon(config)
  173. self.assertEqual(ret, _expected)
  174. def test_match_group(self):
  175. for groupadd in (
  176. "salt.modules.aix_group",
  177. "salt.modules.mac_group",
  178. "salt.modules.pw_group",
  179. "salt.modules.solaris_group",
  180. "salt.modules.win_groupadd",
  181. ):
  182. mock_group_info = {
  183. "passwd": "x",
  184. "gid": 100,
  185. "name": "users",
  186. "members": ["garet"],
  187. }
  188. with patch("salt.utils.files.fopen", mock_open(read_data=raw)):
  189. with patch("time.time", MagicMock(return_value=1506121200)):
  190. with patch("struct.unpack", MagicMock(return_value=pack)):
  191. with patch(
  192. "{0}.info".format(groupadd),
  193. new=MagicMock(return_value=mock_group_info),
  194. ):
  195. config = [
  196. {
  197. "group": {
  198. "users": {
  199. "time_range": {"end": "5pm", "start": "3pm"}
  200. }
  201. }
  202. }
  203. ]
  204. ret = btmp.validate(config)
  205. self.assertEqual(ret, (True, "Valid beacon configuration"))
  206. _expected = [
  207. {
  208. "addr": 1505937373,
  209. "exit_status": 0,
  210. "inittab": "",
  211. "hostname": "::1",
  212. "PID": 29774,
  213. "session": 0,
  214. "user": "garet",
  215. "time": 0,
  216. "line": "ssh:notty",
  217. "type": 6,
  218. }
  219. ]
  220. ret = btmp.beacon(config)
  221. self.assertEqual(ret, _expected)