-
Notifications
You must be signed in to change notification settings - Fork 491
/
binding.go
137 lines (119 loc) · 4.69 KB
/
binding.go
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2019 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package application
import (
"fmt"
"sort"
"strings"
"github.com/juju/collections/set"
"github.com/juju/errors"
)
const parseBindError = "--bind must be in the form '[<default-space>] [<endpoint-name>=<space> ...]'; %s"
// parseBindExpr parses the --bind option and returns back a map where keys
// are endpoint names and values are space names. Valid forms are:
// - relation-name=space-name
// - extra-binding-name=space-name
// - space-name (equivalent to binding all endpoints to the same space, i.e. application-default)
// - The above in a space separated list to specify multiple bindings,
// e.g. "rel1=space1 ext1=space2 space3"
func parseBindExpr(expr string, knownSpaceNames set.Strings) (map[string]string, error) {
if expr == "" {
return nil, nil
}
parsedBindings := make(map[string]string)
for _, s := range strings.Fields(expr) {
v := strings.Split(s, "=")
var endpoint, spaceName string
switch len(v) {
case 1:
endpoint = ""
spaceName = v[0]
case 2:
if v[0] == "" {
return nil, errors.Errorf(parseBindError,
`found "=" without endpoint name. Use a lone space name to set the default.`)
}
endpoint = v[0]
spaceName = v[1]
default:
return nil, errors.Errorf(parseBindError,
`found multiple "=" in binding. Did you forget to space-separate the binding list?`)
}
// This is a temporary hack to allow us to bind endpoints to the
// default spaceName which is currently represented as a blank string.
// It will be removed when the work for properly naming the
// default spaceName lands.
spaceName = strings.Trim(spaceName, `"`)
if !knownSpaceNames.Contains(spaceName) {
return nil, errors.NotFoundf("space %q", spaceName)
}
parsedBindings[endpoint] = spaceName
}
return parsedBindings, nil
}
// mergeBindings is invoked when upgrading a charm to merge the existing set of
// endpoint to space assignments for a deployed application and the user-defined
// bindings passed to the upgrade-charm command.
func mergeBindings(
newCharmEndpoints set.Strings, oldEndpointsMap, userBindings map[string]string, oldDefaultSpace string,
) (map[string]string, []string) {
var changelog []string
if oldEndpointsMap == nil {
oldEndpointsMap = make(map[string]string)
}
if userBindings == nil {
userBindings = make(map[string]string)
}
newDefaultSpace, newDefaultBindingDefined := userBindings[""]
changeDefaultSpace := newDefaultBindingDefined && oldDefaultSpace != newDefaultSpace
mergedBindings := make(map[string]string)
unmodifiedEndpoints := make(map[string][]string)
for _, epName := range newCharmEndpoints.SortedValues() {
newSpaceAssignment, newBindingDefined := userBindings[epName]
// If this is a new endpoint and it is not specified, assign it to the default space
oldSpaceAssignment, isOldEndpoint := oldEndpointsMap[epName]
if !isOldEndpoint {
// If not explicitly defined, it inherits the default space for the application
if !newBindingDefined {
mergedBindings[epName] = oldDefaultSpace
changelog = append(changelog, fmt.Sprintf("adding endpoint %q to default space %q", epName, oldDefaultSpace))
} else {
mergedBindings[epName] = newSpaceAssignment
changelog = append(changelog, fmt.Sprintf("adding endpoint %q to space %q", epName, newSpaceAssignment))
}
continue
}
// This is an existing endpoint. Check whether the operator
// specified a different space for it.
if newBindingDefined && oldSpaceAssignment != newSpaceAssignment {
mergedBindings[epName] = newSpaceAssignment
changelog = append(changelog,
fmt.Sprintf("moving endpoint %q from space %q to %q", epName, oldSpaceAssignment, newSpaceAssignment))
continue
}
// Next, check whether the endpoint is bound to the old default
// space and override it to the new default space.
if !newBindingDefined && changeDefaultSpace && oldSpaceAssignment == oldDefaultSpace {
mergedBindings[epName] = newDefaultSpace
changelog = append(changelog,
fmt.Sprintf("moving endpoint %q from space %q to %q", epName, oldSpaceAssignment, newDefaultSpace))
continue
}
// Retain the existing binding
mergedBindings[epName] = oldSpaceAssignment
unmodifiedEndpoints[oldSpaceAssignment] = append(unmodifiedEndpoints[oldSpaceAssignment], epName)
}
for spName, epList := range unmodifiedEndpoints {
var pluralSuffix string
if len(epList) > 1 {
pluralSuffix = "s"
}
sort.Strings(epList)
changelog = append(changelog,
fmt.Sprintf("no change to endpoint%s in space %q: %s", pluralSuffix, spName, strings.Join(epList, ", ")))
}
if changeDefaultSpace {
mergedBindings[""] = newDefaultSpace
}
return mergedBindings, changelog
}