forked from juju/juju
/
common.go
204 lines (190 loc) · 6.09 KB
/
common.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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package storageprovisioner
import (
"path/filepath"
"github.com/juju/errors"
"gopkg.in/juju/names.v2"
"github.com/juju/juju/apiserver/params"
"github.com/juju/juju/storage"
"github.com/juju/juju/watcher"
)
// storageEntityLife queries the lifecycle state of each specified
// storage entity (volume or filesystem), and then partitions the
// tags by them.
func storageEntityLife(ctx *context, tags []names.Tag) (alive, dying, dead []names.Tag, _ error) {
lifeResults, err := ctx.config.Life.Life(tags)
if err != nil {
return nil, nil, nil, errors.Annotate(err, "getting storage entity life")
}
for i, result := range lifeResults {
if result.Error != nil {
return nil, nil, nil, errors.Annotatef(
result.Error, "getting life of %s",
names.ReadableString(tags[i]),
)
}
switch result.Life {
case params.Alive:
alive = append(alive, tags[i])
case params.Dying:
dying = append(dying, tags[i])
case params.Dead:
dead = append(dead, tags[i])
}
}
return alive, dying, dead, nil
}
// attachmentLife queries the lifecycle state of each specified
// attachment, and then partitions the IDs by them.
func attachmentLife(ctx *context, ids []params.MachineStorageId) (
alive, dying, dead []params.MachineStorageId, _ error,
) {
lifeResults, err := ctx.config.Life.AttachmentLife(ids)
if err != nil {
return nil, nil, nil, errors.Annotate(err, "getting machine attachment life")
}
for i, result := range lifeResults {
if result.Error != nil {
return nil, nil, nil, errors.Annotatef(
result.Error, "getting life of %s attached to %s",
ids[i].AttachmentTag, ids[i].MachineTag,
)
}
switch result.Life {
case params.Alive:
alive = append(alive, ids[i])
case params.Dying:
dying = append(dying, ids[i])
case params.Dead:
dead = append(dead, ids[i])
}
}
return alive, dying, dead, nil
}
// removeEntities removes each specified Dead entity from state.
func removeEntities(ctx *context, tags []names.Tag) error {
if len(tags) == 0 {
return nil
}
logger.Debugf("removing entities: %v", tags)
errorResults, err := ctx.config.Life.Remove(tags)
if err != nil {
return errors.Annotate(err, "removing storage entities")
}
for i, result := range errorResults {
if result.Error != nil {
return errors.Annotatef(result.Error, "removing %s from state", names.ReadableString(tags[i]))
}
}
return nil
}
// removeAttachments removes each specified attachment from state.
func removeAttachments(ctx *context, ids []params.MachineStorageId) error {
if len(ids) == 0 {
return nil
}
errorResults, err := ctx.config.Life.RemoveAttachments(ids)
if err != nil {
return errors.Annotate(err, "removing attachments")
}
for i, result := range errorResults {
if result.Error != nil {
return errors.Annotatef(
result.Error, "removing attachment of %s to %s from state",
ids[i].AttachmentTag, ids[i].MachineTag,
)
}
}
return nil
}
// setStatus sets the given entity statuses, if any. If setting
// the status fails the error is logged but otherwise ignored.
func setStatus(ctx *context, statuses []params.EntityStatusArgs) {
if len(statuses) > 0 {
if err := ctx.config.Status.SetStatus(statuses); err != nil {
logger.Errorf("failed to set status: %v", err)
}
}
}
var errNonDynamic = errors.New("non-dynamic storage provider")
// volumeSource returns a volume source given a name, provider type,
// environment config and storage directory.
//
// TODO(axw) move this to the main storageprovisioner, and have
// it watch for changes to storage source configurations, updating
// a map in-between calls to the volume/filesystem/attachment
// event handlers.
func volumeSource(
baseStorageDir string,
sourceName string,
providerType storage.ProviderType,
registry storage.ProviderRegistry,
) (storage.VolumeSource, error) {
provider, sourceConfig, err := sourceParams(baseStorageDir, sourceName, providerType, registry)
if err != nil {
return nil, errors.Annotatef(err, "getting storage source %q params", sourceName)
}
if !provider.Dynamic() {
return nil, errNonDynamic
}
source, err := provider.VolumeSource(sourceConfig)
if err != nil {
return nil, errors.Annotatef(err, "getting storage source %q", sourceName)
}
return source, nil
}
// filesystemSource returns a filesystem source given a name, provider type,
// environment config and storage directory.
//
// TODO(axw) move this to the main storageprovisioner, and have
// it watch for changes to storage source configurations, updating
// a map in-between calls to the volume/filesystem/attachment
// event handlers.
func filesystemSource(
baseStorageDir string,
sourceName string,
providerType storage.ProviderType,
registry storage.ProviderRegistry,
) (storage.FilesystemSource, error) {
provider, sourceConfig, err := sourceParams(baseStorageDir, sourceName, providerType, registry)
if err != nil {
return nil, errors.Annotatef(err, "getting storage source %q params", sourceName)
}
source, err := provider.FilesystemSource(sourceConfig)
if err != nil {
return nil, errors.Annotatef(err, "getting storage source %q", sourceName)
}
return source, nil
}
func sourceParams(
baseStorageDir string,
sourceName string,
providerType storage.ProviderType,
registry storage.ProviderRegistry,
) (storage.Provider, *storage.Config, error) {
provider, err := registry.StorageProvider(providerType)
if err != nil {
return nil, nil, errors.Annotate(err, "getting provider")
}
attrs := make(map[string]interface{})
if baseStorageDir != "" {
storageDir := filepath.Join(baseStorageDir, sourceName)
attrs[storage.ConfigStorageDir] = storageDir
}
sourceConfig, err := storage.NewConfig(sourceName, providerType, attrs)
if err != nil {
return nil, nil, errors.Annotate(err, "getting config")
}
return provider, sourceConfig, nil
}
func copyMachineStorageIds(src []watcher.MachineStorageId) []params.MachineStorageId {
dst := make([]params.MachineStorageId, len(src))
for i, msid := range src {
dst[i] = params.MachineStorageId{
MachineTag: msid.MachineTag,
AttachmentTag: msid.AttachmentTag,
}
}
return dst
}