shipyard/src/bin/shipyard_airflow/shipyard_airflow/common/notes/notes_helper.py

160 lines
6.0 KiB
Python

# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import logging
from .notes import MAX_VERBOSITY
from .notes import MIN_VERBOSITY
from .notes import Query
LOG = logging.getLogger(__name__)
# Constants and magic numbers for actions:
# [7:33] to slice a string like:
# action/12345678901234567890123456
# matching the patterns in this helper.
ACTION_KEY_PATTERN = "action/{}"
ACTION_LOOKUP_PATTERN = "action/"
ACTION_ID_START = 7
ACTION_ID_END = 33
class NotesHelper:
"""Notes Helper
Provides helper methods for the common use cases for notes
:param notes_manager: the NotesManager object to use
"""
def __init__(self, notes_manager):
self.nm = notes_manager
def _failsafe_make_note(self, assoc_id, subject, sub_type, note_val,
verbosity=None, link_url=None, is_auth_link=None):
"""LOG and continue on any note creation failure"""
try:
self.nm.create(
assoc_id=assoc_id,
subject=subject,
sub_type=sub_type,
note_val=note_val,
verbosity=verbosity,
link_url=link_url,
is_auth_link=is_auth_link,
)
except Exception as ex:
LOG.warn(
"Creating note for {} encountered a problem, exception info "
"follows, but processing is not halted for notes.",
assoc_id
)
LOG.exception(ex)
def _failsafe_get_notes(self, assoc_id_pattern, max_verbosity,
exact_match):
"""LOG and continue on any note retrieval failure"""
try:
q = Query(assoc_id_pattern, max_verbosity, exact_match)
return self.nm.retrieve(q)
except Exception as ex:
LOG.warn(
"Note retrieval for {} encountered a problem, exception "
"info follows, but processing is not halted for notes.",
assoc_id_pattern
)
LOG.exception(ex)
return []
def make_action_note(self, action_id, note_val, subject=None,
sub_type=None, verbosity=None, link_url=None,
is_auth_link=None):
"""Creates an action note using a convention for the note's assoc_id
:param action_id: the ULID id of an action
:param note_val: the text for the note
:param subject: optional subject for the note. Defaults to the
action_id
:param sub_type: optional subject type for the note, defaults to
"action metadata"
:param verbosity: optional verbosity for the note, defaults to 1,
i.e.: summary level
:param link_url: optional link URL if there's additional information
to retreive from another source.
:param is_auth_link: optional, defaults to False, indicating if there
is a need to send a Shipyard service account token with the
request to the optional URL
"""
assoc_id = ACTION_KEY_PATTERN.format(action_id)
if subject is None:
subject = action_id
if sub_type is None:
sub_type = "action metadata"
if verbosity is None:
verbosity = 1
self._failsafe_make_note(
assoc_id=assoc_id,
subject=subject,
sub_type=sub_type,
note_val=note_val,
verbosity=verbosity,
link_url=link_url,
is_auth_link=is_auth_link,
)
def get_all_action_notes(self, verbosity=None):
"""Retrieve notes for all actions, in a dictionary keyed by action id.
:param verbosity: optional, 1-5, the maximum verbosity level to
retrieve, defaults to 1 (most summary level)
Warning: if there are a lot of URL links in notes, this could take a
long time. The default verbosity of 1 attempts to avoid this as there
is less expectation of URL links on summary notes.
"""
max_verbosity = verbosity or MIN_VERBOSITY
notes = self._failsafe_get_notes(
assoc_id_pattern=ACTION_LOOKUP_PATTERN,
max_verbosity=verbosity,
exact_match=False
)
note_dict = {}
for n in notes:
# magic numbers [7:33] to slice a string like:
# action/12345678901234567890123456/something
# matching the convention in this helper.
# in the case where there are non-compliant, the slice will make
# the action_id a garbage key and that note will not be easily
# associated.
action_id = n.assoc_id[ACTION_ID_START:ACTION_ID_END]
if action_id not in note_dict:
note_dict[action_id] = []
note_dict[action_id].append(n)
return note_dict
def get_action_notes(self, action_id, verbosity=None):
"""Retrive notes related to a particular action
:param action_id: the action for which to retrieve notes.
:param verbosity: optional, 1-5, the maximum verbosity level to
retrieve, defaults to 5 (most detailed level)
"""
assoc_id_pattern = ACTION_KEY_PATTERN.format(action_id)
max_verbosity = verbosity or MAX_VERBOSITY
exact_match = True
return self._failsafe_get_notes(
assoc_id_pattern=assoc_id_pattern,
max_verbosity=max_verbosity,
exact_match=exact_match
)