github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/cluster/convert/volume.go (about) 1 package convert // import "github.com/docker/docker/daemon/cluster/convert" 2 3 import ( 4 volumetypes "github.com/docker/docker/api/types/volume" 5 gogotypes "github.com/gogo/protobuf/types" 6 swarmapi "github.com/moby/swarmkit/v2/api" 7 ) 8 9 // VolumeFromGRPC converts a swarmkit api Volume object to a docker api Volume 10 // object 11 func VolumeFromGRPC(v *swarmapi.Volume) volumetypes.Volume { 12 clusterVolumeSpec := volumetypes.ClusterVolumeSpec{ 13 Group: v.Spec.Group, 14 AccessMode: accessModeFromGRPC(v.Spec.AccessMode), 15 AccessibilityRequirements: topologyRequirementFromGRPC(v.Spec.AccessibilityRequirements), 16 CapacityRange: capacityRangeFromGRPC(v.Spec.CapacityRange), 17 Secrets: volumeSecretsFromGRPC(v.Spec.Secrets), 18 Availability: volumeAvailabilityFromGRPC(v.Spec.Availability), 19 } 20 21 clusterVolume := &volumetypes.ClusterVolume{ 22 ID: v.ID, 23 Spec: clusterVolumeSpec, 24 PublishStatus: volumePublishStatusFromGRPC(v.PublishStatus), 25 Info: volumeInfoFromGRPC(v.VolumeInfo), 26 } 27 28 clusterVolume.Version.Index = v.Meta.Version.Index 29 clusterVolume.CreatedAt, _ = gogotypes.TimestampFromProto(v.Meta.CreatedAt) 30 clusterVolume.UpdatedAt, _ = gogotypes.TimestampFromProto(v.Meta.UpdatedAt) 31 32 return volumetypes.Volume{ 33 ClusterVolume: clusterVolume, 34 CreatedAt: clusterVolume.CreatedAt.String(), 35 Driver: v.Spec.Driver.Name, 36 Labels: v.Spec.Annotations.Labels, 37 Name: v.Spec.Annotations.Name, 38 Options: v.Spec.Driver.Options, 39 Scope: "global", 40 } 41 } 42 43 func volumeSpecToGRPC(spec volumetypes.ClusterVolumeSpec) *swarmapi.VolumeSpec { 44 swarmSpec := &swarmapi.VolumeSpec{ 45 Group: spec.Group, 46 } 47 48 if spec.AccessMode != nil { 49 swarmSpec.AccessMode = &swarmapi.VolumeAccessMode{} 50 51 switch spec.AccessMode.Scope { 52 case volumetypes.ScopeSingleNode: 53 swarmSpec.AccessMode.Scope = swarmapi.VolumeScopeSingleNode 54 case volumetypes.ScopeMultiNode: 55 swarmSpec.AccessMode.Scope = swarmapi.VolumeScopeMultiNode 56 } 57 58 switch spec.AccessMode.Sharing { 59 case volumetypes.SharingNone: 60 swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingNone 61 case volumetypes.SharingReadOnly: 62 swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingReadOnly 63 case volumetypes.SharingOneWriter: 64 swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingOneWriter 65 case volumetypes.SharingAll: 66 swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingAll 67 } 68 69 if spec.AccessMode.BlockVolume != nil { 70 swarmSpec.AccessMode.AccessType = &swarmapi.VolumeAccessMode_Block{ 71 Block: &swarmapi.VolumeAccessMode_BlockVolume{}, 72 } 73 } 74 if spec.AccessMode.MountVolume != nil { 75 swarmSpec.AccessMode.AccessType = &swarmapi.VolumeAccessMode_Mount{ 76 Mount: &swarmapi.VolumeAccessMode_MountVolume{ 77 FsType: spec.AccessMode.MountVolume.FsType, 78 MountFlags: spec.AccessMode.MountVolume.MountFlags, 79 }, 80 } 81 } 82 } 83 84 for _, secret := range spec.Secrets { 85 swarmSpec.Secrets = append(swarmSpec.Secrets, &swarmapi.VolumeSecret{ 86 Key: secret.Key, 87 Secret: secret.Secret, 88 }) 89 } 90 91 if spec.AccessibilityRequirements != nil { 92 swarmSpec.AccessibilityRequirements = &swarmapi.TopologyRequirement{} 93 94 for _, top := range spec.AccessibilityRequirements.Requisite { 95 swarmSpec.AccessibilityRequirements.Requisite = append( 96 swarmSpec.AccessibilityRequirements.Requisite, 97 &swarmapi.Topology{ 98 Segments: top.Segments, 99 }, 100 ) 101 } 102 103 for _, top := range spec.AccessibilityRequirements.Preferred { 104 swarmSpec.AccessibilityRequirements.Preferred = append( 105 swarmSpec.AccessibilityRequirements.Preferred, 106 &swarmapi.Topology{ 107 Segments: top.Segments, 108 }, 109 ) 110 } 111 } 112 113 if spec.CapacityRange != nil { 114 swarmSpec.CapacityRange = &swarmapi.CapacityRange{ 115 RequiredBytes: spec.CapacityRange.RequiredBytes, 116 LimitBytes: spec.CapacityRange.LimitBytes, 117 } 118 } 119 120 // availability is not a pointer, it is a value. if the user does not 121 // specify an availability, it will be inferred as the 0-value, which is 122 // "active". 123 switch spec.Availability { 124 case volumetypes.AvailabilityActive: 125 swarmSpec.Availability = swarmapi.VolumeAvailabilityActive 126 case volumetypes.AvailabilityPause: 127 swarmSpec.Availability = swarmapi.VolumeAvailabilityPause 128 case volumetypes.AvailabilityDrain: 129 swarmSpec.Availability = swarmapi.VolumeAvailabilityDrain 130 } 131 132 return swarmSpec 133 } 134 135 // VolumeCreateToGRPC takes a VolumeCreateBody and outputs the matching 136 // swarmapi VolumeSpec. 137 func VolumeCreateToGRPC(volume *volumetypes.CreateOptions) *swarmapi.VolumeSpec { 138 var swarmSpec *swarmapi.VolumeSpec 139 if volume != nil && volume.ClusterVolumeSpec != nil { 140 swarmSpec = volumeSpecToGRPC(*volume.ClusterVolumeSpec) 141 } else { 142 swarmSpec = &swarmapi.VolumeSpec{} 143 } 144 145 swarmSpec.Annotations = swarmapi.Annotations{ 146 Name: volume.Name, 147 Labels: volume.Labels, 148 } 149 150 swarmSpec.Driver = &swarmapi.Driver{ 151 Name: volume.Driver, 152 Options: volume.DriverOpts, 153 } 154 155 return swarmSpec 156 } 157 158 func volumeInfoFromGRPC(info *swarmapi.VolumeInfo) *volumetypes.Info { 159 if info == nil { 160 return nil 161 } 162 163 var accessibleTopology []volumetypes.Topology 164 if info.AccessibleTopology != nil { 165 accessibleTopology = make([]volumetypes.Topology, len(info.AccessibleTopology)) 166 for i, top := range info.AccessibleTopology { 167 accessibleTopology[i] = topologyFromGRPC(top) 168 } 169 } 170 171 return &volumetypes.Info{ 172 CapacityBytes: info.CapacityBytes, 173 VolumeContext: info.VolumeContext, 174 VolumeID: info.VolumeID, 175 AccessibleTopology: accessibleTopology, 176 } 177 } 178 179 func volumePublishStatusFromGRPC(publishStatus []*swarmapi.VolumePublishStatus) []*volumetypes.PublishStatus { 180 if publishStatus == nil { 181 return nil 182 } 183 184 vps := make([]*volumetypes.PublishStatus, len(publishStatus)) 185 for i, status := range publishStatus { 186 var state volumetypes.PublishState 187 switch status.State { 188 case swarmapi.VolumePublishStatus_PENDING_PUBLISH: 189 state = volumetypes.StatePending 190 case swarmapi.VolumePublishStatus_PUBLISHED: 191 state = volumetypes.StatePublished 192 case swarmapi.VolumePublishStatus_PENDING_NODE_UNPUBLISH: 193 state = volumetypes.StatePendingNodeUnpublish 194 case swarmapi.VolumePublishStatus_PENDING_UNPUBLISH: 195 state = volumetypes.StatePendingUnpublish 196 } 197 198 vps[i] = &volumetypes.PublishStatus{ 199 NodeID: status.NodeID, 200 State: state, 201 PublishContext: status.PublishContext, 202 } 203 } 204 205 return vps 206 } 207 208 func accessModeFromGRPC(accessMode *swarmapi.VolumeAccessMode) *volumetypes.AccessMode { 209 if accessMode == nil { 210 return nil 211 } 212 213 convertedAccessMode := &volumetypes.AccessMode{} 214 215 switch accessMode.Scope { 216 case swarmapi.VolumeScopeSingleNode: 217 convertedAccessMode.Scope = volumetypes.ScopeSingleNode 218 case swarmapi.VolumeScopeMultiNode: 219 convertedAccessMode.Scope = volumetypes.ScopeMultiNode 220 } 221 222 switch accessMode.Sharing { 223 case swarmapi.VolumeSharingNone: 224 convertedAccessMode.Sharing = volumetypes.SharingNone 225 case swarmapi.VolumeSharingReadOnly: 226 convertedAccessMode.Sharing = volumetypes.SharingReadOnly 227 case swarmapi.VolumeSharingOneWriter: 228 convertedAccessMode.Sharing = volumetypes.SharingOneWriter 229 case swarmapi.VolumeSharingAll: 230 convertedAccessMode.Sharing = volumetypes.SharingAll 231 } 232 233 if block := accessMode.GetBlock(); block != nil { 234 convertedAccessMode.BlockVolume = &volumetypes.TypeBlock{} 235 } 236 if mount := accessMode.GetMount(); mount != nil { 237 convertedAccessMode.MountVolume = &volumetypes.TypeMount{ 238 FsType: mount.FsType, 239 MountFlags: mount.MountFlags, 240 } 241 } 242 243 return convertedAccessMode 244 } 245 246 func volumeSecretsFromGRPC(secrets []*swarmapi.VolumeSecret) []volumetypes.Secret { 247 if secrets == nil { 248 return nil 249 } 250 convertedSecrets := make([]volumetypes.Secret, len(secrets)) 251 for i, secret := range secrets { 252 convertedSecrets[i] = volumetypes.Secret{ 253 Key: secret.Key, 254 Secret: secret.Secret, 255 } 256 } 257 return convertedSecrets 258 } 259 260 func topologyRequirementFromGRPC(top *swarmapi.TopologyRequirement) *volumetypes.TopologyRequirement { 261 if top == nil { 262 return nil 263 } 264 265 convertedTop := &volumetypes.TopologyRequirement{} 266 if top.Requisite != nil { 267 convertedTop.Requisite = make([]volumetypes.Topology, len(top.Requisite)) 268 for i, req := range top.Requisite { 269 convertedTop.Requisite[i] = topologyFromGRPC(req) 270 } 271 } 272 273 if top.Preferred != nil { 274 convertedTop.Preferred = make([]volumetypes.Topology, len(top.Preferred)) 275 for i, pref := range top.Preferred { 276 convertedTop.Preferred[i] = topologyFromGRPC(pref) 277 } 278 } 279 280 return convertedTop 281 } 282 283 func topologyFromGRPC(top *swarmapi.Topology) volumetypes.Topology { 284 if top == nil { 285 return volumetypes.Topology{} 286 } 287 return volumetypes.Topology{ 288 Segments: top.Segments, 289 } 290 } 291 292 func capacityRangeFromGRPC(capacity *swarmapi.CapacityRange) *volumetypes.CapacityRange { 293 if capacity == nil { 294 return nil 295 } 296 297 return &volumetypes.CapacityRange{ 298 RequiredBytes: capacity.RequiredBytes, 299 LimitBytes: capacity.LimitBytes, 300 } 301 } 302 303 func volumeAvailabilityFromGRPC(availability swarmapi.VolumeSpec_VolumeAvailability) volumetypes.Availability { 304 switch availability { 305 case swarmapi.VolumeAvailabilityActive: 306 return volumetypes.AvailabilityActive 307 case swarmapi.VolumeAvailabilityPause: 308 return volumetypes.AvailabilityPause 309 } 310 return volumetypes.AvailabilityDrain 311 }