def event(obj, *, type, reason, message=''): """ Issue an event for the object. """ if isinstance(obj, (list, tuple)): for item in obj: event(obj, type=type, reason=reason, message=message) return now = datetime.datetime.utcnow() namespace = obj['metadata']['namespace'] meta = kubernetes.client.V1ObjectMeta( namespace=namespace, generate_name='kopf-event-', ) body = kubernetes.client.V1beta1Event( metadata=meta, action='Action?', type=type, reason=reason, note=message, # message=message, reporting_controller='kopf', reporting_instance='dev', deprecated_source=kubernetes.client.V1EventSource( component='kopf' ), # used in the "From" column in `kubectl describe`. regarding=build_object_reference(obj), # related=build_object_reference(obj), event_time=now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' deprecated_first_timestamp=now.isoformat() + 'Z', # used in the "Age" column in `kubectl describe`. ) api = kubernetes.client.EventsV1beta1Api() api.create_namespaced_event( namespace=namespace, body=body, )
def event(objs, *, type, reason, message=''): for obj in dicts.walk(objs): ref = hierarchies.build_object_reference(obj) enqueue(ref=ref, type=type, reason=reason, message=message)
async def post_event(*, obj=None, ref=None, type, reason, message=''): """ Issue an event for the object. This is where they can also be accumulated, aggregated, grouped, and where the rate-limits should be maintained. It can (and should) be done by the client library, as it is done in the Go client. """ # Object reference - similar to the owner reference, but different. if obj is not None and ref is not None: raise TypeError( "Only one of obj= and ref= is allowed for a posted event. Got both." ) if obj is None and ref is None: raise TypeError( "One of obj= and ref= is required for a posted event. Got none.") if ref is None: ref = hierarchies.build_object_reference(obj) now = datetime.datetime.utcnow() namespace = ref['namespace'] or 'default' # Prevent a common case of event posting errors but shortening the message. if len(message) > MAX_MESSAGE_LENGTH: infix = CUT_MESSAGE_INFIX prefix = message[:MAX_MESSAGE_LENGTH // 2 - (len(infix) // 2)] suffix = message[-MAX_MESSAGE_LENGTH // 2 + (len(infix) - len(infix) // 2):] message = f'{prefix}{infix}{suffix}' meta = kubernetes.client.V1ObjectMeta( namespace=namespace, generate_name='kopf-event-', ) body = kubernetes.client.V1Event( metadata=meta, action='Action?', type=type, reason=reason, message=message, reporting_component='kopf', reporting_instance='dev', source=kubernetes.client.V1EventSource( component='kopf' ), # used in the "From" column in `kubectl describe`. involved_object=ref, first_timestamp=now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' -- seen in `kubectl describe ...` last_timestamp=now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' - seen in `kubectl get events` event_time=now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' ) api = kubernetes.client.CoreV1Api() loop = asyncio.get_running_loop() try: await loop.run_in_executor( config.WorkersConfig.get_syn_executor(), functools.partial(api.create_namespaced_event, **{ 'namespace': namespace, 'body': body })) except kubernetes.client.rest.ApiException as e: # Events are helpful but auxiliary, they should not fail the handling cycle. # Yet we want to notice that something went wrong (in logs). logger.warning( "Failed to post an event. Ignoring and continuing. " f"Error: {e!r}. " f"Event: type={type!r}, reason={reason!r}, message={message!r}.")
def event(objs, *, type, reason, message=''): queue = event_queue_var.get() for obj in dicts.walk(objs): ref = hierarchies.build_object_reference(obj) event = K8sEvent(ref=ref, type=type, reason=reason, message=message) queue.put_nowait(event)
async def post_event(*, obj=None, ref=None, type, reason, message=''): """ Issue an event for the object. This is where they can also be accumulated, aggregated, grouped, and where the rate-limits should be maintained. It can (and should) be done by the client library, as it is done in the Go client. """ # Object reference - similar to the owner reference, but different. if obj is not None and ref is not None: raise TypeError( "Only one of obj= and ref= is allowed for a posted event. Got both." ) if obj is None and ref is None: raise TypeError( "One of obj= and ref= is required for a posted event. Got none.") if ref is None: ref = hierarchies.build_object_reference(obj) now = datetime.datetime.utcnow() namespace = ref['namespace'] or 'default' # Prevent a common case of event posting errors but shortening the message. if len(message) > MAX_MESSAGE_LENGTH: infix = CUT_MESSAGE_INFIX prefix = message[:MAX_MESSAGE_LENGTH // 2 - (len(infix) // 2)] suffix = message[-MAX_MESSAGE_LENGTH // 2 + (len(infix) - len(infix) // 2):] message = f'{prefix}{infix}{suffix}' body = { 'metadata': { 'namespace': namespace, 'generateName': 'kopf-event-', }, 'action': 'Action?', 'type': type, 'reason': reason, 'message': message, 'reportingComponent': 'kopf', 'reportingInstance': 'dev', 'source': { 'component': 'kopf' }, # used in the "From" column in `kubectl describe`. 'involvedObject': ref, 'firstTimestamp': now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' -- seen in `kubectl describe ...` 'lastTimestamp': now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' - seen in `kubectl get events` 'eventTime': now.isoformat() + 'Z', # '2019-01-28T18:25:03.000000Z' } try: api = auth.get_pykube_api() obj = pykube.Event(api, body) loop = asyncio.get_running_loop() await loop.run_in_executor(config.WorkersConfig.get_syn_executor(), obj.create) except (requests.exceptions.HTTPError, pykube.exceptions.HTTPError) as e: # Events are helpful but auxiliary, they should not fail the handling cycle. # Yet we want to notice that something went wrong (in logs). logger.warning( "Failed to post an event. Ignoring and continuing. " f"Error: {e!r}. " f"Event: type={type!r}, reason={reason!r}, message={message!r}.")