dotcloud/docker

View on GitHub
daemon/cluster/convert/volume.go

Summary

Maintainability
A
2 hrs
Test Coverage
package convert // import "github.com/docker/docker/daemon/cluster/convert"

import (
    volumetypes "github.com/docker/docker/api/types/volume"
    gogotypes "github.com/gogo/protobuf/types"
    swarmapi "github.com/moby/swarmkit/v2/api"
)

// VolumeFromGRPC converts a swarmkit api Volume object to a docker api Volume
// object
func VolumeFromGRPC(v *swarmapi.Volume) volumetypes.Volume {
    clusterVolumeSpec := volumetypes.ClusterVolumeSpec{
        Group:                     v.Spec.Group,
        AccessMode:                accessModeFromGRPC(v.Spec.AccessMode),
        AccessibilityRequirements: topologyRequirementFromGRPC(v.Spec.AccessibilityRequirements),
        CapacityRange:             capacityRangeFromGRPC(v.Spec.CapacityRange),
        Secrets:                   volumeSecretsFromGRPC(v.Spec.Secrets),
        Availability:              volumeAvailabilityFromGRPC(v.Spec.Availability),
    }

    clusterVolume := &volumetypes.ClusterVolume{
        ID:            v.ID,
        Spec:          clusterVolumeSpec,
        PublishStatus: volumePublishStatusFromGRPC(v.PublishStatus),
        Info:          volumeInfoFromGRPC(v.VolumeInfo),
    }

    clusterVolume.Version.Index = v.Meta.Version.Index
    clusterVolume.CreatedAt, _ = gogotypes.TimestampFromProto(v.Meta.CreatedAt)
    clusterVolume.UpdatedAt, _ = gogotypes.TimestampFromProto(v.Meta.UpdatedAt)

    return volumetypes.Volume{
        ClusterVolume: clusterVolume,
        CreatedAt:     clusterVolume.CreatedAt.String(),
        Driver:        v.Spec.Driver.Name,
        Labels:        v.Spec.Annotations.Labels,
        Name:          v.Spec.Annotations.Name,
        Options:       v.Spec.Driver.Options,
        Scope:         "global",
    }
}

func volumeSpecToGRPC(spec volumetypes.ClusterVolumeSpec) *swarmapi.VolumeSpec {
    swarmSpec := &swarmapi.VolumeSpec{
        Group: spec.Group,
    }

    if spec.AccessMode != nil {
        swarmSpec.AccessMode = &swarmapi.VolumeAccessMode{}

        switch spec.AccessMode.Scope {
        case volumetypes.ScopeSingleNode:
            swarmSpec.AccessMode.Scope = swarmapi.VolumeScopeSingleNode
        case volumetypes.ScopeMultiNode:
            swarmSpec.AccessMode.Scope = swarmapi.VolumeScopeMultiNode
        }

        switch spec.AccessMode.Sharing {
        case volumetypes.SharingNone:
            swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingNone
        case volumetypes.SharingReadOnly:
            swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingReadOnly
        case volumetypes.SharingOneWriter:
            swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingOneWriter
        case volumetypes.SharingAll:
            swarmSpec.AccessMode.Sharing = swarmapi.VolumeSharingAll
        }

        if spec.AccessMode.BlockVolume != nil {
            swarmSpec.AccessMode.AccessType = &swarmapi.VolumeAccessMode_Block{
                Block: &swarmapi.VolumeAccessMode_BlockVolume{},
            }
        }
        if spec.AccessMode.MountVolume != nil {
            swarmSpec.AccessMode.AccessType = &swarmapi.VolumeAccessMode_Mount{
                Mount: &swarmapi.VolumeAccessMode_MountVolume{
                    FsType:     spec.AccessMode.MountVolume.FsType,
                    MountFlags: spec.AccessMode.MountVolume.MountFlags,
                },
            }
        }
    }

    for _, secret := range spec.Secrets {
        swarmSpec.Secrets = append(swarmSpec.Secrets, &swarmapi.VolumeSecret{
            Key:    secret.Key,
            Secret: secret.Secret,
        })
    }

    if spec.AccessibilityRequirements != nil {
        swarmSpec.AccessibilityRequirements = &swarmapi.TopologyRequirement{}

        for _, top := range spec.AccessibilityRequirements.Requisite {
            swarmSpec.AccessibilityRequirements.Requisite = append(
                swarmSpec.AccessibilityRequirements.Requisite,
                &swarmapi.Topology{
                    Segments: top.Segments,
                },
            )
        }

        for _, top := range spec.AccessibilityRequirements.Preferred {
            swarmSpec.AccessibilityRequirements.Preferred = append(
                swarmSpec.AccessibilityRequirements.Preferred,
                &swarmapi.Topology{
                    Segments: top.Segments,
                },
            )
        }
    }

    if spec.CapacityRange != nil {
        swarmSpec.CapacityRange = &swarmapi.CapacityRange{
            RequiredBytes: spec.CapacityRange.RequiredBytes,
            LimitBytes:    spec.CapacityRange.LimitBytes,
        }
    }

    // availability is not a pointer, it is a value. if the user does not
    // specify an availability, it will be inferred as the 0-value, which is
    // "active".
    switch spec.Availability {
    case volumetypes.AvailabilityActive:
        swarmSpec.Availability = swarmapi.VolumeAvailabilityActive
    case volumetypes.AvailabilityPause:
        swarmSpec.Availability = swarmapi.VolumeAvailabilityPause
    case volumetypes.AvailabilityDrain:
        swarmSpec.Availability = swarmapi.VolumeAvailabilityDrain
    }

    return swarmSpec
}

