~ionutbalutoiu/charms/trusty/neutron-api/next

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/openstack/utils.py

  • Committer: David Ames
  • Date: 2015-09-28 17:45:40 UTC
  • mfrom: (145 trunk)
  • mto: This revision was merged to the branch mainline in revision 146.
  • Revision ID: david.ames@canonical.com-20150928174540-wx0t0d3uwgmlsotb
PullĀ inĀ upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    charm_dir,
43
43
    INFO,
44
44
    relation_ids,
45
 
    relation_set
 
45
    relation_set,
 
46
    status_set,
 
47
    hook_name
46
48
)
47
49
 
48
50
from charmhelpers.contrib.storage.linux.lvm import (
52
54
)
53
55
 
54
56
from charmhelpers.contrib.network.ip import (
55
 
    get_ipv6_addr
 
57
    get_ipv6_addr,
 
58
    is_ipv6,
56
59
)
57
60
 
58
61
from charmhelpers.contrib.python.packages import (
517
520
                                      relation_prefix=None):
518
521
    hosts = get_ipv6_addr(dynamic_only=False)
519
522
 
 
523
    if config('vip'):
 
524
        vips = config('vip').split()
 
525
        for vip in vips:
 
526
            if vip and is_ipv6(vip):
 
527
                hosts.append(vip)
 
528
 
520
529
    kwargs = {'database': database,
521
530
              'username': database_user,
522
531
              'hostname': json.dumps(hosts)}
754
763
    return None
755
764
 
756
765
 
 
766
def os_workload_status(configs, required_interfaces, charm_func=None):
 
767
    """
 
768
    Decorator to set workload status based on complete contexts
 
769
    """
 
770
    def wrap(f):
 
771
        @wraps(f)
 
772
        def wrapped_f(*args, **kwargs):
 
773
            # Run the original function first
 
774
            f(*args, **kwargs)
 
775
            # Set workload status now that contexts have been
 
776
            # acted on
 
777
            set_os_workload_status(configs, required_interfaces, charm_func)
 
778
        return wrapped_f
 
779
    return wrap
 
780
 
 
781
 
 
782
def set_os_workload_status(configs, required_interfaces, charm_func=None):
 
783
    """
 
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.
 
789
    """
 
790
    incomplete_rel_data = incomplete_relation_data(configs, required_interfaces)
 
791
    state = 'active'
 
792
    missing_relations = []
 
793
    incomplete_relations = []
 
794
    message = None
 
795
    charm_state = None
 
796
    charm_message = None
 
797
 
 
798
    for generic_interface in incomplete_rel_data.keys():
 
799
        related_interface = None
 
800
        missing_data = {}
 
801
        # Related or not?
 
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')
 
810
            state = 'blocked'
 
811
            if generic_interface not in missing_relations:
 
812
                missing_relations.append(generic_interface)
 
813
        else:
 
814
            # Relation ID exists but no related unit
 
815
            if not missing_data:
 
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():
 
819
                    state = 'blocked'
 
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
 
827
                # (joining)
 
828
                else:
 
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
 
833
            else:
 
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':
 
839
                state = 'waiting'
 
840
            if generic_interface not in incomplete_relations \
 
841
                    and generic_interface not in missing_relations:
 
842
                incomplete_relations.append(generic_interface)
 
843
 
 
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))
 
849
        state = 'blocked'
 
850
    elif incomplete_relations:
 
851
        message = "Incomplete relations: {}" \
 
852
                  "".format(", ".join(incomplete_relations))
 
853
        state = 'waiting'
 
854
 
 
855
    # Run charm specific checks
 
856
    if charm_func:
 
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)
 
860
            if message:
 
861
                message = "{} {}".format(message, charm_message)
 
862
            else:
 
863
                message = charm_message
 
864
 
 
865
    # Set to active if all requirements have been met
 
866
    if state == 'active':
 
867
        message = "Unit is ready"
 
868
        juju_log(message, "INFO")
 
869
 
 
870
    status_set(state, message)
 
871
 
 
872
 
 
873
def workload_state_compare(current_workload_state, workload_state):
 
874
    """ Return highest priority of two states"""
 
875
    hierarchy = {'unknown': -1,
 
876
                 'active': 0,
 
877
                 'maintenance': 1,
 
878
                 'waiting': 2,
 
879
                 'blocked': 3,
 
880
                 }
 
881
 
 
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'
 
886
 
 
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
 
890
    else:
 
891
        return workload_state
 
892
 
 
893
 
 
894
def incomplete_relation_data(configs, required_interfaces):
 
895
    """
 
896
    Check complete contexts against required_interfaces
 
897
    Return dictionary of incomplete relation data.
 
898
 
 
899
    configs is an OSConfigRenderer object with configs registered
 
900
 
 
901
    required_interfaces is a dictionary of required general interfaces
 
902
    with dictionary values of possible specific interfaces.
 
903
    Example:
 
904
    required_interfaces = {'database': ['shared-db', 'pgsql-db']}
 
905
 
 
906
    The interface is said to be satisfied if anyone of the interfaces in the
 
907
    list has a complete context.
 
908
 
 
909
    Return dictionary of incomplete or missing required contexts with relation
 
910
    status of interfaces and any missing data points. Example:
 
911
        {'message':
 
912
             {'amqp': {'missing_data': ['rabbitmq_password'], 'related': True},
 
913
              'zeromq-configuration': {'related': False}},
 
914
         'identity':
 
915
             {'identity-service': {'related': False}},
 
916
         'database':
 
917
             {'pgsql-db': {'related': False},
 
918
              'shared-db': {'related': True}}}
 
919
    """
 
920
    complete_ctxts = configs.complete_contexts()
 
921
    incomplete_relations = []
 
922
    for svc_type in required_interfaces.keys():
 
923
        # Avoid duplicates
 
924
        found_ctxt = False
 
925
        for interface in required_interfaces[svc_type]:
 
926
            if interface in complete_ctxts:
 
927
                found_ctxt = True
 
928
        if not found_ctxt:
 
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
 
934
 
 
935
 
757
936
def do_action_openstack_upgrade(package, upgrade_callback, configs):
758
937
    """Perform action-managed OpenStack upgrade.
759
938