synapse 2.192.0__py311-none-any.whl → 2.194.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (77) hide show
  1. synapse/common.py +15 -0
  2. synapse/cortex.py +19 -25
  3. synapse/datamodel.py +6 -3
  4. synapse/exc.py +6 -1
  5. synapse/lib/agenda.py +17 -6
  6. synapse/lib/ast.py +242 -97
  7. synapse/lib/auth.py +1 -0
  8. synapse/lib/cell.py +31 -85
  9. synapse/lib/cli.py +20 -11
  10. synapse/lib/parser.py +5 -1
  11. synapse/lib/snap.py +44 -15
  12. synapse/lib/storm.lark +16 -1
  13. synapse/lib/storm.py +40 -21
  14. synapse/lib/storm_format.py +1 -0
  15. synapse/lib/stormctrl.py +88 -6
  16. synapse/lib/stormlib/cache.py +6 -2
  17. synapse/lib/stormlib/json.py +5 -2
  18. synapse/lib/stormlib/scrape.py +1 -1
  19. synapse/lib/stormlib/stix.py +8 -8
  20. synapse/lib/stormtypes.py +32 -5
  21. synapse/lib/version.py +2 -2
  22. synapse/lib/view.py +20 -3
  23. synapse/models/geopol.py +1 -0
  24. synapse/models/geospace.py +1 -0
  25. synapse/models/inet.py +20 -1
  26. synapse/models/infotech.py +24 -6
  27. synapse/models/orgs.py +7 -2
  28. synapse/models/person.py +15 -4
  29. synapse/models/risk.py +19 -2
  30. synapse/models/telco.py +10 -3
  31. synapse/tests/test_axon.py +6 -6
  32. synapse/tests/test_cortex.py +133 -14
  33. synapse/tests/test_exc.py +4 -0
  34. synapse/tests/test_lib_agenda.py +282 -2
  35. synapse/tests/test_lib_aha.py +13 -6
  36. synapse/tests/test_lib_ast.py +301 -10
  37. synapse/tests/test_lib_auth.py +6 -7
  38. synapse/tests/test_lib_cell.py +71 -1
  39. synapse/tests/test_lib_grammar.py +14 -0
  40. synapse/tests/test_lib_layer.py +1 -1
  41. synapse/tests/test_lib_lmdbslab.py +3 -3
  42. synapse/tests/test_lib_storm.py +273 -55
  43. synapse/tests/test_lib_stormctrl.py +65 -0
  44. synapse/tests/test_lib_stormhttp.py +5 -5
  45. synapse/tests/test_lib_stormlib_auth.py +5 -5
  46. synapse/tests/test_lib_stormlib_cache.py +38 -6
  47. synapse/tests/test_lib_stormlib_json.py +20 -0
  48. synapse/tests/test_lib_stormlib_modelext.py +3 -3
  49. synapse/tests/test_lib_stormlib_scrape.py +6 -6
  50. synapse/tests/test_lib_stormlib_spooled.py +1 -1
  51. synapse/tests/test_lib_stormlib_xml.py +5 -5
  52. synapse/tests/test_lib_stormtypes.py +54 -57
  53. synapse/tests/test_lib_view.py +1 -1
  54. synapse/tests/test_model_base.py +1 -2
  55. synapse/tests/test_model_geopol.py +4 -0
  56. synapse/tests/test_model_geospace.py +6 -0
  57. synapse/tests/test_model_inet.py +43 -5
  58. synapse/tests/test_model_infotech.py +10 -1
  59. synapse/tests/test_model_orgs.py +17 -2
  60. synapse/tests/test_model_person.py +23 -1
  61. synapse/tests/test_model_risk.py +13 -0
  62. synapse/tests/test_tools_healthcheck.py +4 -4
  63. synapse/tests/test_tools_storm.py +95 -0
  64. synapse/tests/test_utils.py +17 -18
  65. synapse/tests/test_utils_getrefs.py +1 -1
  66. synapse/tests/utils.py +0 -35
  67. synapse/tools/changelog.py +6 -4
  68. synapse/tools/storm.py +1 -1
  69. synapse/utils/getrefs.py +14 -3
  70. synapse/vendor/cpython/lib/http/__init__.py +0 -0
  71. synapse/vendor/cpython/lib/http/cookies.py +59 -0
  72. synapse/vendor/cpython/lib/test/test_http_cookies.py +49 -0
  73. {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/METADATA +6 -6
  74. {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/RECORD +77 -73
  75. {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/WHEEL +1 -1
  76. {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/LICENSE +0 -0
  77. {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/top_level.txt +0 -0
@@ -990,12 +990,12 @@ bar baz",vv
990
990
  self.isinstance(resp.get('err'), tuple)
991
991
 
992
992
  q = f'''
993
- $fields = $lib.list(
994
- ({{'name':'file', 'sha256':$sha256, 'filename':'file'}}),
995
- ({{'name':'zip_password', 'value':'test'}}),
996
- ({{'name':'dict', 'value':({{'foo':'bar'}}) }}),
997
- ({{'name':'bytes', 'value':$bytes}})
998
- )
993
+ $fields = ([
994
+ {{'name':'file', 'sha256':$sha256, 'filename':'file'}},
995
+ {{'name':'zip_password', 'value':'test'}},
996
+ {{'name':'dict', 'value':{{'foo':'bar'}} }},
997
+ {{'name':'bytes', 'value':$bytes}}
998
+ ])
999
999
  $resp = $lib.inet.http.post("https://127.0.0.1:{port}/api/v1/pushfile",
1000
1000
  fields=$fields, ssl_verify=(0))
1001
1001
  return($resp)
@@ -440,7 +440,7 @@ class CortexTest(s_t_utils.SynTest):
440
440
  'interfaces': ['lookup'],
441
441
  'storm': '''
442
442
  function lookup(tokens) {
443
- $looks = $lib.list()
443
+ $looks = ()
444
444
  for $token in $tokens { $looks.append( (inet:fqdn, $token) ) }
445
445
  return($looks)
446
446
  }
@@ -484,7 +484,7 @@ class CortexTest(s_t_utils.SynTest):
484
484
  self.len(0, mods)
485
485
  self.len(0, core.modsbyiface.get('lookup'))
486
486
 
487
- await core.loadStormPkg(pkgdef)
487
+ core.loadStormPkg(pkgdef)
488
488
 
489
489
  mods = await core.getStormIfaces('lookup')
490
490
  self.len(1, mods)
@@ -513,7 +513,7 @@ class CortexTest(s_t_utils.SynTest):
513
513
  vals = [r async for r in core.view.callStormIface('boom', todo)]
514
514
  self.eq((), vals)
515
515
 
516
- await core._dropStormPkg(pkgdef)
516
+ core._dropStormPkg(pkgdef)
517
517
  self.none(core.modsbyiface.get('lookup'))
518
518
 
519
519
  mods = await core.getStormIfaces('lookup')
@@ -558,7 +558,7 @@ class CortexTest(s_t_utils.SynTest):
558
558
  nodes = await core.nodes('foo@bar.com foo@bar.com', opts={'mode': 'lookup'})
559
559
  self.eq(['inet:email', 'inet:email'], [n.ndef[0] for n in nodes])
560
560
 
561
- await core.loadStormPkg(pkgdef)
561
+ core.loadStormPkg(pkgdef)
562
562
  self.len(1, await core.getStormIfaces('search'))
563
563
 
564
564
  todo = s_common.todo('search', ('foo@bar.com',))
@@ -679,7 +679,7 @@ class CortexTest(s_t_utils.SynTest):
679
679
  # functions that don't return a generator
680
680
  storm = '''
681
681
  function x() {
682
- $lst = $lib.list()
682
+ $lst = ()
683
683
  [ ou:org=* ou:org=* +#cat ]
684
684
  $lst.append($node)
685
685
  fini { return($lst) }
@@ -692,7 +692,7 @@ class CortexTest(s_t_utils.SynTest):
692
692
 
693
693
  storm = '''
694
694
  function x() {
695
- $lst = $lib.list()
695
+ $lst = ()
696
696
  [ ou:org=* ou:org=* +#dog ]
697
697
  $lst.append($node)
698
698
  fini { return($lst) }
@@ -974,7 +974,7 @@ class CortexTest(s_t_utils.SynTest):
974
974
  await core.nodes('media:news -(refs)> $(10)')
975
975
 
976
976
  self.eq(1, await core.callStorm('''
977
- $list = $lib.list()
977
+ $list = ()
978
978
  for $edge in $lib.view.get().getEdges() { $list.append($edge) }
979
979
  return($list.size())
980
980
  '''))
@@ -982,7 +982,7 @@ class CortexTest(s_t_utils.SynTest):
982
982
  # check that auto-deleting a node's edges works
983
983
  await core.nodes('media:news | delnode')
984
984
  self.eq(0, await core.callStorm('''
985
- $list = $lib.list()
985
+ $list = ()
986
986
  for $edge in $lib.view.get().getEdges() { $list.append($edge) }
987
987
  return($list.size())
988
988
  '''))
@@ -1017,7 +1017,7 @@ class CortexTest(s_t_utils.SynTest):
1017
1017
  self.eq(('1', '2'), retn)
1018
1018
 
1019
1019
  with self.raises(s_exc.StormRuntimeError):
1020
- q = '$foo=$lib.list() $bar=$foo.index(10) return ( $bar )'
1020
+ q = '$foo=() $bar=$foo.index(10) return ( $bar )'
1021
1021
  await proxy.callStorm(q)
1022
1022
 
1023
1023
  with self.raises(s_exc.SynErr) as cm:
@@ -1033,6 +1033,26 @@ class CortexTest(s_t_utils.SynTest):
1033
1033
  self.eq(cm.exception.get('hehe'), 'haha')
1034
1034
  self.eq(cm.exception.get('key'), 1)
1035
1035
 
1036
+ # We convert StormLoopCtrl and StormGenrCtrl into StormRuntimeError
1037
+ opts = {'vars': {'i': 2}}
1038
+ q = 'if ($i = 2) { break }'
1039
+ with self.raises(s_exc.StormRuntimeError) as cm:
1040
+ await core.callStorm(q, opts=opts)
1041
+ self.eq(cm.exception.get('mesg'),
1042
+ 'Loop control statement "break" used outside of a loop.')
1043
+
1044
+ q = 'if ($i = 2) { continue }'
1045
+ with self.raises(s_exc.StormRuntimeError) as cm:
1046
+ await core.callStorm(q, opts=opts)
1047
+ self.eq(cm.exception.get('mesg'),
1048
+ 'Loop control statement "continue" used outside of a loop.')
1049
+
1050
+ q = 'if ($i = 2) { stop }'
1051
+ with self.raises(s_exc.StormRuntimeError) as cm:
1052
+ await core.callStorm(q, opts=opts)
1053
+ self.eq(cm.exception.get('mesg'),
1054
+ 'Generator control statement "stop" used outside of a generator function.')
1055
+
1036
1056
  with self.getAsyncLoggerStream('synapse.lib.view', 'callStorm cancelled') as stream:
1037
1057
  async with core.getLocalProxy() as proxy:
1038
1058
 
@@ -1069,7 +1089,7 @@ class CortexTest(s_t_utils.SynTest):
1069
1089
  self.eq('ok', retn.get('status'))
1070
1090
  self.eq('asdf', retn['result'])
1071
1091
 
1072
- body = {'query': '$foo=$lib.list() $bar=$foo.index(10) return ( $bar )'}
1092
+ body = {'query': '$foo=() $bar=$foo.index(10) return ( $bar )'}
1073
1093
  async with sess.get(f'https://localhost:{port}/api/v1/storm/call', json=body) as resp:
1074
1094
  retn = await resp.json()
1075
1095
  self.eq('err', retn.get('status'))
@@ -1081,7 +1101,7 @@ class CortexTest(s_t_utils.SynTest):
1081
1101
  retn = await resp.json()
1082
1102
  self.eq('err', retn.get('status'))
1083
1103
  self.eq('StormExit', retn.get('code'))
1084
- self.eq('', retn.get('mesg'))
1104
+ self.eq('StormExit: ', retn.get('mesg'))
1085
1105
 
1086
1106
  # No body
1087
1107
  async with sess.get(f'https://localhost:{port}/api/v1/storm/call') as resp:
@@ -1760,7 +1780,7 @@ class CortexTest(s_t_utils.SynTest):
1760
1780
  self.len(1, nodes)
1761
1781
  self.eq(set(nodes[0].tags.keys()), {'foo', 'bar', 'bar.baz'})
1762
1782
 
1763
- nodes = await wcore.nodes('$foo=$lib.list("foo", "bar.baz") [test:int=4 +#$foo]')
1783
+ nodes = await wcore.nodes('$foo=(["foo", "bar.baz"]) [test:int=4 +#$foo]')
1764
1784
  self.len(1, nodes)
1765
1785
  self.eq(set(nodes[0].tags.keys()), {'foo', 'bar', 'bar.baz'})
1766
1786
 
@@ -3499,6 +3519,97 @@ class CortexBasicTest(s_t_utils.SynTest):
3499
3519
  for node in nodes:
3500
3520
  self.nn(node.getTag('hehe'))
3501
3521
 
3522
+ # Break and Continue cannot cross function boundaries and will instead raise a catchable StormRuntimeError
3523
+ keywords = ('break', 'continue')
3524
+ base_func_q = '''
3525
+ function inner(v) {
3526
+ if ( $v = 2 ) {
3527
+ KEYWORD
3528
+ }
3529
+ return ( $v )
3530
+ }
3531
+ $N = (5)
3532
+
3533
+ for $valu in $lib.range($N) {
3534
+ $lib.print(`{$inner($valu)}/{$N}`)
3535
+ }
3536
+ '''
3537
+ func_catch_q = '''
3538
+ function inner(v) {
3539
+ if ( $v = 2 ) {
3540
+ KEYWORD
3541
+ }
3542
+ return ( $v )
3543
+ }
3544
+ $N = (5)
3545
+ try {
3546
+ for $valu in $lib.range($N) {
3547
+ $lib.print(`{$inner($valu)}/{$N}`)
3548
+ }
3549
+ } catch StormRuntimeError as err {
3550
+ $lib.print(`caught: {$err.mesg}`)
3551
+ }
3552
+ '''
3553
+ for keyword in keywords:
3554
+ q = base_func_q.replace('KEYWORD', keyword)
3555
+ msgs = await core.stormlist(q)
3556
+ self.stormIsInPrint('1/5', msgs)
3557
+ self.stormNotInPrint('2/5', msgs)
3558
+ self.stormIsInErr(f'function inner - Loop control statement "{keyword}" used outside of a loop.',
3559
+ msgs)
3560
+
3561
+ q = func_catch_q.replace('KEYWORD', keyword)
3562
+ msgs = await core.stormlist(q)
3563
+ self.stormIsInPrint('1/5', msgs)
3564
+ self.stormNotInPrint('2/5', msgs)
3565
+ self.stormIsInPrint(f'function inner - Loop control statement "{keyword}" used outside of a loop.',
3566
+ msgs)
3567
+
3568
+ # The toplevel use of the keywords will convert them into StormRuntimeError in the message stream
3569
+ # but prevent them from being caught.
3570
+ base_top_q = '''
3571
+ $N = (5)
3572
+ for $j in $lib.range($N) {
3573
+ if ($j = 2) { break }
3574
+ $lib.print(`{$j}/{$N}`)
3575
+ }
3576
+ if ($j = 2) {
3577
+ KEYWORD
3578
+ }
3579
+ '''
3580
+ top_catch_q = '''
3581
+ $N = (5)
3582
+ for $j in $lib.range($N) {
3583
+ if ($j = 2) { break }
3584
+ $lib.print(`{$j}/{$N}`)
3585
+ }
3586
+ try {
3587
+ if ($j = 2) {
3588
+ KEYWORD
3589
+ }
3590
+ } catch StormRuntimeError as err {
3591
+ $lib.print(`caught: {$err.mesg}`)
3592
+ }
3593
+ '''
3594
+ for keyword in keywords:
3595
+ q = base_top_q.replace('KEYWORD', keyword)
3596
+ msgs = await core.stormlist(q)
3597
+ self.stormIsInPrint('1/5', msgs)
3598
+ self.stormNotInPrint('2/5', msgs)
3599
+ self.stormIsInErr(f'Loop control statement "{keyword}" used outside of a loop.',
3600
+ msgs)
3601
+ errname = [m[1][0] for m in msgs if m[0] == 'err'][0]
3602
+ self.eq(errname, 'StormRuntimeError')
3603
+
3604
+ q = top_catch_q.replace('KEYWORD', keyword)
3605
+ msgs = await core.stormlist(q)
3606
+ self.stormIsInPrint('1/5', msgs)
3607
+ self.stormNotInPrint('2/5', msgs)
3608
+ self.stormIsInErr(f'Loop control statement "{keyword}" used outside of a loop.',
3609
+ msgs)
3610
+ errname = [m[1][0] for m in msgs if m[0] == 'err'][0]
3611
+ self.eq(errname, 'StormRuntimeError')
3612
+
3502
3613
  async def test_storm_varcall(self):
3503
3614
 
3504
3615
  async with self.getTestCore() as core:
@@ -5119,6 +5230,14 @@ class CortexBasicTest(s_t_utils.SynTest):
5119
5230
  self.eq(('inet:fqdn', 'nest.com'), nodes[0].ndef)
5120
5231
  self.eq(('inet:fqdn', 'nest.com'), nodes[1].ndef)
5121
5232
 
5233
+ with self.raises(s_exc.StormRuntimeError) as err:
5234
+ await core.nodes('[ it:dev:int=1 ] for $n in $node.value() { }')
5235
+ self.isin("'int' object is not iterable: 1", err.exception.errinfo.get('mesg'))
5236
+
5237
+ with self.raises(s_exc.StormRuntimeError) as err:
5238
+ await core.nodes('for $n in { .created return($node) } { }')
5239
+ self.isin("'node' object is not iterable", err.exception.errinfo.get('mesg'))
5240
+
5122
5241
  async def test_storm_whileloop(self):
5123
5242
 
5124
5243
  async with self.getTestCore() as core:
@@ -5460,7 +5579,7 @@ class CortexBasicTest(s_t_utils.SynTest):
5460
5579
  self.len(1, nodes)
5461
5580
 
5462
5581
  async def test_storm_order(self):
5463
- q = '''[test:str=foo :hehe=bar] $tvar=$lib.text() $tvar.add(1) $tvar.add(:hehe) $lib.print($tvar.str()) '''
5582
+ q = '''[test:str=foo :hehe=bar] $tvar=() $tvar.append(1) $tvar.append(:hehe) $lib.print($lib.str.join('', $tvar)) '''
5464
5583
  async with self.getTestCore() as core:
5465
5584
  mesgs = await core.stormlist(q)
5466
5585
  self.stormIsInPrint('1bar', mesgs)
@@ -5684,7 +5803,7 @@ class CortexBasicTest(s_t_utils.SynTest):
5684
5803
 
5685
5804
  url02 = core02.getLocalUrl()
5686
5805
  opts = {'vars': {'url01': url01, 'url02': url02}}
5687
- strim = 'return($lib.cell.trimNexsLog(consumers=$lib.list($url01, $url02), timeout=$lib.null))'
5806
+ strim = 'return($lib.cell.trimNexsLog(consumers=($url01, $url02), timeout=$lib.null))'
5688
5807
 
5689
5808
  await core00.nodes('[ inet:ipv4=11.0.0.0/28 ]')
5690
5809
  ips00 = await core00.count('inet:ipv4')
synapse/tests/test_exc.py CHANGED
@@ -16,6 +16,7 @@ class ExcTest(s_t_utils.SynTest):
16
16
  def test_basic(self):
17
17
  e = s_exc.SynErr(mesg='words', foo='bar')
18
18
  self.eq(e.get('foo'), 'bar')
19
+ self.eq(e.items(), {'mesg': 'words', 'foo': 'bar'})
19
20
  self.eq("SynErr: foo='bar' mesg='words'", str(e))
20
21
  e.set('hehe', 1234)
21
22
  e.set('foo', 'words')
@@ -27,6 +28,9 @@ class ExcTest(s_t_utils.SynTest):
27
28
  e.setdefault('defv', 2)
28
29
  self.eq("SynErr: defv=1 foo='words' hehe=1234 mesg='words'", str(e))
29
30
 
31
+ e.update({'foo': 'newwords', 'bar': 'baz'})
32
+ self.eq("SynErr: bar='baz' defv=1 foo='newwords' hehe=1234 mesg='words'", str(e))
33
+
30
34
  self.eq(e.errname, 'SynErr')
31
35
 
32
36
  e2 = s_exc.BadTypeValu(mesg='haha')
@@ -1,3 +1,4 @@
1
+ import time
1
2
  import asyncio
2
3
  import hashlib
3
4
  import datetime
@@ -361,7 +362,9 @@ class AgendaTest(s_t_utils.SynTest):
361
362
 
362
363
  appt = await agenda.get(guid)
363
364
  self.eq(appt.isrunning, False)
364
- self.eq(appt.lastresult, "raised exception StormRaise: errname='OmgWtfBbq' mesg='boom'")
365
+ self.isin("raised exception StormRaise: errname='OmgWtfBbq'", appt.lastresult)
366
+ self.isin("highlight={'hash': '6736b8252d9413221a9b693b2b19cf53'", appt.lastresult)
367
+ self.isin("mesg='boom'", appt.lastresult)
365
368
 
366
369
  # Test setting the global enable/disable flag
367
370
  await agenda.delete(guid)
@@ -438,7 +441,7 @@ class AgendaTest(s_t_utils.SynTest):
438
441
  await self.asyncraises(s_exc.DupIden, core.addCronJob(cdef))
439
442
  await core.delCronJob(viewiden)
440
443
 
441
- self.nn(core.getAuthGate(viewiden))
444
+ self.nn(await core.getAuthGate(viewiden))
442
445
 
443
446
  async def test_agenda_persistence(self):
444
447
  ''' Test we can make/change/delete appointments and they are persisted to storage '''
@@ -824,6 +827,159 @@ class AgendaTest(s_t_utils.SynTest):
824
827
  data = stream.read()
825
828
  self.isin("_Appt.edits() Invalid attribute received: invalid = 'newp'", data)
826
829
 
830
+ async def test_agenda_promotions(self):
831
+ # Adjust this knob for the number of cron jobs you want to test. Below
832
+ # are some average run times from my dev box
833
+ # 100 -> ~15s
834
+ # 250 -> ~18s
835
+ # 500 -> ~22s
836
+ # 5000 -> ~88s
837
+ NUMJOBS = 100
838
+
839
+ async with self.getTestAha() as aha:
840
+
841
+ conf00 = {
842
+ 'aha:provision': await aha.addAhaSvcProv('00.cortex')
843
+ }
844
+
845
+ async with self.getTestCore(conf=conf00) as core00:
846
+ self.false(core00.conf.get('mirror'))
847
+
848
+ msgs = await core00.stormlist('[it:dev:str=foo]')
849
+ self.stormHasNoWarnErr(msgs)
850
+
851
+ # Forward wind agenda to two minutes past the hour so we don't hit any weird timing windows
852
+ tick = core00.agenda._getNowTick()
853
+ now = time.gmtime(int(tick))
854
+ diff = (60 - now.tm_min) * 60
855
+ core00.agenda._addTickOff(diff + 120)
856
+
857
+ # Add NUMJOBS cron jobs that starts every hour
858
+ q = '''
859
+ for $ii in $lib.range($numjobs) {
860
+ cron.add --name `CRON{$ii}` --hour +1 { $lib.time.sleep(90) }
861
+ }
862
+ '''
863
+ opts = {'vars': {'numjobs': NUMJOBS}}
864
+ await core00.callStorm(q, opts=opts)
865
+
866
+ prov01 = {'mirror': '00.cortex'}
867
+ conf01 = {
868
+ 'aha:provision': await aha.addAhaSvcProv('01.cortex', provinfo=prov01),
869
+ }
870
+
871
+ async with self.getTestCore(conf=conf01) as core01:
872
+ # Advance the ticks so the cronjob starts sooner
873
+ core00.agenda._addTickOff(3600)
874
+
875
+ # Sync agenda ticks
876
+ diff = core00.agenda._getNowTick() - core01.agenda._getNowTick()
877
+ core01.agenda._addTickOff(diff)
878
+
879
+ mesgs = []
880
+ async for mesg in core00.behold():
881
+ mesgs.append(mesg)
882
+ if len(mesgs) >= NUMJOBS:
883
+ break
884
+
885
+ for mesg in mesgs:
886
+ self.eq(mesg['event'], 'cron:start')
887
+
888
+ # Inspect crons and tasks
889
+ crons00 = await core00.callStorm('return($lib.cron.list())')
890
+ self.len(NUMJOBS, crons00)
891
+ # isrunning is synced via nexus so it should be true for both cortexes
892
+ for cron in crons00:
893
+ self.true(cron.get('isrunning'))
894
+
895
+ cronidens = [k['iden'] for k in crons00]
896
+
897
+ await core01.sync()
898
+
899
+ crons01 = await core01.callStorm('return($lib.cron.list())')
900
+ self.len(NUMJOBS, crons01)
901
+ # isrunning is synced via nexus so it should be true for both cortexes
902
+ for cron in crons01:
903
+ self.true(cron.get('isrunning'))
904
+
905
+ tasks00 = await core00.callStorm('return($lib.ps.list())')
906
+ # 101 tasks: one for the main task and NUMJOBS for the cronjob instances
907
+ self.len(NUMJOBS + 1, tasks00)
908
+ self.eq(tasks00[0]['info']['query'], '[it:dev:str=foo]')
909
+ for idx, task in enumerate(tasks00):
910
+ if idx == 0:
911
+ continue
912
+
913
+ self.isin(task['info']['iden'], cronidens)
914
+ self.eq(task['info']['query'], '$lib.time.sleep(90)')
915
+
916
+ # No tasks running on the follower
917
+ tasks01 = await core01.callStorm('return($lib.ps.list())')
918
+ self.len(0, tasks01)
919
+
920
+ with self.getLoggerStream('synapse.lib.agenda', mesg='name=CRON99') as stream:
921
+ # Promote and inspect cortex status
922
+ await core01.promote(graceful=True)
923
+ self.false(core00.isactive)
924
+ self.true(core01.isactive)
925
+
926
+ stream.seek(0)
927
+ data = stream.read()
928
+ for ii in range(NUMJOBS):
929
+ self.isin(f' name=CRON{ii} with result "cancelled" took ', data)
930
+
931
+ # Sync the (now) follower so the isrunning status gets updated to false on both cortexes
932
+ await core00.sync()
933
+
934
+ crons00 = await core00.callStorm('return($lib.cron.list())')
935
+ self.len(NUMJOBS, crons00)
936
+ for cron in crons00:
937
+ self.false(cron.get('isrunning'))
938
+
939
+ crons01 = await core01.callStorm('return($lib.cron.list())')
940
+ self.len(NUMJOBS, crons01)
941
+ for cron in crons01:
942
+ self.false(cron.get('isrunning'))
943
+
944
+ # Bump the ticks on core01 so the cron jobs start
945
+ core01.agenda._addTickOff(3600)
946
+
947
+ mesgs = []
948
+ async for mesg in core01.behold():
949
+ mesgs.append(mesg)
950
+ if len(mesgs) >= NUMJOBS:
951
+ break
952
+
953
+ for mesg in mesgs:
954
+ self.eq(mesg['event'], 'cron:start')
955
+
956
+ # Sync the follower to get the latest isrunning status
957
+ await core00.sync()
958
+
959
+ crons00 = await core00.callStorm('return($lib.cron.list())')
960
+ self.len(NUMJOBS, crons00)
961
+ # Cronjobs are running so true on both cortexes
962
+ for cron in crons00:
963
+ self.true(cron.get('isrunning'))
964
+
965
+ crons01 = await core01.callStorm('return($lib.cron.list())')
966
+ self.len(NUMJOBS, crons01)
967
+ # Cronjobs are running so true on both cortexes
968
+ for cron in crons01:
969
+ self.true(cron.get('isrunning'))
970
+
971
+ tasks00 = await core00.callStorm('return($lib.ps.list())')
972
+ # This task is the main task from before promotion
973
+ self.len(1, tasks00)
974
+ self.eq(tasks00[0]['info']['query'], '[it:dev:str=foo]')
975
+
976
+ tasks01 = await core01.callStorm('return($lib.ps.list())')
977
+ # The cronjob instances are the only tasks
978
+ self.len(NUMJOBS, tasks01)
979
+ for task in tasks01:
980
+ self.isin(task['info']['iden'], cronidens)
981
+ self.eq(task['info']['query'], '$lib.time.sleep(90)')
982
+
827
983
  async def test_cron_kill(self):
828
984
  async with self.getTestCore() as core:
829
985
 
@@ -941,3 +1097,127 @@ class AgendaTest(s_t_utils.SynTest):
941
1097
  self.eq(cdef01.get('lastresult'), 'cancelled')
942
1098
  self.gt(cdef00['laststarttime'], 0)
943
1099
  self.eq(cdef00['laststarttime'], cdef01['laststarttime'])
1100
+
1101
+ async def test_agenda_graceful_promotion_with_running_cron(self):
1102
+
1103
+ async with self.getTestAha() as aha:
1104
+
1105
+ conf00 = {
1106
+ 'aha:provision': await aha.addAhaSvcProv('00.cortex')
1107
+ }
1108
+
1109
+ async with self.getTestCore(conf=conf00) as core00:
1110
+ self.false(core00.conf.get('mirror'))
1111
+
1112
+ q = '''
1113
+ while((true)) {
1114
+ $lib.log.error('I AM A ERROR LOG MESSAGE')
1115
+ $lib.time.sleep(6)
1116
+ }
1117
+ '''
1118
+ msgs = await core00.stormlist('cron.at --now $q', opts={'vars': {'q': q}})
1119
+ self.stormHasNoWarnErr(msgs)
1120
+
1121
+ crons00 = await core00.callStorm('return($lib.cron.list())')
1122
+ self.len(1, crons00)
1123
+
1124
+ prov01 = {'mirror': '00.cortex'}
1125
+ conf01 = {
1126
+ 'aha:provision': await aha.addAhaSvcProv('01.cortex', provinfo=prov01),
1127
+ }
1128
+
1129
+ async with self.getTestCore(conf=conf01) as core01:
1130
+
1131
+ with self.getAsyncLoggerStream('synapse.storm.log', 'I AM A ERROR LOG MESSAGE') as stream:
1132
+ self.true(await stream.wait(timeout=6))
1133
+
1134
+ cron = await core00.callStorm('return($lib.cron.list())')
1135
+ self.len(1, cron)
1136
+ self.true(cron[0].get('isrunning'))
1137
+
1138
+ await core01.promote(graceful=True)
1139
+
1140
+ self.false(core00.isactive)
1141
+ self.true(core01.isactive)
1142
+
1143
+ await core00.sync()
1144
+
1145
+ cron00 = await core00.callStorm('return($lib.cron.list())')
1146
+ self.len(1, cron00)
1147
+ self.false(cron00[0].get('isrunning'))
1148
+ self.eq(cron00[0].get('lasterrs')[0], 'aborted')
1149
+
1150
+ cron01 = await core01.callStorm('return($lib.cron.list())')
1151
+ self.len(1, cron01)
1152
+ self.false(cron01[0].get('isrunning'))
1153
+ self.eq(cron01[0].get('lasterrs')[0], 'aborted')
1154
+
1155
+ async def test_agenda_force_promotion_with_running_cron(self):
1156
+
1157
+ async with self.getTestAha() as aha:
1158
+
1159
+ conf00 = {
1160
+ 'aha:provision': await aha.addAhaSvcProv('00.cortex')
1161
+ }
1162
+
1163
+ async with self.getTestCore(conf=conf00) as core00:
1164
+ self.false(core00.conf.get('mirror'))
1165
+
1166
+ q = '''
1167
+ while((true)) {
1168
+ $lib.log.error('I AM A ERROR LOG MESSAGE')
1169
+ $lib.time.sleep(6)
1170
+ }
1171
+ '''
1172
+ msgs = await core00.stormlist('cron.at --now $q', opts={'vars': {'q': q}})
1173
+ self.stormHasNoWarnErr(msgs)
1174
+
1175
+ crons00 = await core00.callStorm('return($lib.cron.list())')
1176
+ self.len(1, crons00)
1177
+
1178
+ prov01 = {'mirror': '00.cortex'}
1179
+ conf01 = {
1180
+ 'aha:provision': await aha.addAhaSvcProv('01.cortex', provinfo=prov01),
1181
+ }
1182
+
1183
+ async with self.getTestCore(conf=conf01) as core01:
1184
+
1185
+ cron = await core00.callStorm('return($lib.cron.list())')
1186
+ self.len(1, cron)
1187
+ self.true(cron[0].get('isrunning'))
1188
+
1189
+ await core01.promote(graceful=False)
1190
+
1191
+ self.true(core00.isactive)
1192
+ self.true(core01.isactive)
1193
+
1194
+ cron01 = await core01.callStorm('return($lib.cron.list())')
1195
+ self.len(1, cron01)
1196
+ self.false(cron01[0].get('isrunning'))
1197
+ self.eq(cron01[0].get('lasterrs')[0], 'aborted')
1198
+
1199
+ async def test_agenda_clear_running_none_nexttime(self):
1200
+
1201
+ async with self.getTestCore() as core:
1202
+
1203
+ cdef = {
1204
+ 'creator': core.auth.rootuser.iden,
1205
+ 'iden': s_common.guid(),
1206
+ 'storm': '$lib.log.info("test")',
1207
+ 'reqs': {},
1208
+ 'incunit': 'minute',
1209
+ 'incvals': 1
1210
+ }
1211
+ await core.addCronJob(cdef)
1212
+
1213
+ appt = core.agenda.appts[cdef['iden']]
1214
+ self.true(appt in core.agenda.apptheap)
1215
+
1216
+ appt.isrunning = True
1217
+ appt.nexttime = None
1218
+
1219
+ await core.agenda.clearRunningStatus()
1220
+ self.false(appt in core.agenda.apptheap)
1221
+
1222
+ crons = await core.callStorm('return($lib.cron.list())')
1223
+ self.len(1, crons)
@@ -59,7 +59,7 @@ class AhaTest(s_test.SynTest):
59
59
  self.len(ahacount, await proxy0.getAhaUrls())
60
60
  self.len(ahacount, await proxy0.getAhaServers())
61
61
 
62
- purl = await proxy0.addAhaClone(zoinks)
62
+ purl = await proxy0.addAhaClone(zoinks, port=0)
63
63
 
64
64
  conf1 = {'clone': purl}
65
65
  async with self.getTestAha(conf=conf1, dirn=dir1) as aha1:
@@ -574,7 +574,7 @@ class AhaTest(s_test.SynTest):
574
574
  }
575
575
  s_common.yamlsave(axonconf, axonpath, 'cell.yaml')
576
576
 
577
- argv = (axonpath, '--auth-passwd', 'rootbeer')
577
+ argv = (axonpath, '--auth-passwd', 'rootbeer', '--https', '0')
578
578
  async with await s_axon.Axon.initFromArgv(argv) as axon:
579
579
 
580
580
  # opts were copied through successfully
@@ -1161,7 +1161,8 @@ class AhaTest(s_test.SynTest):
1161
1161
  aconf = {
1162
1162
  'aha:name': 'aha',
1163
1163
  'aha:network': networkname,
1164
- 'provision:listen': f'ssl://aha.{networkname}:0'
1164
+ 'dmon:listen': f'ssl://aha.{networkname}:0',
1165
+ 'provision:listen': f'ssl://aha.{networkname}:0',
1165
1166
  }
1166
1167
  name = aconf.get('aha:name')
1167
1168
  netw = aconf.get('aha:network')
@@ -1300,11 +1301,17 @@ class AhaTest(s_test.SynTest):
1300
1301
  conf = {
1301
1302
  'aha:network': 'synapse',
1302
1303
  'dns:name': 'here.loop.vertex.link',
1304
+ 'dmon:listen': 'ssl://0.0.0.0:0?hostname=here.loop.vertex.link&ca=synapse',
1303
1305
  }
1304
- mesg = 'provision listening: ssl://0.0.0.0:27272?hostname=here.loop.vertex.link'
1305
- with self.getAsyncLoggerStream('synapse.lib.aha', mesg) as stream:
1306
+
1307
+ orig = s_aha.AhaCell._getProvListen
1308
+ def _getProvListen(_self):
1309
+ ret = orig(_self)
1310
+ self.eq(ret, 'ssl://0.0.0.0:27272?hostname=here.loop.vertex.link')
1311
+ return 'ssl://0.0.0.0:0?hostname=here.loop.vertex.link'
1312
+
1313
+ with mock.patch('synapse.lib.aha.AhaCell._getProvListen', _getProvListen):
1306
1314
  async with self.getTestCell(s_aha.AhaCell, conf=conf) as aha:
1307
- self.true(await stream.wait(timeout=6))
1308
1315
  # And the URL works with our listener :)
1309
1316
  provurl = await aha.addAhaUserEnroll('bob.grey')
1310
1317
  async with await s_telepath.openurl(provurl) as prox: