opentf-toolkit-nightly 0.57.0.dev1039__py3-none-any.whl → 0.57.0.dev1051__py3-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.
@@ -43,7 +43,7 @@ from .auth import (
43
43
  get_user_accessible_namespaces,
44
44
  is_user_authorized,
45
45
  )
46
- from .pubsub import make_event, publish, subscribe, unsubscribe
46
+ from .pubsub import make_dispatchqueue, make_event, publish, subscribe, unsubscribe
47
47
  from .schemas import *
48
48
 
49
49
 
@@ -550,7 +550,7 @@ def run_app(app: Flask) -> None:
550
550
  app.logger.info(f'Serving on http://{context["host"]}:{context["port"]}')
551
551
  _app = app
552
552
 
553
- serve(_app, host=context['host'], port=context['port'])
553
+ serve(_app, host=context['host'], port=context['port'], server_name=app.name)
554
554
 
555
555
 
556
556
  ########################################################################
opentf/commons/pubsub.py CHANGED
@@ -17,8 +17,11 @@
17
17
  from typing import Any, Dict, Optional
18
18
 
19
19
  import sys
20
+ import threading
20
21
 
21
22
  from datetime import datetime
23
+ from queue import Queue
24
+ from time import sleep
22
25
 
23
26
 
24
27
  from requests import delete, post, Response
@@ -105,6 +108,51 @@ def _do(req, path: str, eventbus: Dict[str, Any], **kwargs) -> Response:
105
108
  )
106
109
 
107
110
 
111
+ def _dispatch_events(dispatch_queue: Queue, app) -> None:
112
+ """Async event dispatch thread handler."""
113
+ delay = 0
114
+ while True:
115
+ try:
116
+ publication = dispatch_queue.get()
117
+ try:
118
+ publish(publication, app.config['CONTEXT'])
119
+ delay = 0
120
+ except Exception:
121
+ dispatch_queue.put(publication)
122
+ delay = min(2 * delay + 0.2, 60)
123
+ sleep(delay)
124
+ except Exception as err:
125
+ app.logger.error(f'Internal error while dispatching publication: {err}.')
126
+
127
+
128
+ def make_dispatchqueue(app) -> Queue:
129
+ """Make an asynchronous dispatch queue.
130
+
131
+ Handles publication failures by waiting for an increasing delay and
132
+ re-attempting publication.
133
+
134
+ The delay is at most 60 seconds.
135
+
136
+ # Required parameters
137
+
138
+ - app: a flask app
139
+
140
+ # Returned value
141
+
142
+ A _queue_. Events pushed to this queue will be published.
143
+ """
144
+ queue = Queue()
145
+ app.logger.debug('Starting events dispatch thread.')
146
+ try:
147
+ threading.Thread(
148
+ target=_dispatch_events, args=[queue, app], daemon=True
149
+ ).start()
150
+ return queue
151
+ except Exception as err:
152
+ app.logger.error('Cound not start events dispatch thread: %s.', str(err))
153
+ sys.exit(2)
154
+
155
+
108
156
  def subscribe(
109
157
  kind: Optional[str],
110
158
  target: str,
@@ -296,22 +296,26 @@ def _dispatch_providercommand(plugin, handler: Handler, body: Dict[str, Any]) ->
296
296
  def _dispatch_executioncommand(_, handler: Handler, body: Dict[str, Any]):
297
297
  """Channel plugin dispatcher."""
298
298
  try:
299
- return handler(body)
299
+ handler(body)
300
300
  except Exception as err:
301
- msg = f'Unexpected execution error: {err}.'
302
- core.publish_error(msg)
303
- return make_status_response('InternalError', msg)
301
+ core.publish_error(f'Unexpected execution error: {err}.')
304
302
 
305
303
 
306
- def _dispatch_generatorcommand(_, handler: Handler, body: Dict[str, Any]):
304
+ def _dispatch_generatorcommand(plugin, handler: Handler, body: Dict[str, Any]):
307
305
  """Generator plugin dispatcher."""
308
306
  try:
307
+ labels = body['metadata'].get('labels', {})
308
+ plugin.logger.debug(
309
+ 'Calling generator %s (%s/%s@%s).',
310
+ handler.__name__,
311
+ labels.get('opentestfactory.org/categoryPrefix', '_'),
312
+ labels.get('opentestfactory.org/category', '_'),
313
+ labels.get('opentestfactory.org/categoryVersion', '_'),
314
+ )
309
315
  inputs: Dict[str, Any] = body.get('with', {})
310
316
  core.publish_generatorresult(handler(inputs))
311
317
  except Exception as err:
312
- msg = f'Unexpected execution error: {err}.'
313
- core.publish_error(msg)
314
- return make_status_response('InternalError', msg)
318
+ core.publish_error(f'Unexpected execution error: {err}.')
315
319
 
316
320
 
317
321
  ########################################################################
@@ -544,6 +548,7 @@ def make_plugin(
544
548
  descriptor=None,
545
549
  schema=None,
546
550
  configfile=None,
551
+ args: Optional[Any] = None,
547
552
  ):
548
553
  """Create and return a new plugin service.
549
554
 
@@ -559,6 +564,11 @@ def make_plugin(
559
564
  - Add publication handler
560
565
  - Create service (not started)
561
566
 
567
+ Some 'optional' parameters are required for some publin types:
568
+
569
+ `args` is required for channel handlers. It must be a list of one
570
+ element that implements the `__contains__` interface.
571
+
562
572
  # Required parameters
563
573
 
564
574
  - name: a string
@@ -572,6 +582,7 @@ def make_plugin(
572
582
  by default)
573
583
  - schema: a string or None (None by default)
574
584
  - configfile: a string or None (None by default)
585
+ - args: a list or None (None by default)
575
586
 
576
587
  # Raised exceptions
577
588
 
@@ -589,6 +600,19 @@ def make_plugin(
589
600
  except Exception as err:
590
601
  return make_status_response('BadRequest', f'Could not parse body: {err}.')
591
602
 
603
+ if channel:
604
+ try:
605
+ channel_id = body['metadata'].get('channel_id')
606
+ if channel_id and channel_id not in args[0]:
607
+ return make_status_response(
608
+ 'OK', 'Job not handled by this channel plugin.'
609
+ )
610
+ except KeyError:
611
+ return make_status_response(
612
+ 'BadRequest',
613
+ f'Not a valid {kind} request: Missing metadata section',
614
+ )
615
+
592
616
  valid, extra = validate_schema(kind, body)
593
617
  if not valid:
594
618
  return make_status_response(
@@ -608,7 +632,7 @@ def make_plugin(
608
632
  elif provider:
609
633
  _dispatch_providercommand(plugin, provider, body)
610
634
  elif channel:
611
- return _dispatch_executioncommand(plugin, channel, body)
635
+ _dispatch_executioncommand(plugin, channel, body)
612
636
  elif generator:
613
637
  _dispatch_generatorcommand(plugin, generator, body)
614
638
  else:
@@ -624,6 +648,10 @@ def make_plugin(
624
648
  raise ValueError(
625
649
  "'descriptor', if specified, must be a dictionary or a list of dictionaries."
626
650
  )
651
+ if channel and (not isinstance(args, list) or len(args) != 1):
652
+ raise ValueError(
653
+ "'args' is required for channel plugins and must be a list of one element."
654
+ )
627
655
 
628
656
  kind = (
629
657
  EXECUTIONCOMMAND
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: opentf-toolkit-nightly
3
- Version: 0.57.0.dev1039
3
+ Version: 0.57.0.dev1051
4
4
  Summary: OpenTestFactory Orchestrator Toolkit
5
5
  Home-page: https://gitlab.com/henixdevelopment/open-source/opentestfactory/python-toolkit
6
6
  Author: Martin Lafaix
@@ -1,9 +1,9 @@
1
- opentf/commons/__init__.py,sha256=KRY8ShQw_0ZZ0oEOiKi4-xnWofE_QsFjEe1T8wUxJ-w,21952
1
+ opentf/commons/__init__.py,sha256=Uq-7WvkMoBiF3C1KnhwIL4LCKpT8EvomnuG4MBYpIhs,21994
2
2
  opentf/commons/auth.py,sha256=bM2Z3kxm2Wku1lKXaRAIg37LHvXWAXIZIqjplDfN2P8,15899
3
3
  opentf/commons/config.py,sha256=dyus4K5Zdmcftc3Y9Z1YRkzA1KwiRLHoeAlg2_A49QM,7876
4
4
  opentf/commons/datasources.py,sha256=4ye-TMtaE88O8GVcWx-FtKXOC8aIZLteR6wfIr7Do8U,25232
5
5
  opentf/commons/expressions.py,sha256=jM_YKXVOFhvOE2aE2IuacuvxhIsOYTFs2oQkpcbWR6g,19645
6
- opentf/commons/pubsub.py,sha256=7khxAHVZiwJRcwIBJ6MPR-f3xY9144-2eNLROwq5F-4,5894
6
+ opentf/commons/pubsub.py,sha256=Y3vOeGNcI4_-uYwBy2grxmn1Oq5r89tyRZZX3mjgiAA,7254
7
7
  opentf/commons/schemas.py,sha256=YSCvlmqc7satt-OqIoYXnmhOyo9h8wIpNyKaBAY4u9c,4039
8
8
  opentf/commons/selectors.py,sha256=DEpLgRAr5HXSpSYI4liXP2hLUTvOSexFa9Vfa1xIQTk,7134
9
9
  opentf/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -46,11 +46,11 @@ opentf/schemas/opentestfactory.org/v1beta1/Workflow.json,sha256=QZ8mM9PhzsI9gTmw
46
46
  opentf/schemas/opentestfactory.org/v1beta2/ServiceConfig.json,sha256=rEvK2YWL5lG94_qYgR_GnLWNsaQhaQ-2kuZdWJr5NnY,3517
47
47
  opentf/scripts/launch_java_service.sh,sha256=S0jAaCuv2sZy0Gf2NGBuPX-eD531rcM-b0fNyhmzSjw,2423
48
48
  opentf/scripts/startup.py,sha256=Da2zo93pBWbdRmj-wgekgLcF94rpNc3ZkbvR8R0w8XY,21279
49
- opentf/toolkit/__init__.py,sha256=FLjU1HzD3M4xyLV3uUrec4RdVDyTcpvMGRnZOZtfXfc,22037
49
+ opentf/toolkit/__init__.py,sha256=0265hKrPC2trSQcTEIiobFCUzeXGRLbIm-T30NP-Kio,23216
50
50
  opentf/toolkit/channels.py,sha256=6xcVKHUK2FdyVKIQmPQbakngfVuQDzCcD_lInOdKpro,17171
51
51
  opentf/toolkit/core.py,sha256=Uc5cRwyi6bs7WVmgvQLTvEa6bXjZ3KfCKWHSdIeUy98,9621
52
- opentf_toolkit_nightly-0.57.0.dev1039.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
53
- opentf_toolkit_nightly-0.57.0.dev1039.dist-info/METADATA,sha256=kY91sP_A0MZIlGFlPHrf4FrfF86p5VWvE81flxjUH90,1951
54
- opentf_toolkit_nightly-0.57.0.dev1039.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
55
- opentf_toolkit_nightly-0.57.0.dev1039.dist-info/top_level.txt,sha256=_gPuE6GTT6UNXy1DjtmQSfCcZb_qYA2vWmjg7a30AGk,7
56
- opentf_toolkit_nightly-0.57.0.dev1039.dist-info/RECORD,,
52
+ opentf_toolkit_nightly-0.57.0.dev1051.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
53
+ opentf_toolkit_nightly-0.57.0.dev1051.dist-info/METADATA,sha256=dlte0IlbCdEPnhzDEE5pyG-A3PxBkdB0No4Ubh64BB8,1951
54
+ opentf_toolkit_nightly-0.57.0.dev1051.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
55
+ opentf_toolkit_nightly-0.57.0.dev1051.dist-info/top_level.txt,sha256=_gPuE6GTT6UNXy1DjtmQSfCcZb_qYA2vWmjg7a30AGk,7
56
+ opentf_toolkit_nightly-0.57.0.dev1051.dist-info/RECORD,,