Skip to content

Commit b0a1aa6

Browse files
committed
Add code for creating volumes
Adds code for creating CSI volumes. This includes: * The basic Plugin object, which manages the connection to the CSI plugin * The basic VolumeManager object, which manages plugins and responds to store events This also includes lots of tests and tests rigging, including fake CSI clients. Signed-off-by: Drew Erny <[email protected]>
1 parent 3a1f960 commit b0a1aa6

17 files changed

Lines changed: 2669 additions & 934 deletions

api/api.pb.txt

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4505,6 +4505,76 @@ file {
45054505
json_name: "publishedNodes"
45064506
}
45074507
}
4508+
message_type {
4509+
name: "VolumeInfo"
4510+
field {
4511+
name: "capacity_bytes"
4512+
number: 1
4513+
label: LABEL_OPTIONAL
4514+
type: TYPE_INT64
4515+
json_name: "capacityBytes"
4516+
}
4517+
field {
4518+
name: "volume_context"
4519+
number: 2
4520+
label: LABEL_REPEATED
4521+
type: TYPE_MESSAGE
4522+
type_name: ".docker.swarmkit.v1.VolumeInfo.VolumeContextEntry"
4523+
json_name: "volumeContext"
4524+
}
4525+
field {
4526+
name: "volume_id"
4527+
number: 3
4528+
label: LABEL_OPTIONAL
4529+
type: TYPE_STRING
4530+
json_name: "volumeId"
4531+
}
4532+
field {
4533+
name: "accessible_topology"
4534+
number: 4
4535+
label: LABEL_REPEATED
4536+
type: TYPE_MESSAGE
4537+
type_name: ".docker.swarmkit.v1.Topology"
4538+
json_name: "accessibleTopology"
4539+
}
4540+
nested_type {
4541+
name: "VolumeContextEntry"
4542+
field {
4543+
name: "key"
4544+
number: 1
4545+
label: LABEL_OPTIONAL
4546+
type: TYPE_STRING
4547+
json_name: "key"
4548+
}
4549+
field {
4550+
name: "value"
4551+
number: 2
4552+
label: LABEL_OPTIONAL
4553+
type: TYPE_STRING
4554+
json_name: "value"
4555+
}
4556+
options {
4557+
map_entry: true
4558+
}
4559+
}
4560+
}
4561+
message_type {
4562+
name: "CapacityRange"
4563+
field {
4564+
name: "required_bytes"
4565+
number: 1
4566+
label: LABEL_OPTIONAL
4567+
type: TYPE_INT64
4568+
json_name: "requiredBytes"
4569+
}
4570+
field {
4571+
name: "limit_bytes"
4572+
number: 2
4573+
label: LABEL_OPTIONAL
4574+
type: TYPE_INT64
4575+
json_name: "limitBytes"
4576+
}
4577+
}
45084578
message_type {
45094579
name: "VolumeAssignment"
45104580
field {
@@ -5992,6 +6062,14 @@ file {
59926062
type_name: ".docker.swarmkit.v1.TopologyRequirement"
59936063
json_name: "AccessibilityRequirements"
59946064
}
6065+
field {
6066+
name: "capacity_range"
6067+
number: 7
6068+
label: LABEL_OPTIONAL
6069+
type: TYPE_MESSAGE
6070+
type_name: ".docker.swarmkit.v1.CapacityRange"
6071+
json_name: "capacityRange"
6072+
}
59956073
}
59966074
syntax: "proto3"
59976075
}
@@ -7305,11 +7383,12 @@ file {
73057383
json_name: "status"
73067384
}
73077385
field {
7308-
name: "volume_id"
7386+
name: "volume_info"
73097387
number: 5
73107388
label: LABEL_OPTIONAL
7311-
type: TYPE_STRING
7312-
json_name: "volumeId"
7389+
type: TYPE_MESSAGE
7390+
type_name: ".docker.swarmkit.v1.VolumeInfo"
7391+
json_name: "volumeInfo"
73137392
}
73147393
options {
73157394
70001 {

api/objects.pb.go

Lines changed: 141 additions & 131 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/objects.proto

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,7 @@ message Volume {
537537
// Status contains information about how the volume is currently being used.
538538
VolumeStatus status = 4 [(gogoproto.nullable) = false];
539539

540-
// VolumeID is the ID of the volume as reported by the CSI plugin.
541-
// Information about the volume is not cached in swarmkit's object store;
542-
// instead, it is retrieved on-demand as needed. If the VolumeID field is an
543-
// empty string, and the plugin advertises CREATE_DELETE_VOLUME capability,
544-
// then Swarmkit has not yet called CreateVolume.
545-
string volume_id = 5;
540+
// VolumeInfo contains information about the volume originating from the CSI
541+
// plugin
542+
VolumeInfo volume_info = 5;
546543
}

api/specs.pb.go

Lines changed: 218 additions & 156 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/specs.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,8 @@ message VolumeSpec {
549549
// VOLUME_ACCESSIBILITY_CONSTRAINTS, then Swarmkit will assume the entire
550550
// cluster is a valid target for the volume.
551551
TopologyRequirement AccessibilityRequirements = 6;
552+
553+
// CapacityRange is the capacity this volume should be created with. If nil,
554+
// the plugin will decide the capacity.
555+
CapacityRange capacity_range = 7;
552556
}

api/types.pb.go

Lines changed: 1083 additions & 395 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/types.proto

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,40 @@ message VolumeStatus {
12501250
repeated string published_nodes = 1;
12511251
}
12521252

1253+
// VolumeInfo contains information about the volume originating from the CSI
1254+
// plugin.
1255+
message VolumeInfo {
1256+
// CapacityBytes is the capacity of this volume in bytes. A value of 0
1257+
// indicates that the capcity is unknown.
1258+
int64 capacity_bytes = 1;
1259+
1260+
// VolumeContext includes fields that are opaque to Swarmkit.
1261+
map<string, string> volume_context = 2;
1262+
1263+
// VolumeID is the ID of the volume as reported by the CSI plugin.
1264+
// Information about the volume is not cached in swarmkit's object store;
1265+
// instead, it is retrieved on-demand as needed. If the VolumeID field is an
1266+
// empty string, and the plugin advertises CREATE_DELETE_VOLUME capability,
1267+
// then Swarmkit has not yet called CreateVolume.
1268+
string volume_id = 3;
1269+
1270+
// AccessibleTopology is the topology this volume is actually accessible
1271+
// from.
1272+
repeated Topology accessible_topology = 4;
1273+
}
1274+
1275+
// CapacityRange describes the minimum and maximum capacity a volume should be
1276+
// created with.
1277+
message CapacityRange {
1278+
// RequiredBytes specifies that a volume must be at least this big. The value
1279+
// of 0 indicates an unspecified minimum. Must not be negative.
1280+
int64 required_bytes = 1;
1281+
1282+
// LimitBytes specifies that a volume must not be bigger than this. The value
1283+
// of 0 indicates an unspecified maximum. Must not be negative.
1284+
int64 limit_bytes = 2;
1285+
}
1286+
12531287
// VolumeAssignment contains the information needed by a Node to use a CSI
12541288
// volume. This includes the information need to Stage and Publish the volume
12551289
// on the node, but never the full Volume object.

manager/volumes/convert.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package volumes
2+
3+
import (
4+
"github.com/container-storage-interface/spec/lib/go/csi"
5+
"github.com/docker/swarmkit/api"
6+
)
7+
8+
// convert.go contains functions for converting swarm objects into CSI requests
9+
// and back again.
10+
11+
// makeTopology converts a swarmkit topology into a CSI topology.
12+
func makeTopologyRequirement(t *api.TopologyRequirement) *csi.TopologyRequirement {
13+
return &csi.TopologyRequirement{
14+
Requisite: makeTopologies(t.Requisite),
15+
Preferred: makeTopologies(t.Preferred),
16+
}
17+
}
18+
19+
// makeTopologies converts a slice of swarmkit topologies into a slice of CSI
20+
// topologies.
21+
func makeTopologies(ts []*api.Topology) []*csi.Topology {
22+
if ts == nil {
23+
return nil
24+
}
25+
csiTops := make([]*csi.Topology, len(ts))
26+
for i, t := range ts {
27+
csiTops[i] = makeTopology(t)
28+
}
29+
30+
return csiTops
31+
}
32+
33+
// makeTopology converts a swarmkit topology into a CSI topology. These types
34+
// are essentially homologous, with the swarm type being copied verbatim from
35+
// the CSI type (for build reasons).
36+
func makeTopology(t *api.Topology) *csi.Topology {
37+
return &csi.Topology{
38+
Segments: t.Segments,
39+
}
40+
}
41+
42+
func makeAccessMode(am *api.VolumeAccessMode) *csi.VolumeCapability {
43+
var mode csi.VolumeCapability_AccessMode_Mode
44+
switch am.Scope {
45+
case api.VolumeScopeSingleNode:
46+
switch am.Sharing {
47+
case api.VolumeSharingNone, api.VolumeSharingOneWriter, api.VolumeSharingAll:
48+
mode = csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
49+
case api.VolumeSharingReadOnly:
50+
mode = csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY
51+
}
52+
case api.VolumeScopeMultiNode:
53+
switch am.Sharing {
54+
case api.VolumeSharingReadOnly:
55+
mode = csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY
56+
case api.VolumeSharingOneWriter:
57+
mode = csi.VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER
58+
case api.VolumeSharingAll:
59+
mode = csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER
60+
}
61+
}
62+
63+
return &csi.VolumeCapability{
64+
AccessMode: &csi.VolumeCapability_AccessMode{
65+
Mode: mode,
66+
},
67+
}
68+
}
69+
70+
// makeCapcityRange converts the swarmkit CapacityRange object to the
71+
// equivalent CSI object
72+
func makeCapacityRange(cr *api.CapacityRange) *csi.CapacityRange {
73+
if cr == nil {
74+
return nil
75+
}
76+
77+
return &csi.CapacityRange{
78+
RequiredBytes: cr.RequiredBytes,
79+
LimitBytes: cr.LimitBytes,
80+
}
81+
}
82+
83+
// unmakeTopologies transforms a CSI-type topology into the equivalent swarm
84+
// type. it is called "unmakeTopologies" because it performs the inverse of
85+
// "makeTopologies".
86+
func unmakeTopologies(topologies []*csi.Topology) []*api.Topology {
87+
if topologies == nil {
88+
return nil
89+
}
90+
swarmTopologies := make([]*api.Topology, len(topologies))
91+
for i, t := range topologies {
92+
swarmTopologies[i] = unmakeTopology(t)
93+
}
94+
return swarmTopologies
95+
}
96+
97+
// unmakeTopology transforms a CSI-type topology into the equivalent swarm
98+
// type.
99+
func unmakeTopology(topology *csi.Topology) *api.Topology {
100+
return &api.Topology{
101+
Segments: topology.Segments,
102+
}
103+
}
104+
105+
// makeVolumeInfo converts a csi.Volume object into a swarmkit VolumeInfo
106+
// object.
107+
func makeVolumeInfo(csiVolume *csi.Volume) *api.VolumeInfo {
108+
return &api.VolumeInfo{
109+
CapacityBytes: csiVolume.CapacityBytes,
110+
VolumeContext: csiVolume.VolumeContext,
111+
VolumeID: csiVolume.VolumeId,
112+
AccessibleTopology: unmakeTopologies(csiVolume.AccessibleTopology),
113+
}
114+
}

0 commit comments

Comments
 (0)