Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Commit f65f82a

Browse files
author
David Chung
authored
Support shared attachment in swarm plugin (#476)
Signed-off-by: David Chung <[email protected]>
1 parent 6ecb296 commit f65f82a

File tree

2 files changed

+62
-24
lines changed

2 files changed

+62
-24
lines changed

examples/flavor/swarm/flavor.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@ import (
2424

2525
const (
2626
ebsAttachment string = "ebs"
27+
28+
// AllInstances as a special logical ID for use in the Attachments map
29+
AllInstances = instance.LogicalID("*")
2730
)
2831

2932
// Spec is the value passed in the `Properties` field of configs
3033
type Spec struct {
31-
// Attachments indicate the devices that are to be attached to the instance
34+
35+
// Attachments indicate the devices that are to be attached to the instance.
36+
// If the logical ID is '*' (the AllInstances const) then the attachment applies to all instances.
3237
Attachments map[instance.LogicalID][]instance.Attachment
3338

3439
// InitScriptTemplateURL overrides the template specified when the plugin started up.
@@ -316,6 +321,13 @@ func (s *baseFlavor) prepare(role string, flavorProperties *types.Any, instanceS
316321
}
317322
}
318323

324+
// look for the AllInstances logicalID in shared attachments
325+
for logicalID, attachments := range spec.Attachments {
326+
if logicalID == AllInstances {
327+
instanceSpec.Attachments = append(instanceSpec.Attachments, attachments...)
328+
}
329+
}
330+
319331
// TODO(wfarner): Use the cluster UUID to scope instances for this swarm separately from instances in another
320332
// swarm. This will require plumbing back to Scaled (membership tags).
321333
instanceSpec.Tags["swarm-id"] = swarmID
@@ -341,7 +353,7 @@ func validateIDsAndAttachments(logicalIDs []instance.LogicalID,
341353
idsMap[id] = true
342354
}
343355
for id := range attachments {
344-
if _, exists := idsMap[id]; !exists {
356+
if _, exists := idsMap[id]; !exists && id != AllInstances {
345357
return fmt.Errorf("LogicalID %v used for an attachment but is not in group LogicalIDs", id)
346358
}
347359
}
@@ -350,17 +362,7 @@ func validateIDsAndAttachments(logicalIDs []instance.LogicalID,
350362
for _, atts := range attachments {
351363
for _, attachment := range atts {
352364
if attachment.Type == "" {
353-
return fmt.Errorf(
354-
"Attachment Type %s must be specified for '%s'",
355-
ebsAttachment,
356-
attachment.ID)
357-
}
358-
359-
if attachment.Type != ebsAttachment {
360-
return fmt.Errorf(
361-
"Invalid attachment Type '%s', only %s is supported",
362-
attachment.Type,
363-
ebsAttachment)
365+
return fmt.Errorf("no attachment type")
364366
}
365367
}
366368
}

examples/flavor/swarm/flavor_test.go

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,13 @@ func TestValidate(t *testing.T) {
8080
require.Error(t, err)
8181
require.Equal(t, "Attachment a specified more than once", err.Error())
8282

83-
// Unsupported Attachment Type.
83+
// Attachment for all
8484
err = managerFlavor.Validate(
8585
types.AnyString(`{
8686
"Docker" : {"Host":"unix:///var/run/docker.sock"},
87-
"Attachments": {"127.0.0.1": [{"ID": "a", "Type": "keyboard"}]}}`),
87+
"Attachments": {"*": [{"ID": "a", "Type": "NFSVolume"}]}}`),
8888
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"127.0.0.1"}})
89-
require.Error(t, err)
90-
require.Equal(t, "Invalid attachment Type 'keyboard', only ebs is supported", err.Error())
89+
require.NoError(t, err)
9190

9291
close(managerStop)
9392
close(workerStop)
@@ -192,16 +191,28 @@ func TestManager(t *testing.T) {
192191
client.EXPECT().NodeInspectWithRaw(gomock.Any(), nodeID).Return(nodeInfo, nil, nil).AnyTimes()
193192
client.EXPECT().Close().AnyTimes()
194193

194+
flavorSpec := types.AnyString(`
195+
{
196+
"Attachments" : {
197+
"10.20.100.1" : [ { "ID" : "disk01", "Type" : "disk" }, { "ID" : "nic01", "Type" : "nic" } ],
198+
"10.20.100.2" : [ { "ID" : "disk02", "Type" : "disk" }, { "ID" : "nic02", "Type" : "nic" } ],
199+
"10.20.100.3" : [ { "ID" : "disk03", "Type" : "disk" }, { "ID" : "nic03", "Type" : "nic" } ]
200+
}
201+
}
202+
`)
203+
195204
index := group_types.Index{Group: group.ID("group"), Sequence: 0}
196-
id := instance.LogicalID("127.0.0.1")
197-
details, err := flavorImpl.Prepare(
198-
types.AnyString(`{"Attachments": {"127.0.0.1": [{"ID": "a", "Type": "gpu"}]}}`),
205+
id := instance.LogicalID("10.20.100.1")
206+
details, err := flavorImpl.Prepare(flavorSpec,
199207
instance.Spec{Tags: map[string]string{"a": "b"}, LogicalID: &id},
200-
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"127.0.0.1"}},
208+
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"10.20.100.1"}},
201209
index)
202210
require.NoError(t, err)
203211
require.Equal(t, "b", details.Tags["a"])
204212

213+
// ensures that the attachments are matched to the logical ID of the instance and in the attachments map
214+
require.Equal(t, []instance.Attachment{{ID: "disk01", Type: "disk"}, {ID: "nic01", Type: "nic"}}, details.Attachments)
215+
205216
link := types.NewLinkFromMap(details.Tags)
206217
require.True(t, link.Valid())
207218
require.True(t, len(link.KVPairs()) > 0)
@@ -228,6 +239,31 @@ func TestManager(t *testing.T) {
228239

229240
require.Equal(t, []instance.Attachment{{ID: "a", Type: "gpu"}}, details.Attachments)
230241

242+
// Shared AllInstances for attachment
243+
for _, id := range []instance.LogicalID{
244+
instance.LogicalID("10.20.100.1"),
245+
instance.LogicalID("10.20.100.2"),
246+
instance.LogicalID("10.20.100.3"),
247+
} {
248+
249+
details, err = flavorImpl.Prepare(
250+
types.AnyString(`{"Attachments": {"*": [{"ID": "nfs", "Type": "NFSVolume"}]}}`),
251+
instance.Spec{Tags: map[string]string{"a": "b"}, LogicalID: &id},
252+
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"10.20.100.1", "10.20.100.2", "10.20.100.3"}},
253+
index)
254+
require.NoError(t, err)
255+
require.Equal(t, []instance.Attachment{{ID: "nfs", Type: "NFSVolume"}}, details.Attachments)
256+
}
257+
258+
// Shared AllInstances for attachment -- for workers / no special logical IDs
259+
details, err = flavorImpl.Prepare(
260+
types.AnyString(`{"Attachments": {"*": [{"ID": "nfs", "Type": "NFSVolume"}]}}`),
261+
instance.Spec{Tags: map[string]string{"a": "b"}},
262+
group_types.AllocationMethod{Size: 10},
263+
index)
264+
require.NoError(t, err)
265+
require.Equal(t, []instance.Attachment{{ID: "nfs", Type: "NFSVolume"}}, details.Attachments)
266+
231267
// An instance with no association information is considered unhealthy.
232268
health, err := flavorImpl.Healthy(types.AnyString("{}"), instance.Description{})
233269
require.NoError(t, err)
@@ -278,16 +314,16 @@ func TestTemplateFunctions(t *testing.T) {
278314

279315
properties := types.AnyString(`
280316
{
281-
"Attachments": {"127.0.0.1": [{"ID": "a", "Type": "gpu"}]},
317+
"Attachments": {"10.20.100.1": [{"ID": "a", "Type": "gpu"}]},
282318
"InitScriptTemplateURL" : "str://` + initTemplate + `"
283319
}
284320
`)
285321

286322
index := group_types.Index{Group: group.ID("group"), Sequence: 100}
287-
id := instance.LogicalID("127.0.0.1")
323+
id := instance.LogicalID("10.20.100.1")
288324
details, err := flavorImpl.Prepare(properties,
289325
instance.Spec{Tags: map[string]string{"a": "b"}, LogicalID: &id},
290-
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"127.0.0.1"}},
326+
group_types.AllocationMethod{LogicalIDs: []instance.LogicalID{"10.20.100.1"}},
291327
index)
292328
require.NoError(t, err)
293329
require.Equal(t, fmt.Sprintf("%v,%v", index.Group, index.Sequence), details.Init)

0 commit comments

Comments
 (0)