769
def os_workload_status(configs, required_interfaces, charm_func=None):
771
Decorator to set workload status based on complete contexts
775
def wrapped_f(*args, **kwargs):
776
# Run the original function first
778
# Set workload status now that contexts have been
780
set_os_workload_status(configs, required_interfaces, charm_func)
785
def set_os_workload_status(configs, required_interfaces, charm_func=None):
787
Set workload status based on complete contexts.
788
status-set missing or incomplete contexts
789
and juju-log details of missing required data.
790
charm_func is a charm specific function to run checking
791
for charm specific requirements such as a VIP setting.
793
incomplete_rel_data = incomplete_relation_data(configs, required_interfaces)
795
missing_relations = []
796
incomplete_relations = []
801
for generic_interface in incomplete_rel_data.keys():
802
related_interface = None
805
for interface in incomplete_rel_data[generic_interface]:
806
if incomplete_rel_data[generic_interface][interface].get('related'):
807
related_interface = interface
808
missing_data = incomplete_rel_data[generic_interface][interface].get('missing_data')
809
# No relation ID for the generic_interface
810
if not related_interface:
811
juju_log("{} relation is missing and must be related for "
812
"functionality. ".format(generic_interface), 'WARN')
814
if generic_interface not in missing_relations:
815
missing_relations.append(generic_interface)
817
# Relation ID exists but no related unit
819
# Edge case relation ID exists but departing
820
if ('departed' in hook_name() or 'broken' in hook_name()) \
821
and related_interface in hook_name():
823
if generic_interface not in missing_relations:
824
missing_relations.append(generic_interface)
825
juju_log("{} relation's interface, {}, "
826
"relationship is departed or broken "
827
"and is required for functionality."
828
"".format(generic_interface, related_interface), "WARN")
829
# Normal case relation ID exists but no related unit
832
juju_log("{} relations's interface, {}, is related but has "
833
"no units in the relation."
834
"".format(generic_interface, related_interface), "INFO")
835
# Related unit exists and data missing on the relation
837
juju_log("{} relation's interface, {}, is related awaiting "
838
"the following data from the relationship: {}. "
839
"".format(generic_interface, related_interface,
840
", ".join(missing_data)), "INFO")
841
if state != 'blocked':
843
if generic_interface not in incomplete_relations \
844
and generic_interface not in missing_relations:
845
incomplete_relations.append(generic_interface)
847
if missing_relations:
848
message = "Missing relations: {}".format(", ".join(missing_relations))
849
if incomplete_relations:
850
message += "; incomplete relations: {}" \
851
"".format(", ".join(incomplete_relations))
853
elif incomplete_relations:
854
message = "Incomplete relations: {}" \
855
"".format(", ".join(incomplete_relations))
858
# Run charm specific checks
860
charm_state, charm_message = charm_func(configs)
861
if charm_state != 'active' and charm_state != 'unknown':
862
state = workload_state_compare(state, charm_state)
864
charm_message = charm_message.replace("Incomplete relations: ",
866
message = "{}, {}".format(message, charm_message)
868
message = charm_message
870
# Set to active if all requirements have been met
871
if state == 'active':
872
message = "Unit is ready"
873
juju_log(message, "INFO")
875
status_set(state, message)
878
def workload_state_compare(current_workload_state, workload_state):
879
""" Return highest priority of two states"""
880
hierarchy = {'unknown': -1,
887
if hierarchy.get(workload_state) is None:
888
workload_state = 'unknown'
889
if hierarchy.get(current_workload_state) is None:
890
current_workload_state = 'unknown'
892
# Set workload_state based on hierarchy of statuses
893
if hierarchy.get(current_workload_state) > hierarchy.get(workload_state):
894
return current_workload_state
896
return workload_state
899
def incomplete_relation_data(configs, required_interfaces):
901
Check complete contexts against required_interfaces
902
Return dictionary of incomplete relation data.
904
configs is an OSConfigRenderer object with configs registered
906
required_interfaces is a dictionary of required general interfaces
907
with dictionary values of possible specific interfaces.
909
required_interfaces = {'database': ['shared-db', 'pgsql-db']}
911
The interface is said to be satisfied if anyone of the interfaces in the
912
list has a complete context.
914
Return dictionary of incomplete or missing required contexts with relation
915
status of interfaces and any missing data points. Example:
917
{'amqp': {'missing_data': ['rabbitmq_password'], 'related': True},
918
'zeromq-configuration': {'related': False}},
920
{'identity-service': {'related': False}},
922
{'pgsql-db': {'related': False},
923
'shared-db': {'related': True}}}
925
complete_ctxts = configs.complete_contexts()
926
incomplete_relations = []
927
for svc_type in required_interfaces.keys():
930
for interface in required_interfaces[svc_type]:
931
if interface in complete_ctxts:
934
incomplete_relations.append(svc_type)
935
incomplete_context_data = {}
936
for i in incomplete_relations:
937
incomplete_context_data[i] = configs.get_incomplete_context_data(required_interfaces[i])
938
return incomplete_context_data
941
def do_action_openstack_upgrade(package, upgrade_callback, configs):
942
"""Perform action-managed OpenStack upgrade.
944
Upgrades packages to the configured openstack-origin version and sets
945
the corresponding action status as a result.
947
If the charm was installed from source we cannot upgrade it.
948
For backwards compatibility a config flag (action-managed-upgrade) must
949
be set for this code to run, otherwise a full service level upgrade will
950
fire on config-changed.
952
@param package: package name for determining if upgrade available
953
@param upgrade_callback: function callback to charm's upgrade function
954
@param configs: templating object derived from OSConfigRenderer class
956
@return: True if upgrade successful; False if upgrade failed or skipped
960
if git_install_requested():
961
action_set({'outcome': 'installed from source, skipped upgrade.'})
963
if openstack_upgrade_available(package):
964
if config('action-managed-upgrade'):
965
juju_log('Upgrading OpenStack release')
968
upgrade_callback(configs=configs)
969
action_set({'outcome': 'success, upgrade completed.'})
972
action_set({'outcome': 'upgrade failed, see traceback.'})
973
action_set({'traceback': traceback.format_exc()})
974
action_fail('do_openstack_upgrade resulted in an '
977
action_set({'outcome': 'action-managed-upgrade config is '
978
'False, skipped upgrade.'})
980
action_set({'outcome': 'no upgrade available.'})
694
985
def remote_restart(rel_name, remote_service=None):
696
987
'restart-trigger': str(uuid.uuid4()),