// VolumeCreateToGRPC takes a VolumeCreateBody and outputs the matching
// swarmapi VolumeSpec.
func VolumeCreateToGRPC(volume *volumetypes.CreateOptions) *swarmapi.VolumeSpec {
    var swarmSpec *swarmapi.VolumeSpec
    if volume != nil && volume.ClusterVolumeSpec != nil {
        swarmSpec = volumeSpecToGRPC(*volume.ClusterVolumeSpec)
    } else {
        swarmSpec = &swarmapi.VolumeSpec{}
    }

    swarmSpec.Annotations = swarmapi.Annotations{
        Name:   volume.Name,
        Labels: volume.Labels,
    }

    swarmSpec.Driver = &swarmapi.Driver{
        Name:    volume.Driver,
        Options: volume.DriverOpts,
    }

    return swarmSpec
}

func volumeInfoFromGRPC(info *swarmapi.VolumeInfo) *volumetypes.Info {
    if info == nil {
        return nil
    }

    var accessibleTopology []volumetypes.Topology
    if info.AccessibleTopology != nil {
        accessibleTopology = make([]volumetypes.Topology, len(info.AccessibleTopology))
        for i, top := range info.AccessibleTopology {
            accessibleTopology[i] = topologyFromGRPC(top)
        }
    }

    return &volumetypes.Info{
        CapacityBytes:      info.CapacityBytes,
        VolumeContext:      info.VolumeContext,
        VolumeID:           info.VolumeID,
        AccessibleTopology: accessibleTopology,
    }
}

func volumePublishStatusFromGRPC(publishStatus []*swarmapi.VolumePublishStatus) []*volumetypes.PublishStatus {
    if publishStatus == nil {
        return nil
    }

    vps := make([]*volumetypes.PublishStatus, len(publishStatus))
    for i, status := range publishStatus {
        var state volumetypes.PublishState
        switch status.State {
        case swarmapi.VolumePublishStatus_PENDING_PUBLISH:
            state = volumetypes.StatePending
        case swarmapi.VolumePublishStatus_PUBLISHED:
            state = volumetypes.StatePublished
        case swarmapi.VolumePublishStatus_PENDING_NODE_UNPUBLISH:
            state = volumetypes.StatePendingNodeUnpublish
        case swarmapi.VolumePublishStatus_PENDING_UNPUBLISH:
            state = volumetypes.StatePendingUnpublish
        }

        vps[i] = &volumetypes.PublishStatus{
            NodeID:         status.NodeID,
            State:          state,
            PublishContext: status.PublishContext,
        }
    }

    return vps
}

