Ubuntu Pastebin

Paste from william at Tue, 18 Aug 2015 15:24:48 +0000

Download as text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
// Copyright 2012-2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package relation

// NextHook returns the next hook that should be executed in the relation
// characterised by the supplied local and remote state; or an error if the
// states do not refer to the same relation; or ErrRelationUpToDate if no
// hooks need to be executed.
func NextHook(local *State, remote *RemoteState) (hook.Info, error) {

	// Check sanity.
	if local.RelationId != remote.RelationId {
		template := "mismatched relation state ids (local: %d, remote: %d)"
		return hook.Info{}, errors.Errorf(template, local.RelationId, remote.RelationId)
	}
	relationId := local.RelationId

	// If there's a guaranteed next hook, return that.
	if local.ChangedPending != "" {
		unitName := local.ChangedPending
		return hook.Info{
			Kind:          hooks.RelationChanged,
			RelationId:    relationId,
			RemoteUnit:    unitName,
			ChangeVersion: remote.Members[unitName],
		}, nil
	}

	// Get the union of all relevant units, and sort them, so we produce events
	// in a consistent order (largely for the convenience of the tests).
	allUnitNames := set.NewStrings()
	for unitName := range local.Members {
		allUnitNames.Add(unitName)
	}
	for unitName := range remote.Members {
		allUnitNames.Add(unitName)
	}
	sortedUnitNames := allUnitNames.SortedValues()

	// If there are any locally known units that are no longer reflected in
	// remote state, depart them.
	for _, unitName := range sortedUnitNames {
		changeVersion, found := local.Members[unitName]
		if !found {
			continue
		}
		if _, found := remote.Members[unitName]; !found {
			return hook.Info{
				Kind:          hooks.RelationDeparted,
				RelationId:    relationId,
				RemoteUnit:    unitName,
				ChangeVersion: changeVersion,
			}, nil
		}
	}

	// If the relation's meant to be broken, break it.
	if remote.Broken {
		return hook.Info{
			Kind:       hooks.RelationBroken,
			RelationId: relationId,
		}
	}

	// If there are any remote units not locally known, join them.
	for _, unitName := range sortedUnitNames {
		changeVersion, found := remote.Members[unitName]
		if !found {
			continue
		}
		if _, found := local.Members[unitName]; !found {
			return hook.Info{
				Kind:          hooks.RelationJoined,
				RelationId:    relationId,
				RemoteUnit:    unitName,
				ChangeVersion: changeVersion,
			}
		}
	}

	// Finally scan for remote units whose latest version is not reflected
	// in local state.
	for _, unitName := range sortedUnitNames {
		remoteChangeVersion, found := remote.Members[unitName]
		if !found {
			continue
		}
		localChangeVersion, found := local.Members[unitName]
		if !found {
			continue
		}
		if remoteChangeVersion > localChangeVersion {
			return hook.Info{
				Kind:          hooks.RelationChanged,
				RelationId:    relationId,
				RemoteUnit:    unitName,
				ChangeVersion: remoteChangeVersion,
			}
		}
	}

	// Nothing left to do for this relation.
	return hook.Info{}, ErrRelationUpToDate
}
Download as text