diff --git a/lockable.go b/lockable.go index d1b65ca..b3d6650 100644 --- a/lockable.go +++ b/lockable.go @@ -66,7 +66,6 @@ type LockableExtJSON struct { Dependencies map[string]string `json:"dependencies"` } -// Simple json load function: TODO: make these a generic function as before func LoadLockableExt(ctx *Context, data []byte) (Extension, error) { var j LockableExtJSON err := json.Unmarshal(data, &j) diff --git a/lockable_test.go b/lockable_test.go index 7dab6bb..1aa054f 100644 --- a/lockable_test.go +++ b/lockable_test.go @@ -17,7 +17,7 @@ func lockableTestContext(t *testing.T, logs []string) *Context { var link_policy = NewAllNodesPolicy([]SignalType{LinkSignalType, StatusSignalType}) -var lock_policy = NewAllNodesPolicy([]SignalType{LinkSignalType, LockSignalType, StatusSignalType}) +var lock_policy = NewAllNodesPolicy([]SignalType{LockSignalType}) func TestLink(t *testing.T) { ctx := lockableTestContext(t, []string{"lockable"}) @@ -50,13 +50,13 @@ func TestLink(t *testing.T) { } func TestLock(t *testing.T) { - ctx := lockableTestContext(t, []string{}) + ctx := lockableTestContext(t, []string{"policy"}) NewLockable := func()(*Node, *ListenerExt) { listener := NewListenerExt(10) l := NewNode(ctx, RandID(), TestLockableType, nil, listener, - NewACLExt(&lock_policy), + NewACLExt(&lock_policy, &link_policy), NewLockableExt(), ) return l, listener diff --git a/policy.go b/policy.go index 91bc685..59af235 100644 --- a/policy.go +++ b/policy.go @@ -18,6 +18,8 @@ const ( type Policy interface { Serializable[PolicyType] Allows(principal_id NodeID, action SignalType, node *Node) error + // Merge with another policy of the same underlying type + Merge(Policy) Policy } //TODO: Update with change from principal *Node to principal_id so sane policies can still be made @@ -67,6 +69,51 @@ func NewRequirementOfPolicy(actions Actions) RequirementOfPolicy { } } +func MergeActions(first Actions, second Actions) Actions { + ret := second + for _, action := range(first) { + found := false + for _, a := range(second) { + if a == action { + break + } + } + if found == false { + ret = append(ret, action) + } + } + return ret +} + +func MergeNodeActions(modified NodeActions, read NodeActions) { + for id, actions := range(read) { + existing, exists := modified[id] + if exists { + modified[id] = MergeActions(existing, actions) + } else { + modified[id] = actions + } + } +} + +func (policy *PerNodePolicy) Merge(p Policy) Policy { + other := p.(*PerNodePolicy) + MergeNodeActions(policy.NodeActions, other.NodeActions) + return policy +} + +func (policy *AllNodesPolicy) Merge(p Policy) Policy { + other := p.(*AllNodesPolicy) + policy.Actions = MergeActions(policy.Actions, other.Actions) + return policy +} + +func (policy *RequirementOfPolicy) Merge(p Policy) Policy { + other := p.(*RequirementOfPolicy) + policy.Actions = MergeActions(policy.Actions, other.Actions) + return policy +} + type Actions []SignalType func (actions Actions) Allows(action SignalType) error { @@ -223,9 +270,9 @@ func (ext *ACLExt) Process(ctx *Context, princ_id NodeID, node *Node, signal Sig func NewACLExt(policies ...Policy) *ACLExt { policy_map := map[PolicyType]Policy{} for _, policy := range(policies) { - _, exists := policy_map[policy.Type()] + existing, exists := policy_map[policy.Type()] if exists == true { - panic("Cannot add same policy type twice") + policy = existing.Merge(policy) } policy_map[policy.Type()] = policy