func accessModeFromGRPC(accessMode *swarmapi.VolumeAccessMode) *volumetypes.AccessMode {
    if accessMode == nil {
        return nil
    }

    convertedAccessMode := &volumetypes.AccessMode{}

    switch accessMode.Scope {
    case swarmapi.VolumeScopeSingleNode:
        convertedAccessMode.Scope = volumetypes.ScopeSingleNode
    case swarmapi.VolumeScopeMultiNode:
        convertedAccessMode.Scope = volumetypes.ScopeMultiNode
    }

    switch accessMode.Sharing {
    case swarmapi.VolumeSharingNone:
        convertedAccessMode.Sharing = volumetypes.SharingNone
    case swarmapi.VolumeSharingReadOnly:
        convertedAccessMode.Sharing = volumetypes.SharingReadOnly
    case swarmapi.VolumeSharingOneWriter:
        convertedAccessMode.Sharing = volumetypes.SharingOneWriter
    case swarmapi.VolumeSharingAll:
        convertedAccessMode.Sharing = volumetypes.SharingAll
    }

    if block := accessMode.GetBlock(); block != nil {
        convertedAccessMode.BlockVolume = &volumetypes.TypeBlock{}
    }
    if mount := accessMode.GetMount(); mount != nil {
        convertedAccessMode.MountVolume = &volumetypes.TypeMount{
            FsType:     mount.FsType,
            MountFlags: mount.MountFlags,
        }
    }

    return convertedAccessMode
}

func volumeSecretsFromGRPC(secrets []*swarmapi.VolumeSecret) []volumetypes.Secret {
    if secrets == nil {
        return nil
    }
    convertedSecrets := make([]volumetypes.Secret, len(secrets))
    for i, secret := range secrets {
        convertedSecrets[i] = volumetypes.Secret{
            Key:    secret.Key,
            Secret: secret.Secret,
        }
    }
    return convertedSecrets
}

func topologyRequirementFromGRPC(top *swarmapi.TopologyRequirement) *volumetypes.TopologyRequirement {
    if top == nil {
        return nil
    }

    convertedTop := &volumetypes.TopologyRequirement{}
    if top.Requisite != nil {
        convertedTop.Requisite = make([]volumetypes.Topology, len(top.Requisite))
        for i, req := range top.Requisite {
            convertedTop.Requisite[i] = topologyFromGRPC(req)
        }
    }

    if top.Preferred != nil {
        convertedTop.Preferred = make([]volumetypes.Topology, len(top.Preferred))
        for i, pref := range top.Preferred {
            convertedTop.Preferred[i] = topologyFromGRPC(pref)
        }
    }

    return convertedTop
}

func topologyFromGRPC(top *swarmapi.Topology) volumetypes.Topology {
    if top == nil {
        return volumetypes.Topology{}
    }
    return volumetypes.Topology{
        Segments: top.Segments,
    }
}

func capacityRangeFromGRPC(capacity *swarmapi.CapacityRange) *volumetypes.CapacityRange {
    if capacity == nil {
        return nil
    }

    return &volumetypes.CapacityRange{
        RequiredBytes: capacity.RequiredBytes,
        LimitBytes:    capacity.LimitBytes,
    }
}

func volumeAvailabilityFromGRPC(availability swarmapi.VolumeSpec_VolumeAvailability) volumetypes.Availability {
    switch availability {
    case swarmapi.VolumeAvailabilityActive:
        return volumetypes.AvailabilityActive
    case swarmapi.VolumeAvailabilityPause:
        return volumetypes.AvailabilityPause
    }
    return volumetypes.AvailabilityDrain
}