766
def os_workload_status(configs, required_interfaces, charm_func=None):
768
Decorator to set workload status based on complete contexts
772
def wrapped_f(*args, **kwargs):
773
# Run the original function first
775
# Set workload status now that contexts have been
777
set_os_workload_status(configs, required_interfaces, charm_func)
782
def set_os_workload_status(configs, required_interfaces, charm_func=None):
784
Set workload status based on complete contexts.
785
status-set missing or incomplete contexts
786
and juju-log details of missing required data.
787
charm_func is a charm specific function to run checking
788
for charm specific requirements such as a VIP setting.
790
incomplete_rel_data = incomplete_relation_data(configs, required_interfaces)
792
missing_relations = []
793
incomplete_relations = []
798
for generic_interface in incomplete_rel_data.keys():
799
related_interface = None
802
for interface in incomplete_rel_data[generic_interface]:
803
if incomplete_rel_data[generic_interface][interface].get('related'):
804
related_interface = interface
805
missing_data = incomplete_rel_data[generic_interface][interface].get('missing_data')
806
# No relation ID for the generic_interface
807
if not related_interface:
808
juju_log("{} relation is missing and must be related for "
809
"functionality. ".format(generic_interface), 'WARN')
811
if generic_interface not in missing_relations:
812
missing_relations.append(generic_interface)
814
# Relation ID exists but no related unit
816
# Edge case relation ID exists but departing
817
if ('departed' in hook_name() or 'broken' in hook_name()) \
818
and related_interface in hook_name():
820
if generic_interface not in missing_relations:
821
missing_relations.append(generic_interface)
822
juju_log("{} relation's interface, {}, "
823
"relationship is departed or broken "
824
"and is required for functionality."
825
"".format(generic_interface, related_interface), "WARN")
826
# Normal case relation ID exists but no related unit
829
juju_log("{} relations's interface, {}, is related but has "
830
"no units in the relation."
831
"".format(generic_interface, related_interface), "INFO")
832
# Related unit exists and data missing on the relation
834
juju_log("{} relation's interface, {}, is related awaiting "
835
"the following data from the relationship: {}. "
836
"".format(generic_interface, related_interface,
837
", ".join(missing_data)), "INFO")
838
if state != 'blocked':
840
if generic_interface not in incomplete_relations \
841
and generic_interface not in missing_relations:
842
incomplete_relations.append(generic_interface)
844
if missing_relations:
845
message = "Missing relations: {}".format(", ".join(missing_relations))
846
if incomplete_relations:
847
message += "; incomplete relations: {}" \
848
"".format(", ".join(incomplete_relations))
850
elif incomplete_relations:
851
message = "Incomplete relations: {}" \
852
"".format(", ".join(incomplete_relations))
855
# Run charm specific checks
857
charm_state, charm_message = charm_func(configs)
858
if charm_state != 'active' and charm_state != 'unknown':
859
state = workload_state_compare(state, charm_state)
861
message = "{} {}".format(message, charm_message)
863
message = charm_message
865
# Set to active if all requirements have been met
866
if state == 'active':
867
message = "Unit is ready"
868
juju_log(message, "INFO")
870
status_set(state, message)
873
def workload_state_compare(current_workload_state, workload_state):
874
""" Return highest priority of two states"""
875
hierarchy = {'unknown': -1,
882
if hierarchy.get(workload_state) is None:
883
workload_state = 'unknown'
884
if hierarchy.get(current_workload_state) is None:
885
current_workload_state = 'unknown'
887
# Set workload_state based on hierarchy of statuses
888
if hierarchy.get(current_workload_state) > hierarchy.get(workload_state):
889
return current_workload_state
891
return workload_state
894
def incomplete_relation_data(configs, required_interfaces):
896
Check complete contexts against required_interfaces
897
Return dictionary of incomplete relation data.
899
configs is an OSConfigRenderer object with configs registered
901
required_interfaces is a dictionary of required general interfaces
902
with dictionary values of possible specific interfaces.
904
required_interfaces = {'database': ['shared-db', 'pgsql-db']}
906
The interface is said to be satisfied if anyone of the interfaces in the
907
list has a complete context.
909
Return dictionary of incomplete or missing required contexts with relation
910
status of interfaces and any missing data points. Example:
912
{'amqp': {'missing_data': ['rabbitmq_password'], 'related': True},
913
'zeromq-configuration': {'related': False}},
915
{'identity-service': {'related': False}},
917
{'pgsql-db': {'related': False},
918
'shared-db': {'related': True}}}
920
complete_ctxts = configs.complete_contexts()
921
incomplete_relations = []
922
for svc_type in required_interfaces.keys():
925
for interface in required_interfaces[svc_type]:
926
if interface in complete_ctxts:
929
incomplete_relations.append(svc_type)
930
incomplete_context_data = {}
931
for i in incomplete_relations:
932
incomplete_context_data[i] = configs.get_incomplete_context_data(required_interfaces[i])
933
return incomplete_context_data
757
936
def do_action_openstack_upgrade(package, upgrade_callback, configs):
758
937
"""Perform action-managed OpenStack upgrade.