test_smb.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Test utility methods that communicate with SMB shares.
  4. '''
  5. from __future__ import absolute_import
  6. import getpass
  7. import logging
  8. import os
  9. import signal
  10. import subprocess
  11. import tempfile
  12. import time
  13. import salt.utils.files
  14. import salt.utils.path
  15. import salt.utils.smb
  16. from tests.support.unit import skipIf
  17. from tests.support.case import TestCase
  18. log = logging.getLogger(__name__)
  19. CONFIG = (
  20. '[global]\n'
  21. 'realm = saltstack.com\n'
  22. 'interfaces = lo 127.0.0.0/8\n'
  23. 'smb ports = 1445\n'
  24. 'log level = 2\n'
  25. 'map to guest = Bad User\n'
  26. 'enable core files = no\n'
  27. 'passdb backend = smbpasswd\n'
  28. 'smb passwd file = {passwdb}\n'
  29. 'lock directory = {samba_dir}\n'
  30. 'state directory = {samba_dir}\n'
  31. 'cache directory = {samba_dir}\n'
  32. 'pid directory = {samba_dir}\n'
  33. 'private dir = {samba_dir}\n'
  34. 'ncalrpc dir = {samba_dir}\n'
  35. 'socket options = IPTOS_LOWDELAY TCP_NODELAY\n'
  36. 'min receivefile size = 0\n'
  37. 'write cache size = 0\n'
  38. 'client ntlmv2 auth = no\n'
  39. 'client min protocol = SMB3_11\n'
  40. 'client plaintext auth = no\n'
  41. '\n'
  42. '[public]\n'
  43. 'path = {public_dir}\n'
  44. 'read only = no\n'
  45. 'guest ok = no\n'
  46. 'writeable = yes\n'
  47. 'force user = {user}\n'
  48. )
  49. TBE = (
  50. '{}:0:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:AC8E657F8'
  51. '3DF82BEEA5D43BDAF7800CC:[U ]:LCT-507C14C7:'
  52. )
  53. def which_smbd():
  54. '''
  55. Find the smbd executable and cache the result if it exits.
  56. '''
  57. if hasattr(which_smbd, 'cached_result'):
  58. return which_smbd.cached_result
  59. smbd = salt.utils.path.which('smbd')
  60. if smbd:
  61. which_smbd.cached_result = smbd
  62. return smbd
  63. @skipIf(not which_smbd(), 'Skip when no smbd binary found')
  64. class TestSmb(TestCase):
  65. _smbd = None
  66. @staticmethod
  67. def check_pid(pid):
  68. try:
  69. os.kill(pid, 0)
  70. except OSError:
  71. return False
  72. else:
  73. return True
  74. @classmethod
  75. def setUpClass(cls):
  76. tmpdir = tempfile.mkdtemp()
  77. cls.samba_dir = os.path.join(tmpdir, 'samba')
  78. cls.public_dir = os.path.join(tmpdir, 'public')
  79. os.makedirs(cls.samba_dir)
  80. os.makedirs(cls.public_dir)
  81. os.chmod(cls.samba_dir, 0o775)
  82. os.chmod(cls.public_dir, 0o775)
  83. passwdb = os.path.join(tmpdir, 'passwdb')
  84. cls.username = getpass.getuser()
  85. with salt.utils.files.fopen(passwdb, 'w') as fp:
  86. fp.write(TBE.format(cls.username))
  87. samba_conf = os.path.join(tmpdir, 'smb.conf')
  88. with salt.utils.files.fopen(samba_conf, 'w') as fp:
  89. fp.write(
  90. CONFIG.format(
  91. samba_dir=cls.samba_dir,
  92. public_dir=cls.public_dir,
  93. passwdb=passwdb,
  94. user=cls.username,
  95. )
  96. )
  97. cls._smbd = subprocess.Popen(
  98. '{0} -FS -P0 -s {1}'.format(which_smbd(), samba_conf),
  99. shell=True
  100. )
  101. time.sleep(1)
  102. pidfile = os.path.join(cls.samba_dir, 'smbd.pid')
  103. with salt.utils.files.fopen(pidfile, 'r') as fp:
  104. cls._pid = int(fp.read().strip())
  105. if not cls.check_pid(cls._pid):
  106. raise Exception('Unable to locate smbd\'s pid file')
  107. @classmethod
  108. def tearDownClass(cls):
  109. log.warning('teardown')
  110. os.kill(cls._pid, signal.SIGTERM)
  111. def test_write_file(self):
  112. '''
  113. Transfer a file over SMB
  114. '''
  115. name = 'test_write_file.txt'
  116. content = 'write test file content'
  117. share_path = os.path.join(self.public_dir, name)
  118. assert not os.path.exists(share_path)
  119. local_path = tempfile.mktemp()
  120. with salt.utils.files.fopen(local_path, 'w') as fp:
  121. fp.write(content)
  122. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  123. salt.utils.smb.put_file(local_path, name, 'public', conn=conn)
  124. conn.close()
  125. assert os.path.exists(share_path)
  126. with salt.utils.files.fopen(share_path, 'r') as fp:
  127. result = fp.read()
  128. assert result == content
  129. def test_write_str(self):
  130. '''
  131. Write a string to a file over SMB
  132. '''
  133. name = 'test_write_str.txt'
  134. content = 'write test file content'
  135. share_path = os.path.join(self.public_dir, name)
  136. assert not os.path.exists(share_path)
  137. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  138. salt.utils.smb.put_str(content, name, 'public', conn=conn)
  139. conn.close()
  140. assert os.path.exists(share_path)
  141. with salt.utils.files.fopen(share_path, 'r') as fp:
  142. result = fp.read()
  143. assert result == content
  144. def test_delete_file(self):
  145. '''
  146. Validate deletion of files over SMB
  147. '''
  148. name = 'test_delete_file.txt'
  149. content = 'read test file content'
  150. share_path = os.path.join(self.public_dir, name)
  151. with salt.utils.files.fopen(share_path, 'w') as fp:
  152. fp.write(content)
  153. assert os.path.exists(share_path)
  154. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  155. salt.utils.smb.delete_file(name, 'public', conn=conn)
  156. conn.close()
  157. assert not os.path.exists(share_path)
  158. def test_mkdirs(self):
  159. '''
  160. Create directories over SMB
  161. '''
  162. dir_name = 'mkdirs/test'
  163. share_path = os.path.join(self.public_dir, dir_name)
  164. assert not os.path.exists(share_path)
  165. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  166. salt.utils.smb.mkdirs(dir_name, 'public', conn=conn)
  167. conn.close()
  168. assert os.path.exists(share_path)
  169. def test_delete_dirs(self):
  170. '''
  171. Validate deletion of directoreies over SMB
  172. '''
  173. dir_name = 'deldirs'
  174. subdir_name = 'deldirs/test'
  175. local_path = os.path.join(self.public_dir, subdir_name)
  176. os.makedirs(local_path)
  177. assert os.path.exists(local_path)
  178. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  179. salt.utils.smb.delete_directory(subdir_name, 'public', conn=conn)
  180. conn.close()
  181. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  182. salt.utils.smb.delete_directory(dir_name, 'public', conn=conn)
  183. conn.close()
  184. assert not os.path.exists(local_path)
  185. assert not os.path.exists(os.path.join(self.public_dir, dir_name))
  186. def test_connection(self):
  187. '''
  188. Validate creation of an SMB connection
  189. '''
  190. conn = salt.utils.smb.get_conn('127.0.0.1', self.username, 'foo', port=1445)
  191. conn.close()