-
Notifications
You must be signed in to change notification settings - Fork 18.6k
/
secrets.go
186 lines (153 loc) · 4.45 KB
/
secrets.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package cluster
import (
"fmt"
"strings"
apitypes "github.com/docker/docker/api/types"
types "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/daemon/cluster/convert"
swarmapi "github.com/docker/swarmkit/api"
"golang.org/x/net/context"
)
func getSecretByNameOrIDPrefix(ctx context.Context, state *nodeState, nameOrIDPrefix string) (*swarmapi.Secret, error) {
// attempt to lookup secret by full ID
if r, err := state.controlClient.GetSecret(ctx, &swarmapi.GetSecretRequest{
SecretID: nameOrIDPrefix,
}); err == nil {
return r.Secret, nil
}
// attempt to lookup secret by full name and partial ID
// Note here ListSecretRequest_Filters operate with `or`
r, err := state.controlClient.ListSecrets(ctx, &swarmapi.ListSecretsRequest{
Filters: &swarmapi.ListSecretsRequest_Filters{
Names: []string{nameOrIDPrefix},
IDPrefixes: []string{nameOrIDPrefix},
},
})
if err != nil {
return nil, err
}
// attempt to lookup secret by full name
for _, s := range r.Secrets {
if s.Spec.Annotations.Name == nameOrIDPrefix {
return s, nil
}
}
// attempt to lookup secret by partial ID (prefix)
// return error if more than one matches found (ambiguous)
n := 0
var found *swarmapi.Secret
for _, s := range r.Secrets {
if strings.HasPrefix(s.ID, nameOrIDPrefix) {
found = s
n++
}
}
if n > 1 {
return nil, fmt.Errorf("secret %s is ambiguous (%d matches found)", nameOrIDPrefix, n)
}
if found == nil {
return nil, fmt.Errorf("no such secret: %s", nameOrIDPrefix)
}
return found, nil
}
// GetSecret returns a secret from a managed swarm cluster
func (c *Cluster) GetSecret(nameOrIDPrefix string) (types.Secret, error) {
c.mu.RLock()
defer c.mu.RUnlock()
state := c.currentNodeState()
if !state.IsActiveManager() {
return types.Secret{}, c.errNoManager(state)
}
ctx, cancel := c.getRequestContext()
defer cancel()
secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
if err != nil {
return types.Secret{}, err
}
return convert.SecretFromGRPC(secret), nil
}
// GetSecrets returns all secrets of a managed swarm cluster.
func (c *Cluster) GetSecrets(options apitypes.SecretListOptions) ([]types.Secret, error) {
c.mu.RLock()
defer c.mu.RUnlock()
state := c.currentNodeState()
if !state.IsActiveManager() {
return nil, c.errNoManager(state)
}
filters, err := newListSecretsFilters(options.Filters)
if err != nil {
return nil, err
}
ctx, cancel := c.getRequestContext()
defer cancel()
r, err := state.controlClient.ListSecrets(ctx,
&swarmapi.ListSecretsRequest{Filters: filters})
if err != nil {
return nil, err
}
secrets := []types.Secret{}
for _, secret := range r.Secrets {
secrets = append(secrets, convert.SecretFromGRPC(secret))
}
return secrets, nil
}
// CreateSecret creates a new secret in a managed swarm cluster.
func (c *Cluster) CreateSecret(s types.SecretSpec) (string, error) {
c.mu.RLock()
defer c.mu.RUnlock()
state := c.currentNodeState()
if !state.IsActiveManager() {
return "", c.errNoManager(state)
}
ctx, cancel := c.getRequestContext()
defer cancel()
secretSpec := convert.SecretSpecToGRPC(s)
r, err := state.controlClient.CreateSecret(ctx,
&swarmapi.CreateSecretRequest{Spec: &secretSpec})
if err != nil {
return "", err
}
return r.Secret.ID, nil
}
// RemoveSecret removes a secret from a managed swarm cluster.
func (c *Cluster) RemoveSecret(nameOrIDPrefix string) error {
c.mu.RLock()
defer c.mu.RUnlock()
state := c.currentNodeState()
if !state.IsActiveManager() {
return c.errNoManager(state)
}
ctx, cancel := c.getRequestContext()
defer cancel()
secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
if err != nil {
return err
}
req := &swarmapi.RemoveSecretRequest{
SecretID: secret.ID,
}
_, err = state.controlClient.RemoveSecret(ctx, req)
return err
}
// UpdateSecret updates a secret in a managed swarm cluster.
// Note: this is not exposed to the CLI but is available from the API only
func (c *Cluster) UpdateSecret(id string, version uint64, spec types.SecretSpec) error {
c.mu.RLock()
defer c.mu.RUnlock()
state := c.currentNodeState()
if !state.IsActiveManager() {
return c.errNoManager(state)
}
ctx, cancel := c.getRequestContext()
defer cancel()
secretSpec := convert.SecretSpecToGRPC(spec)
_, err := state.controlClient.UpdateSecret(ctx,
&swarmapi.UpdateSecretRequest{
SecretID: id,
SecretVersion: &swarmapi.Version{
Index: version,
},
Spec: &secretSpec,
})
return err
}