test_mariadb.py 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.hooks.data_source import mariadb as module
  5. def test_parse_extra_options_passes_through_empty_options():
  6. assert module.parse_extra_options('') == ((), None)
  7. def test_parse_extra_options_with_defaults_extra_file_removes_and_and_parses_out_filename():
  8. assert module.parse_extra_options('--defaults-extra-file=extra.cnf --skip-ssl') == (
  9. ('--skip-ssl',),
  10. 'extra.cnf',
  11. )
  12. def test_parse_extra_options_without_defaults_extra_file_passes_through_options():
  13. assert module.parse_extra_options('--skip-ssl --and=stuff') == (
  14. ('--skip-ssl', '--and=stuff'),
  15. None,
  16. )
  17. def test_make_defaults_file_pipe_without_username_or_password_bails():
  18. flexmock(module.os).should_receive('pipe').never()
  19. assert module.make_defaults_file_options(username=None, password=None) == ()
  20. def test_make_defaults_file_option_with_username_and_password_writes_them_to_file_descriptor():
  21. read_descriptor = 99
  22. write_descriptor = flexmock()
  23. flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
  24. flexmock(module.os).should_receive('write').with_args(
  25. write_descriptor, b'[client]\nuser=root\npassword="trustsome1"'
  26. ).once()
  27. flexmock(module.os).should_receive('close')
  28. flexmock(module.os).should_receive('set_inheritable')
  29. assert module.make_defaults_file_options(username='root', password='trustsome1') == (
  30. '--defaults-extra-file=/dev/fd/99',
  31. )
  32. def test_make_defaults_file_escapes_password_containing_backslash():
  33. read_descriptor = 99
  34. write_descriptor = flexmock()
  35. flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
  36. flexmock(module.os).should_receive('write').with_args(
  37. write_descriptor, b'[client]\nuser=root\n' + br'password="trust\\nsome1"'
  38. ).once()
  39. flexmock(module.os).should_receive('close')
  40. flexmock(module.os).should_receive('set_inheritable')
  41. assert module.make_defaults_file_options(username='root', password=r'trust\nsome1') == (
  42. '--defaults-extra-file=/dev/fd/99',
  43. )
  44. def test_make_defaults_file_pipe_with_only_username_writes_it_to_file_descriptor():
  45. read_descriptor = 99
  46. write_descriptor = flexmock()
  47. flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
  48. flexmock(module.os).should_receive('write').with_args(
  49. write_descriptor, b'[client]\nuser=root'
  50. ).once()
  51. flexmock(module.os).should_receive('close')
  52. flexmock(module.os).should_receive('set_inheritable')
  53. assert module.make_defaults_file_options(username='root', password=None) == (
  54. '--defaults-extra-file=/dev/fd/99',
  55. )
  56. def test_make_defaults_file_pipe_with_only_password_writes_it_to_file_descriptor():
  57. read_descriptor = 99
  58. write_descriptor = flexmock()
  59. flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
  60. flexmock(module.os).should_receive('write').with_args(
  61. write_descriptor, b'[client]\npassword="trustsome1"'
  62. ).once()
  63. flexmock(module.os).should_receive('close')
  64. flexmock(module.os).should_receive('set_inheritable')
  65. assert module.make_defaults_file_options(username=None, password='trustsome1') == (
  66. '--defaults-extra-file=/dev/fd/99',
  67. )
  68. def test_make_defaults_file_option_with_defaults_extra_filename_includes_it_in_file_descriptor():
  69. read_descriptor = 99
  70. write_descriptor = flexmock()
  71. flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
  72. flexmock(module.os).should_receive('write').with_args(
  73. write_descriptor, b'!include extra.cnf\n[client]\nuser=root\npassword="trustsome1"'
  74. ).once()
  75. flexmock(module.os).should_receive('close')
  76. flexmock(module.os).should_receive('set_inheritable')
  77. assert module.make_defaults_file_options(
  78. username='root', password='trustsome1', defaults_extra_filename='extra.cnf'
  79. ) == ('--defaults-extra-file=/dev/fd/99',)
  80. def test_make_defaults_file_option_with_only_defaults_extra_filename_uses_it_instead_of_file_descriptor():
  81. flexmock(module.os).should_receive('pipe').never()
  82. assert module.make_defaults_file_options(
  83. username=None, password=None, defaults_extra_filename='extra.cnf'
  84. ) == ('--defaults-extra-file=extra.cnf',)
  85. def test_database_names_to_dump_passes_through_name():
  86. environment = flexmock()
  87. names = module.database_names_to_dump(
  88. {'name': 'foo'}, {}, 'root', 'trustsome1', environment, dry_run=False
  89. )
  90. assert names == ('foo',)
  91. def test_database_names_to_dump_bails_for_dry_run():
  92. environment = flexmock()
  93. flexmock(module).should_receive('execute_command_and_capture_output').never()
  94. names = module.database_names_to_dump(
  95. {'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=True
  96. )
  97. assert names == ()
  98. def test_database_names_to_dump_queries_mariadb_for_database_names():
  99. environment = flexmock()
  100. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  101. 'resolve_credential'
  102. ).replace_with(lambda value, config: value)
  103. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  104. flexmock(module).should_receive('make_defaults_file_options').with_args(
  105. 'root', 'trustsome1', None
  106. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  107. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  108. (
  109. 'mariadb',
  110. '--defaults-extra-file=/dev/fd/99',
  111. '--skip-column-names',
  112. '--batch',
  113. '--execute',
  114. 'show schemas',
  115. ),
  116. environment=environment,
  117. ).and_return('foo\nbar\nmysql\n').once()
  118. names = module.database_names_to_dump(
  119. {'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=False
  120. )
  121. assert names == ('foo', 'bar')
  122. def test_database_names_to_dump_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  123. environment = flexmock()
  124. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  125. 'resolve_credential'
  126. ).replace_with(lambda value, config: value)
  127. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  128. flexmock(module).should_receive('make_defaults_file_options').never()
  129. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  130. (
  131. 'mariadb',
  132. '--user',
  133. 'root',
  134. '--skip-column-names',
  135. '--batch',
  136. '--execute',
  137. 'show schemas',
  138. ),
  139. environment=environment,
  140. ).and_return('foo\nbar\nmysql\n').once()
  141. names = module.database_names_to_dump(
  142. {'name': 'all', 'password_transport': 'environment'},
  143. {},
  144. 'root',
  145. 'trustsome1',
  146. environment,
  147. dry_run=False,
  148. )
  149. assert names == ('foo', 'bar')
  150. def test_database_names_to_dump_runs_mariadb_with_tls():
  151. environment = flexmock()
  152. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  153. 'resolve_credential'
  154. ).replace_with(lambda value, config: value)
  155. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  156. flexmock(module).should_receive('make_defaults_file_options').with_args(
  157. 'root', 'trustsome1', None
  158. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  159. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  160. (
  161. 'mariadb',
  162. '--defaults-extra-file=/dev/fd/99',
  163. '--ssl',
  164. '--skip-column-names',
  165. '--batch',
  166. '--execute',
  167. 'show schemas',
  168. ),
  169. environment=environment,
  170. ).and_return('foo\nbar\nmysql\n').once()
  171. names = module.database_names_to_dump(
  172. {'name': 'all', 'tls': True}, {}, 'root', 'trustsome1', environment, dry_run=False
  173. )
  174. assert names == ('foo', 'bar')
  175. def test_database_names_to_dump_runs_mariadb_without_tls():
  176. environment = flexmock()
  177. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  178. 'resolve_credential'
  179. ).replace_with(lambda value, config: value)
  180. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  181. flexmock(module).should_receive('make_defaults_file_options').with_args(
  182. 'root', 'trustsome1', None
  183. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  184. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  185. (
  186. 'mariadb',
  187. '--defaults-extra-file=/dev/fd/99',
  188. '--skip-ssl',
  189. '--skip-column-names',
  190. '--batch',
  191. '--execute',
  192. 'show schemas',
  193. ),
  194. environment=environment,
  195. ).and_return('foo\nbar\nmysql\n').once()
  196. names = module.database_names_to_dump(
  197. {'name': 'all', 'tls': False}, {}, 'root', 'trustsome1', environment, dry_run=False
  198. )
  199. assert names == ('foo', 'bar')
  200. def test_use_streaming_true_for_any_databases():
  201. assert module.use_streaming(
  202. databases=[flexmock(), flexmock()],
  203. config=flexmock(),
  204. )
  205. def test_use_streaming_false_for_no_databases():
  206. assert not module.use_streaming(databases=[], config=flexmock())
  207. def test_dump_data_sources_dumps_each_database():
  208. databases = [{'name': 'foo'}, {'name': 'bar'}]
  209. processes = [flexmock(), flexmock()]
  210. flexmock(module).should_receive('make_dump_path').and_return('')
  211. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  212. 'resolve_credential'
  213. ).and_return(None)
  214. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  215. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  216. 'resolve_credential'
  217. ).replace_with(lambda value, config: value)
  218. flexmock(module).should_receive('database_names_to_dump').with_args(
  219. database=databases[0],
  220. config={},
  221. username=None,
  222. password=None,
  223. environment={'USER': 'root'},
  224. dry_run=False,
  225. ).and_return(('foo',))
  226. flexmock(module).should_receive('database_names_to_dump').with_args(
  227. database=databases[1],
  228. config={},
  229. username=None,
  230. password=None,
  231. environment={'USER': 'root'},
  232. dry_run=False,
  233. ).and_return(('bar',))
  234. for name, process in zip(('foo', 'bar'), processes):
  235. flexmock(module).should_receive('execute_dump_command').with_args(
  236. database={'name': name},
  237. config={},
  238. username=None,
  239. password=None,
  240. dump_path=object,
  241. database_names=(name,),
  242. environment={'USER': 'root'},
  243. dry_run=object,
  244. dry_run_label=object,
  245. ).and_return(process).once()
  246. assert (
  247. module.dump_data_sources(
  248. databases,
  249. {},
  250. config_paths=('test.yaml',),
  251. borgmatic_runtime_directory='/run/borgmatic',
  252. patterns=[],
  253. dry_run=False,
  254. )
  255. == processes
  256. )
  257. def test_dump_data_sources_dumps_with_password():
  258. database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
  259. process = flexmock()
  260. flexmock(module).should_receive('make_dump_path').and_return('')
  261. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  262. 'resolve_credential'
  263. ).replace_with(lambda value, config: value)
  264. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  265. flexmock(module).should_receive('database_names_to_dump').with_args(
  266. database=database,
  267. config={},
  268. username='root',
  269. password='trustsome1',
  270. environment={'USER': 'root'},
  271. dry_run=False,
  272. ).and_return(('foo',))
  273. flexmock(module).should_receive('execute_dump_command').with_args(
  274. database=database,
  275. config={},
  276. username='root',
  277. password='trustsome1',
  278. dump_path=object,
  279. database_names=('foo',),
  280. environment={'USER': 'root'},
  281. dry_run=object,
  282. dry_run_label=object,
  283. ).and_return(process).once()
  284. assert module.dump_data_sources(
  285. [database],
  286. {},
  287. config_paths=('test.yaml',),
  288. borgmatic_runtime_directory='/run/borgmatic',
  289. patterns=[],
  290. dry_run=False,
  291. ) == [process]
  292. def test_dump_data_sources_dumps_with_environment_password_transport_passes_password_environment_variable():
  293. database = {
  294. 'name': 'foo',
  295. 'username': 'root',
  296. 'password': 'trustsome1',
  297. 'password_transport': 'environment',
  298. }
  299. process = flexmock()
  300. flexmock(module).should_receive('make_dump_path').and_return('')
  301. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  302. 'resolve_credential'
  303. ).replace_with(lambda value, config: value)
  304. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  305. flexmock(module).should_receive('database_names_to_dump').with_args(
  306. database=database,
  307. config={},
  308. username='root',
  309. password='trustsome1',
  310. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  311. dry_run=False,
  312. ).and_return(('foo',))
  313. flexmock(module).should_receive('execute_dump_command').with_args(
  314. database=database,
  315. config={},
  316. username='root',
  317. password='trustsome1',
  318. dump_path=object,
  319. database_names=('foo',),
  320. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  321. dry_run=object,
  322. dry_run_label=object,
  323. ).and_return(process).once()
  324. assert module.dump_data_sources(
  325. [database],
  326. {},
  327. config_paths=('test.yaml',),
  328. borgmatic_runtime_directory='/run/borgmatic',
  329. patterns=[],
  330. dry_run=False,
  331. ) == [process]
  332. def test_dump_data_sources_dumps_all_databases_at_once():
  333. databases = [{'name': 'all'}]
  334. process = flexmock()
  335. flexmock(module).should_receive('make_dump_path').and_return('')
  336. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  337. 'resolve_credential'
  338. ).replace_with(lambda value, config: value)
  339. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  340. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  341. flexmock(module).should_receive('execute_dump_command').with_args(
  342. database={'name': 'all'},
  343. config={},
  344. username=None,
  345. password=None,
  346. dump_path=object,
  347. database_names=('foo', 'bar'),
  348. environment={'USER': 'root'},
  349. dry_run=object,
  350. dry_run_label=object,
  351. ).and_return(process).once()
  352. assert module.dump_data_sources(
  353. databases,
  354. {},
  355. config_paths=('test.yaml',),
  356. borgmatic_runtime_directory='/run/borgmatic',
  357. patterns=[],
  358. dry_run=False,
  359. ) == [process]
  360. def test_dump_data_sources_dumps_all_databases_separately_when_format_configured():
  361. databases = [{'name': 'all', 'format': 'sql'}]
  362. processes = [flexmock(), flexmock()]
  363. flexmock(module).should_receive('make_dump_path').and_return('')
  364. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  365. 'resolve_credential'
  366. ).and_return(None)
  367. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  368. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  369. for name, process in zip(('foo', 'bar'), processes):
  370. flexmock(module).should_receive('execute_dump_command').with_args(
  371. database={'name': name, 'format': 'sql'},
  372. config={},
  373. username=None,
  374. password=None,
  375. dump_path=object,
  376. database_names=(name,),
  377. environment={'USER': 'root'},
  378. dry_run=object,
  379. dry_run_label=object,
  380. ).and_return(process).once()
  381. assert (
  382. module.dump_data_sources(
  383. databases,
  384. {},
  385. config_paths=('test.yaml',),
  386. borgmatic_runtime_directory='/run/borgmatic',
  387. patterns=[],
  388. dry_run=False,
  389. )
  390. == processes
  391. )
  392. def test_dump_data_sources_errors_for_missing_all_databases():
  393. databases = [{'name': 'all'}]
  394. flexmock(module).should_receive('make_dump_path').and_return('')
  395. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  396. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  397. 'resolve_credential'
  398. ).replace_with(lambda value, config: value)
  399. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  400. 'databases/localhost/all'
  401. )
  402. flexmock(module).should_receive('database_names_to_dump').and_return(())
  403. with pytest.raises(ValueError):
  404. assert module.dump_data_sources(
  405. databases,
  406. {},
  407. config_paths=('test.yaml',),
  408. borgmatic_runtime_directory='/run/borgmatic',
  409. patterns=[],
  410. dry_run=False,
  411. )
  412. def test_dump_data_sources_does_not_error_for_missing_all_databases_with_dry_run():
  413. databases = [{'name': 'all'}]
  414. flexmock(module).should_receive('make_dump_path').and_return('')
  415. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  416. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  417. 'resolve_credential'
  418. ).replace_with(lambda value, config: value)
  419. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  420. 'databases/localhost/all'
  421. )
  422. flexmock(module).should_receive('database_names_to_dump').and_return(())
  423. assert (
  424. module.dump_data_sources(
  425. databases,
  426. {},
  427. config_paths=('test.yaml',),
  428. borgmatic_runtime_directory='/run/borgmatic',
  429. patterns=[],
  430. dry_run=True,
  431. )
  432. == []
  433. )
  434. def test_database_names_to_dump_runs_mariadb_with_list_options():
  435. database = {'name': 'all', 'list_options': '--defaults-extra-file=mariadb.cnf --skip-ssl'}
  436. flexmock(module).should_receive('parse_extra_options').and_return(
  437. ('--skip-ssl',), 'mariadb.cnf'
  438. )
  439. flexmock(module).should_receive('make_defaults_file_options').with_args(
  440. 'root', 'trustsome1', 'mariadb.cnf'
  441. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  442. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  443. (
  444. 'mariadb',
  445. '--defaults-extra-file=/dev/fd/99',
  446. '--skip-ssl',
  447. '--skip-column-names',
  448. '--batch',
  449. '--execute',
  450. 'show schemas',
  451. ),
  452. environment=None,
  453. ).and_return(('foo\nbar')).once()
  454. assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
  455. 'foo',
  456. 'bar',
  457. )
  458. def test_database_names_to_dump_runs_non_default_mariadb_with_list_options():
  459. database = {
  460. 'name': 'all',
  461. 'list_options': '--defaults-extra-file=mariadb.cnf --skip-ssl',
  462. 'mariadb_command': 'custom_mariadb',
  463. }
  464. flexmock(module).should_receive('parse_extra_options').and_return(
  465. ('--skip-ssl',), 'mariadb.cnf'
  466. )
  467. flexmock(module).should_receive('make_defaults_file_options').with_args(
  468. 'root', 'trustsome1', 'mariadb.cnf'
  469. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  470. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  471. environment=None,
  472. full_command=(
  473. 'custom_mariadb', # Custom MariaDB command
  474. '--defaults-extra-file=/dev/fd/99',
  475. '--skip-ssl',
  476. '--skip-column-names',
  477. '--batch',
  478. '--execute',
  479. 'show schemas',
  480. ),
  481. ).and_return(('foo\nbar')).once()
  482. assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
  483. 'foo',
  484. 'bar',
  485. )
  486. def test_execute_dump_command_runs_mariadb_dump():
  487. process = flexmock()
  488. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  489. flexmock(module.os.path).should_receive('exists').and_return(False)
  490. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  491. 'resolve_credential'
  492. ).replace_with(lambda value, config: value)
  493. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  494. flexmock(module).should_receive('make_defaults_file_options').with_args(
  495. 'root', 'trustsome1', None
  496. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  497. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  498. flexmock(module).should_receive('execute_command').with_args(
  499. (
  500. 'mariadb-dump',
  501. '--defaults-extra-file=/dev/fd/99',
  502. '--add-drop-database',
  503. '--databases',
  504. 'foo',
  505. '--result-file',
  506. 'dump',
  507. ),
  508. environment=None,
  509. run_to_completion=False,
  510. ).and_return(process).once()
  511. assert (
  512. module.execute_dump_command(
  513. database={'name': 'foo'},
  514. config={},
  515. username='root',
  516. password='trustsome1',
  517. dump_path=flexmock(),
  518. database_names=('foo',),
  519. environment=None,
  520. dry_run=False,
  521. dry_run_label='',
  522. )
  523. == process
  524. )
  525. def test_execute_dump_command_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  526. process = flexmock()
  527. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  528. flexmock(module.os.path).should_receive('exists').and_return(False)
  529. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  530. 'resolve_credential'
  531. ).replace_with(lambda value, config: value)
  532. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  533. flexmock(module).should_receive('make_defaults_file_options').never()
  534. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  535. flexmock(module).should_receive('execute_command').with_args(
  536. (
  537. 'mariadb-dump',
  538. '--add-drop-database',
  539. '--user',
  540. 'root',
  541. '--databases',
  542. 'foo',
  543. '--result-file',
  544. 'dump',
  545. ),
  546. environment=None,
  547. run_to_completion=False,
  548. ).and_return(process).once()
  549. assert (
  550. module.execute_dump_command(
  551. database={'name': 'foo', 'password_transport': 'environment'},
  552. config={},
  553. username='root',
  554. password='trustsome1',
  555. dump_path=flexmock(),
  556. database_names=('foo',),
  557. environment=None,
  558. dry_run=False,
  559. dry_run_label='',
  560. )
  561. == process
  562. )
  563. def test_execute_dump_command_runs_mariadb_dump_without_add_drop_database():
  564. process = flexmock()
  565. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  566. flexmock(module.os.path).should_receive('exists').and_return(False)
  567. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  568. 'resolve_credential'
  569. ).replace_with(lambda value, config: value)
  570. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  571. flexmock(module).should_receive('make_defaults_file_options').with_args(
  572. 'root', 'trustsome1', None
  573. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  574. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  575. flexmock(module).should_receive('execute_command').with_args(
  576. (
  577. 'mariadb-dump',
  578. '--defaults-extra-file=/dev/fd/99',
  579. '--databases',
  580. 'foo',
  581. '--result-file',
  582. 'dump',
  583. ),
  584. environment=None,
  585. run_to_completion=False,
  586. ).and_return(process).once()
  587. assert (
  588. module.execute_dump_command(
  589. database={'name': 'foo', 'add_drop_database': False},
  590. config={},
  591. username='root',
  592. password='trustsome1',
  593. dump_path=flexmock(),
  594. database_names=('foo',),
  595. environment=None,
  596. dry_run=False,
  597. dry_run_label='',
  598. )
  599. == process
  600. )
  601. def test_execute_dump_command_runs_mariadb_dump_with_hostname_and_port():
  602. process = flexmock()
  603. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  604. flexmock(module.os.path).should_receive('exists').and_return(False)
  605. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  606. 'resolve_credential'
  607. ).replace_with(lambda value, config: value)
  608. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  609. flexmock(module).should_receive('make_defaults_file_options').with_args(
  610. 'root', 'trustsome1', None
  611. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  612. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  613. flexmock(module).should_receive('execute_command').with_args(
  614. (
  615. 'mariadb-dump',
  616. '--defaults-extra-file=/dev/fd/99',
  617. '--add-drop-database',
  618. '--host',
  619. 'database.example.org',
  620. '--port',
  621. '5433',
  622. '--protocol',
  623. 'tcp',
  624. '--databases',
  625. 'foo',
  626. '--result-file',
  627. 'dump',
  628. ),
  629. environment=None,
  630. run_to_completion=False,
  631. ).and_return(process).once()
  632. assert (
  633. module.execute_dump_command(
  634. database={'name': 'foo', 'hostname': 'database.example.org', 'port': 5433},
  635. config={},
  636. username='root',
  637. password='trustsome1',
  638. dump_path=flexmock(),
  639. database_names=('foo',),
  640. environment=None,
  641. dry_run=False,
  642. dry_run_label='',
  643. )
  644. == process
  645. )
  646. def test_execute_dump_command_runs_mariadb_dump_with_tls():
  647. process = flexmock()
  648. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  649. flexmock(module.os.path).should_receive('exists').and_return(False)
  650. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  651. 'resolve_credential'
  652. ).replace_with(lambda value, config: value)
  653. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  654. flexmock(module).should_receive('make_defaults_file_options').with_args(
  655. 'root', 'trustsome1', None
  656. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  657. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  658. flexmock(module).should_receive('execute_command').with_args(
  659. (
  660. 'mariadb-dump',
  661. '--defaults-extra-file=/dev/fd/99',
  662. '--add-drop-database',
  663. '--ssl',
  664. '--databases',
  665. 'foo',
  666. '--result-file',
  667. 'dump',
  668. ),
  669. environment=None,
  670. run_to_completion=False,
  671. ).and_return(process).once()
  672. assert (
  673. module.execute_dump_command(
  674. database={'name': 'foo', 'tls': True},
  675. config={},
  676. username='root',
  677. password='trustsome1',
  678. dump_path=flexmock(),
  679. database_names=('foo',),
  680. environment=None,
  681. dry_run=False,
  682. dry_run_label='',
  683. )
  684. == process
  685. )
  686. def test_execute_dump_command_runs_mariadb_dump_without_tls():
  687. process = flexmock()
  688. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  689. flexmock(module.os.path).should_receive('exists').and_return(False)
  690. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  691. 'resolve_credential'
  692. ).replace_with(lambda value, config: value)
  693. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  694. flexmock(module).should_receive('make_defaults_file_options').with_args(
  695. 'root', 'trustsome1', None
  696. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  697. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  698. flexmock(module).should_receive('execute_command').with_args(
  699. (
  700. 'mariadb-dump',
  701. '--defaults-extra-file=/dev/fd/99',
  702. '--add-drop-database',
  703. '--skip-ssl',
  704. '--databases',
  705. 'foo',
  706. '--result-file',
  707. 'dump',
  708. ),
  709. environment=None,
  710. run_to_completion=False,
  711. ).and_return(process).once()
  712. assert (
  713. module.execute_dump_command(
  714. database={'name': 'foo', 'tls': False},
  715. config={},
  716. username='root',
  717. password='trustsome1',
  718. dump_path=flexmock(),
  719. database_names=('foo',),
  720. environment=None,
  721. dry_run=False,
  722. dry_run_label='',
  723. )
  724. == process
  725. )
  726. def test_execute_dump_command_runs_mariadb_dump_with_username_and_password():
  727. process = flexmock()
  728. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  729. flexmock(module.os.path).should_receive('exists').and_return(False)
  730. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  731. 'resolve_credential'
  732. ).replace_with(lambda value, config: value)
  733. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  734. flexmock(module).should_receive('make_defaults_file_options').with_args(
  735. 'root', 'trustsome1', None
  736. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  737. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  738. flexmock(module).should_receive('execute_command').with_args(
  739. (
  740. 'mariadb-dump',
  741. '--defaults-extra-file=/dev/fd/99',
  742. '--add-drop-database',
  743. '--databases',
  744. 'foo',
  745. '--result-file',
  746. 'dump',
  747. ),
  748. environment={},
  749. run_to_completion=False,
  750. ).and_return(process).once()
  751. assert (
  752. module.execute_dump_command(
  753. database={'name': 'foo', 'username': 'root', 'password': 'trustsome1'},
  754. config={},
  755. username='root',
  756. password='trustsome1',
  757. dump_path=flexmock(),
  758. database_names=('foo',),
  759. environment={},
  760. dry_run=False,
  761. dry_run_label='',
  762. )
  763. == process
  764. )
  765. def test_execute_dump_command_runs_mariadb_dump_with_options():
  766. process = flexmock()
  767. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  768. flexmock(module.os.path).should_receive('exists').and_return(False)
  769. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  770. 'resolve_credential'
  771. ).replace_with(lambda value, config: value)
  772. flexmock(module).should_receive('parse_extra_options').and_return(('--stuff=such',), None)
  773. flexmock(module).should_receive('make_defaults_file_options').with_args(
  774. 'root', 'trustsome1', None
  775. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  776. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  777. flexmock(module).should_receive('execute_command').with_args(
  778. (
  779. 'mariadb-dump',
  780. '--defaults-extra-file=/dev/fd/99',
  781. '--stuff=such',
  782. '--add-drop-database',
  783. '--databases',
  784. 'foo',
  785. '--result-file',
  786. 'dump',
  787. ),
  788. environment=None,
  789. run_to_completion=False,
  790. ).and_return(process).once()
  791. assert (
  792. module.execute_dump_command(
  793. database={'name': 'foo', 'options': '--stuff=such'},
  794. config={},
  795. username='root',
  796. password='trustsome1',
  797. dump_path=flexmock(),
  798. database_names=('foo',),
  799. environment=None,
  800. dry_run=False,
  801. dry_run_label='',
  802. )
  803. == process
  804. )
  805. def test_execute_dump_command_runs_non_default_mariadb_dump_with_options():
  806. process = flexmock()
  807. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  808. flexmock(module.os.path).should_receive('exists').and_return(False)
  809. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  810. 'resolve_credential'
  811. ).replace_with(lambda value, config: value)
  812. flexmock(module).should_receive('parse_extra_options').and_return(('--stuff=such',), None)
  813. flexmock(module).should_receive('make_defaults_file_options').with_args(
  814. 'root', 'trustsome1', None
  815. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  816. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  817. flexmock(module).should_receive('execute_command').with_args(
  818. (
  819. 'custom_mariadb_dump', # Custom MariaDB dump command
  820. '--defaults-extra-file=/dev/fd/99',
  821. '--stuff=such',
  822. '--add-drop-database',
  823. '--databases',
  824. 'foo',
  825. '--result-file',
  826. 'dump',
  827. ),
  828. environment=None,
  829. run_to_completion=False,
  830. ).and_return(process).once()
  831. assert (
  832. module.execute_dump_command(
  833. database={
  834. 'name': 'foo',
  835. 'mariadb_dump_command': 'custom_mariadb_dump',
  836. 'options': '--stuff=such',
  837. }, # Custom MariaDB dump command specified
  838. config={},
  839. username='root',
  840. password='trustsome1',
  841. dump_path=flexmock(),
  842. database_names=('foo',),
  843. environment=None,
  844. dry_run=False,
  845. dry_run_label='',
  846. )
  847. == process
  848. )
  849. def test_execute_dump_command_with_duplicate_dump_skips_mariadb_dump():
  850. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  851. flexmock(module.os.path).should_receive('exists').and_return(True)
  852. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  853. flexmock(module).should_receive('make_defaults_file_options').with_args(
  854. 'root', 'trustsome1', None
  855. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  856. flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
  857. flexmock(module).should_receive('execute_command').never()
  858. assert (
  859. module.execute_dump_command(
  860. database={'name': 'foo'},
  861. config={},
  862. username='root',
  863. password='trustsome1',
  864. dump_path=flexmock(),
  865. database_names=('foo',),
  866. environment=None,
  867. dry_run=True,
  868. dry_run_label='SO DRY',
  869. )
  870. is None
  871. )
  872. def test_execute_dump_command_with_dry_run_skips_mariadb_dump():
  873. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  874. flexmock(module.os.path).should_receive('exists').and_return(False)
  875. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  876. 'resolve_credential'
  877. ).replace_with(lambda value, config: value)
  878. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  879. flexmock(module).should_receive('make_defaults_file_options').with_args(
  880. 'root', 'trustsome1', None
  881. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  882. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  883. flexmock(module).should_receive('execute_command').never()
  884. assert (
  885. module.execute_dump_command(
  886. database={'name': 'foo'},
  887. config={},
  888. username='root',
  889. password='trustsome1',
  890. dump_path=flexmock(),
  891. database_names=('foo',),
  892. environment=None,
  893. dry_run=True,
  894. dry_run_label='SO DRY',
  895. )
  896. is None
  897. )
  898. def test_restore_data_source_dump_runs_mariadb_to_restore():
  899. hook_config = [{'name': 'foo'}, {'name': 'bar'}]
  900. extract_process = flexmock(stdout=flexmock())
  901. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  902. 'resolve_credential'
  903. ).replace_with(lambda value, config: value)
  904. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  905. flexmock(module).should_receive('make_defaults_file_options').with_args(
  906. None, None, None
  907. ).and_return(())
  908. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  909. flexmock(module).should_receive('execute_command_with_processes').with_args(
  910. ('mariadb', '--batch'),
  911. processes=[extract_process],
  912. output_log_level=logging.DEBUG,
  913. input_file=extract_process.stdout,
  914. environment={'USER': 'root'},
  915. ).once()
  916. module.restore_data_source_dump(
  917. hook_config,
  918. {},
  919. data_source={'name': 'foo'},
  920. dry_run=False,
  921. extract_process=extract_process,
  922. connection_params={
  923. 'hostname': None,
  924. 'port': None,
  925. 'username': None,
  926. 'password': None,
  927. },
  928. borgmatic_runtime_directory='/run/borgmatic',
  929. )
  930. def test_restore_data_source_dump_runs_mariadb_with_options():
  931. hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
  932. extract_process = flexmock(stdout=flexmock())
  933. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  934. 'resolve_credential'
  935. ).replace_with(lambda value, config: value)
  936. flexmock(module).should_receive('parse_extra_options').and_return(('--harder',), None)
  937. flexmock(module).should_receive('make_defaults_file_options').with_args(
  938. None, None, None
  939. ).and_return(())
  940. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  941. flexmock(module).should_receive('execute_command_with_processes').with_args(
  942. ('mariadb', '--harder', '--batch'),
  943. processes=[extract_process],
  944. output_log_level=logging.DEBUG,
  945. input_file=extract_process.stdout,
  946. environment={'USER': 'root'},
  947. ).once()
  948. module.restore_data_source_dump(
  949. hook_config,
  950. {},
  951. data_source=hook_config[0],
  952. dry_run=False,
  953. extract_process=extract_process,
  954. connection_params={
  955. 'hostname': None,
  956. 'port': None,
  957. 'username': None,
  958. 'password': None,
  959. },
  960. borgmatic_runtime_directory='/run/borgmatic',
  961. )
  962. def test_restore_data_source_dump_runs_non_default_mariadb_with_options():
  963. hook_config = [
  964. {'name': 'foo', 'restore_options': '--harder', 'mariadb_command': 'custom_mariadb'}
  965. ]
  966. extract_process = flexmock(stdout=flexmock())
  967. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  968. 'resolve_credential'
  969. ).replace_with(lambda value, config: value)
  970. flexmock(module).should_receive('parse_extra_options').and_return(('--harder',), None)
  971. flexmock(module).should_receive('make_defaults_file_options').with_args(
  972. None, None, None
  973. ).and_return(())
  974. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  975. flexmock(module).should_receive('execute_command_with_processes').with_args(
  976. ('custom_mariadb', '--harder', '--batch'),
  977. processes=[extract_process],
  978. output_log_level=logging.DEBUG,
  979. input_file=extract_process.stdout,
  980. environment={'USER': 'root'},
  981. ).once()
  982. module.restore_data_source_dump(
  983. hook_config,
  984. {},
  985. data_source=hook_config[0],
  986. dry_run=False,
  987. extract_process=extract_process,
  988. connection_params={
  989. 'hostname': None,
  990. 'port': None,
  991. 'username': None,
  992. 'password': None,
  993. },
  994. borgmatic_runtime_directory='/run/borgmatic',
  995. )
  996. def test_restore_data_source_dump_runs_mariadb_with_hostname_and_port():
  997. hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
  998. extract_process = flexmock(stdout=flexmock())
  999. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1000. 'resolve_credential'
  1001. ).replace_with(lambda value, config: value)
  1002. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1003. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1004. None, None, None
  1005. ).and_return(())
  1006. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1007. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1008. (
  1009. 'mariadb',
  1010. '--batch',
  1011. '--host',
  1012. 'database.example.org',
  1013. '--port',
  1014. '5433',
  1015. '--protocol',
  1016. 'tcp',
  1017. ),
  1018. processes=[extract_process],
  1019. output_log_level=logging.DEBUG,
  1020. input_file=extract_process.stdout,
  1021. environment={'USER': 'root'},
  1022. ).once()
  1023. module.restore_data_source_dump(
  1024. hook_config,
  1025. {},
  1026. data_source=hook_config[0],
  1027. dry_run=False,
  1028. extract_process=extract_process,
  1029. connection_params={
  1030. 'hostname': None,
  1031. 'port': None,
  1032. 'username': None,
  1033. 'password': None,
  1034. },
  1035. borgmatic_runtime_directory='/run/borgmatic',
  1036. )
  1037. def test_restore_data_source_dump_runs_mariadb_with_tls():
  1038. hook_config = [{'name': 'foo', 'tls': True}]
  1039. extract_process = flexmock(stdout=flexmock())
  1040. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1041. 'resolve_credential'
  1042. ).replace_with(lambda value, config: value)
  1043. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1044. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1045. None, None, None
  1046. ).and_return(())
  1047. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1048. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1049. (
  1050. 'mariadb',
  1051. '--batch',
  1052. '--ssl',
  1053. ),
  1054. processes=[extract_process],
  1055. output_log_level=logging.DEBUG,
  1056. input_file=extract_process.stdout,
  1057. environment={'USER': 'root'},
  1058. ).once()
  1059. module.restore_data_source_dump(
  1060. hook_config,
  1061. {},
  1062. data_source=hook_config[0],
  1063. dry_run=False,
  1064. extract_process=extract_process,
  1065. connection_params={
  1066. 'hostname': None,
  1067. 'port': None,
  1068. 'username': None,
  1069. 'password': None,
  1070. },
  1071. borgmatic_runtime_directory='/run/borgmatic',
  1072. )
  1073. def test_restore_data_source_dump_runs_mariadb_without_tls():
  1074. hook_config = [{'name': 'foo', 'tls': False}]
  1075. extract_process = flexmock(stdout=flexmock())
  1076. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1077. 'resolve_credential'
  1078. ).replace_with(lambda value, config: value)
  1079. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1080. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1081. None, None, None
  1082. ).and_return(())
  1083. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1084. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1085. (
  1086. 'mariadb',
  1087. '--batch',
  1088. '--skip-ssl',
  1089. ),
  1090. processes=[extract_process],
  1091. output_log_level=logging.DEBUG,
  1092. input_file=extract_process.stdout,
  1093. environment={'USER': 'root'},
  1094. ).once()
  1095. module.restore_data_source_dump(
  1096. hook_config,
  1097. {},
  1098. data_source=hook_config[0],
  1099. dry_run=False,
  1100. extract_process=extract_process,
  1101. connection_params={
  1102. 'hostname': None,
  1103. 'port': None,
  1104. 'username': None,
  1105. 'password': None,
  1106. },
  1107. borgmatic_runtime_directory='/run/borgmatic',
  1108. )
  1109. def test_restore_data_source_dump_runs_mariadb_with_username_and_password():
  1110. hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
  1111. extract_process = flexmock(stdout=flexmock())
  1112. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1113. 'resolve_credential'
  1114. ).replace_with(lambda value, config: value)
  1115. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1116. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1117. 'root', 'trustsome1', None
  1118. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  1119. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1120. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1121. ('mariadb', '--defaults-extra-file=/dev/fd/99', '--batch'),
  1122. processes=[extract_process],
  1123. output_log_level=logging.DEBUG,
  1124. input_file=extract_process.stdout,
  1125. environment={'USER': 'root'},
  1126. ).once()
  1127. module.restore_data_source_dump(
  1128. hook_config,
  1129. {},
  1130. data_source=hook_config[0],
  1131. dry_run=False,
  1132. extract_process=extract_process,
  1133. connection_params={
  1134. 'hostname': None,
  1135. 'port': None,
  1136. 'username': None,
  1137. 'password': None,
  1138. },
  1139. borgmatic_runtime_directory='/run/borgmatic',
  1140. )
  1141. def test_restore_data_source_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  1142. hook_config = [
  1143. {
  1144. 'name': 'foo',
  1145. 'username': 'root',
  1146. 'password': 'trustsome1',
  1147. 'password_transport': 'environment',
  1148. }
  1149. ]
  1150. extract_process = flexmock(stdout=flexmock())
  1151. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1152. 'resolve_credential'
  1153. ).replace_with(lambda value, config: value)
  1154. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1155. flexmock(module).should_receive('make_defaults_file_options').never()
  1156. flexmock(module.os).should_receive('environ').and_return(
  1157. {'USER': 'root', 'MYSQL_PWD': 'trustsome1'}
  1158. )
  1159. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1160. ('mariadb', '--batch', '--user', 'root'),
  1161. processes=[extract_process],
  1162. output_log_level=logging.DEBUG,
  1163. input_file=extract_process.stdout,
  1164. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  1165. ).once()
  1166. module.restore_data_source_dump(
  1167. hook_config,
  1168. {},
  1169. data_source=hook_config[0],
  1170. dry_run=False,
  1171. extract_process=extract_process,
  1172. connection_params={
  1173. 'hostname': None,
  1174. 'port': None,
  1175. 'username': None,
  1176. 'password': None,
  1177. },
  1178. borgmatic_runtime_directory='/run/borgmatic',
  1179. )
  1180. def test_restore_data_source_dump_with_connection_params_uses_connection_params_for_restore():
  1181. hook_config = [
  1182. {
  1183. 'name': 'foo',
  1184. 'username': 'root',
  1185. 'password': 'trustsome1',
  1186. 'restore_hostname': 'restorehost',
  1187. 'restore_port': 'restoreport',
  1188. 'restore_username': 'restoreusername',
  1189. 'restore_password': 'restorepassword',
  1190. }
  1191. ]
  1192. extract_process = flexmock(stdout=flexmock())
  1193. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1194. 'resolve_credential'
  1195. ).replace_with(lambda value, config: value)
  1196. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1197. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1198. 'cliusername', 'clipassword', None
  1199. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  1200. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1201. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1202. (
  1203. 'mariadb',
  1204. '--defaults-extra-file=/dev/fd/99',
  1205. '--batch',
  1206. '--host',
  1207. 'clihost',
  1208. '--port',
  1209. 'cliport',
  1210. '--protocol',
  1211. 'tcp',
  1212. ),
  1213. processes=[extract_process],
  1214. output_log_level=logging.DEBUG,
  1215. input_file=extract_process.stdout,
  1216. environment={'USER': 'root'},
  1217. ).once()
  1218. module.restore_data_source_dump(
  1219. hook_config,
  1220. {},
  1221. data_source=hook_config[0],
  1222. dry_run=False,
  1223. extract_process=extract_process,
  1224. connection_params={
  1225. 'hostname': 'clihost',
  1226. 'port': 'cliport',
  1227. 'username': 'cliusername',
  1228. 'password': 'clipassword',
  1229. },
  1230. borgmatic_runtime_directory='/run/borgmatic',
  1231. )
  1232. def test_restore_data_source_dump_without_connection_params_uses_restore_params_in_config_for_restore():
  1233. hook_config = [
  1234. {
  1235. 'name': 'foo',
  1236. 'username': 'root',
  1237. 'password': 'trustsome1',
  1238. 'hostname': 'dbhost',
  1239. 'port': 'dbport',
  1240. 'tls': True,
  1241. 'restore_username': 'restoreuser',
  1242. 'restore_password': 'restorepass',
  1243. 'restore_hostname': 'restorehost',
  1244. 'restore_port': 'restoreport',
  1245. 'restore_tls': False,
  1246. }
  1247. ]
  1248. extract_process = flexmock(stdout=flexmock())
  1249. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1250. 'resolve_credential'
  1251. ).replace_with(lambda value, config: value)
  1252. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1253. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1254. 'restoreuser', 'restorepass', None
  1255. ).and_return(('--defaults-extra-file=/dev/fd/99',))
  1256. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1257. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1258. (
  1259. 'mariadb',
  1260. '--defaults-extra-file=/dev/fd/99',
  1261. '--batch',
  1262. '--host',
  1263. 'restorehost',
  1264. '--port',
  1265. 'restoreport',
  1266. '--protocol',
  1267. 'tcp',
  1268. '--skip-ssl',
  1269. ),
  1270. processes=[extract_process],
  1271. output_log_level=logging.DEBUG,
  1272. input_file=extract_process.stdout,
  1273. environment={'USER': 'root'},
  1274. ).once()
  1275. module.restore_data_source_dump(
  1276. hook_config,
  1277. {},
  1278. data_source=hook_config[0],
  1279. dry_run=False,
  1280. extract_process=extract_process,
  1281. connection_params={
  1282. 'hostname': None,
  1283. 'port': None,
  1284. 'username': None,
  1285. 'password': None,
  1286. },
  1287. borgmatic_runtime_directory='/run/borgmatic',
  1288. )
  1289. def test_restore_data_source_dump_with_dry_run_skips_restore():
  1290. hook_config = [{'name': 'foo'}]
  1291. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1292. 'resolve_credential'
  1293. ).replace_with(lambda value, config: value)
  1294. flexmock(module).should_receive('parse_extra_options').and_return((), None)
  1295. flexmock(module).should_receive('make_defaults_file_options').with_args(
  1296. None, None, None
  1297. ).and_return(())
  1298. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1299. flexmock(module).should_receive('execute_command_with_processes').never()
  1300. module.restore_data_source_dump(
  1301. hook_config,
  1302. {},
  1303. data_source={'name': 'foo'},
  1304. dry_run=True,
  1305. extract_process=flexmock(),
  1306. connection_params={
  1307. 'hostname': None,
  1308. 'port': None,
  1309. 'username': None,
  1310. 'password': None,
  1311. },
  1312. borgmatic_runtime_directory='/run/borgmatic',
  1313. )