Portworx Volume Driver in Kubernetes

- Add a new type PortworxVolumeSource
- Implement the kubernetes volume plugin for Portworx Volumes under pkg/volume/portworx
- The Portworx Volume Driver uses the libopenstorage/openstorage specifications and apis for volume operations.

Changes for k8s configuration and examples for portworx volumes.

- Add PortworxVolume hooks in kubectl, kube-controller-manager and validation.
- Add a README for PortworxVolume usage as PVs, PVCs and StorageClass.
- Add example spec files

Handle code review comments.

- Modified READMEs to incorporate to suggestions.
- Add a test for ReadWriteMany access mode.
- Use util.UnmountPath in TearDown.
- Add ReadOnly flag to PortworxVolumeSource
- Use hostname:port instead of unix sockets
- Delete the mount dir in TearDown.
- Fix link issue in persistentvolumes README
- In unit test check for mountpath after Setup is done.
- Add PVC Claim Name as a Portworx Volume Label

Generated code and documentation.
- Updated swagger spec
- Updated api-reference docs
- Updated generated code under pkg/api/v1

Godeps update for Portworx Volume Driver
- Adds github.com/libopenstorage/openstorage
- Adds go.pedge.io/pb/go/google/protobuf
- Updates Godep Licenses
This commit is contained in:
Aditya Dani
2016-12-19 23:17:11 +00:00
parent dba0af3675
commit 28df55fc31
84 changed files with 14212 additions and 3090 deletions

View File

@@ -0,0 +1,41 @@
## Volume Drivers
Volume drivers implement the [Volume Plugin Interface](https://docs.docker.com/engine/extend/plugins_volume/).
This provides an interface to register a volume driver and advertise the driver to Docker. Registering a driver with this volume interface will cause Docker to be able to communicate with the driver to create and assign volumes to a container.
A volume spec is needed to create a volume. A volume spec looks like:
```
// VolumeSpec has the properties needed to create a volume.
type VolumeSpec struct {
// Ephemeral storage
Ephemeral bool
// Thin provisioned volume size in bytes
Size uint64
// Format disk with this FileSystem
Format Filesystem
// BlockSize for file system
BlockSize int
// HA Level specifies the number of nodes that are
// allowed to fail, and yet data is availabel.
// A value of 0 implies that data is not erasure coded,
// a failure of a node will lead to data loss.
HALevel int
// This disk's CoS
Cos VolumeCos
// Perform dedupe on this disk
Dedupe bool
// SnapshotInterval in minutes, set to 0 to disable Snapshots
SnapshotInterval int
// Volume configuration labels
ConfigLabels Labels
}
```
Various volume driver implementations can be found in the `drivers` directory.
### Block Drivers
Block drivers operate at the block layer. They provide raw volumes formatted with a user specified filesystem. This volume is then mounted into the container at a path specified using the `docker run -v` option.
### File Drivers
File drivers operate at the filesystem layer.

View File

@@ -0,0 +1,171 @@
package volume
import (
"errors"
"github.com/libopenstorage/openstorage/api"
)
var (
ErrAlreadyShutdown = errors.New("VolumeDriverProvider already shutdown")
ErrExist = errors.New("Driver already exists")
ErrDriverNotFound = errors.New("Driver implementation not found")
ErrDriverInitializing = errors.New("Driver is initializing")
ErrEnoEnt = errors.New("Volume does not exist.")
ErrEnomem = errors.New("Out of memory.")
ErrEinval = errors.New("Invalid argument")
ErrVolDetached = errors.New("Volume is detached")
ErrVolAttached = errors.New("Volume is attached")
ErrVolAttachedOnRemoteNode = errors.New("Volume is attached on another node")
ErrVolAttachedScale = errors.New("Volume is attached but can be scaled")
ErrVolHasSnaps = errors.New("Volume has snapshots associated")
ErrNotSupported = errors.New("Operation not supported")
)
// Constants used by the VolumeDriver
const (
APIVersion = "v1"
PluginAPIBase = "/run/docker/plugins/"
DriverAPIBase = "/var/lib/osd/driver/"
MountBase = "/var/lib/osd/mounts/"
VolumeBase = "/var/lib/osd/"
)
type Store interface {
// Lock volume specified by volumeID.
Lock(volumeID string) (interface{}, error)
// Lock volume with token obtained from call to Lock.
Unlock(token interface{}) error
// CreateVol returns error if volume with the same ID already existe.
CreateVol(vol *api.Volume) error
// GetVol from volumeID.
GetVol(volumeID string) (*api.Volume, error)
// UpdateVol with vol
UpdateVol(vol *api.Volume) error
// DeleteVol. Returns error if volume does not exist.
DeleteVol(volumeID string) error
}
// VolumeDriver is the main interface to be implemented by any storage driver.
// Every driver must at minimum implement the ProtoDriver sub interface.
type VolumeDriver interface {
IODriver
ProtoDriver
BlockDriver
Enumerator
}
// IODriver interfaces applicable to object store interfaces.
type IODriver interface {
// Read sz bytes from specified volume at specified offset.
// Return number of bytes read and error.
Read(volumeID string, buf []byte, sz uint64, offset int64) (int64, error)
// Write sz bytes from specified volume at specified offset.
// Return number of bytes written and error.
Write(volumeID string, buf []byte, sz uint64, offset int64) (int64, error)
// Flush writes to stable storage.
// Return error.
Flush(volumeID string) error
}
type SnapshotDriver interface {
// Snapshot create volume snapshot.
// Errors ErrEnoEnt may be returned
Snapshot(volumeID string, readonly bool, locator *api.VolumeLocator) (string, error)
}
// ProtoDriver must be implemented by all volume drivers. It specifies the
// most basic functionality, such as creating and deleting volumes.
type ProtoDriver interface {
SnapshotDriver
// Name returns the name of the driver.
Name() string
// Type of this driver
Type() api.DriverType
// Create a new Vol for the specific volume spec.
// It returns a system generated VolumeID that uniquely identifies the volume
Create(locator *api.VolumeLocator, Source *api.Source, spec *api.VolumeSpec) (string, error)
// Delete volume.
// Errors ErrEnoEnt, ErrVolHasSnaps may be returned.
Delete(volumeID string) error
// Mount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
Mount(volumeID string, mountPath string) error
// MountedAt return volume mounted at specified mountpath.
MountedAt(mountPath string) string
// Unmount volume at specified path
// Errors ErrEnoEnt, ErrVolDetached may be returned.
Unmount(volumeID string, mountPath string) error
// Update not all fields of the spec are supported, ErrNotSupported will be thrown for unsupported
// updates.
Set(volumeID string, locator *api.VolumeLocator, spec *api.VolumeSpec) error
// Stats for specified volume.
// cumulative stats are /proc/diskstats style stats.
// nonCumulative stats are stats for specific duration.
// Errors ErrEnoEnt may be returned
Stats(volumeID string, cumulative bool) (*api.Stats, error)
// Alerts on this volume.
// Errors ErrEnoEnt may be returned
Alerts(volumeID string) (*api.Alerts, error)
// GetActiveRequests get active requests
GetActiveRequests() (*api.ActiveRequests, error)
// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
Status() [][2]string
// Shutdown and cleanup.
Shutdown()
}
// Enumerator provides a set of interfaces to get details on a set of volumes.
type Enumerator interface {
// Inspect specified volumes.
// Returns slice of volumes that were found.
Inspect(volumeIDs []string) ([]*api.Volume, error)
// Enumerate volumes that map to the volumeLocator. Locator fields may be regexp.
// If locator fields are left blank, this will return all volumes.
Enumerate(locator *api.VolumeLocator, labels map[string]string) ([]*api.Volume, error)
// Enumerate snaps for specified volumes
SnapEnumerate(volID []string, snapLabels map[string]string) ([]*api.Volume, error)
}
type StoreEnumerator interface {
Store
Enumerator
}
// BlockDriver needs to be implemented by block volume drivers. Filesystem volume
// drivers can ignore this interface and include the builtin DefaultBlockDriver.
type BlockDriver interface {
// Attach map device to the host.
// On success the devicePath specifies location where the device is exported
// Errors ErrEnoEnt, ErrVolAttached may be returned.
Attach(volumeID string) (string, error)
// Detach device from the host.
// Errors ErrEnoEnt, ErrVolDetached may be returned.
Detach(volumeID string) error
}
// VolumeDriverProvider provides VolumeDrivers.
type VolumeDriverProvider interface {
// Get gets the VolumeDriver for the given name.
// If a VolumeDriver was not created for the given name, the error ErrDriverNotFound is returned.
Get(name string) (VolumeDriver, error)
// Shutdown shuts down all volume drivers.
Shutdown() error
}
// VolumeDriverRegistry registers VolumeDrivers.
type VolumeDriverRegistry interface {
VolumeDriverProvider
// New creates the VolumeDriver for the given name.
// If a VolumeDriver was already created for the given name, the error ErrExist is returned.
Register(name string, params map[string]string) error
// Add inserts a new VolumeDriver provider with a well known name.
Add(name string, init func(map[string]string) (VolumeDriver, error)) error
}
// VolumeDriverRegistry constructs a new VolumeDriverRegistry.
func NewVolumeDriverRegistry(nameToInitFunc map[string]func(map[string]string) (VolumeDriver, error)) VolumeDriverRegistry {
return newVolumeDriverRegistry(nameToInitFunc)
}

View File

@@ -0,0 +1,71 @@
package volume
import "sync"
type volumeDriverRegistry struct {
nameToInitFunc map[string]func(map[string]string) (VolumeDriver, error)
nameToVolumeDriver map[string]VolumeDriver
lock *sync.RWMutex
isShutdown bool
}
func newVolumeDriverRegistry(nameToInitFunc map[string]func(map[string]string) (VolumeDriver, error)) *volumeDriverRegistry {
return &volumeDriverRegistry{
nameToInitFunc,
make(map[string]VolumeDriver),
&sync.RWMutex{},
false,
}
}
func (v *volumeDriverRegistry) Get(name string) (VolumeDriver, error) {
v.lock.RLock()
defer v.lock.RUnlock()
if v.isShutdown {
return nil, ErrAlreadyShutdown
}
volumeDriver, ok := v.nameToVolumeDriver[name]
if !ok {
return nil, ErrDriverNotFound
}
return volumeDriver, nil
}
func (v *volumeDriverRegistry) Add(name string, init func(map[string]string) (VolumeDriver, error)) error {
v.nameToInitFunc[name] = init
return nil
}
func (v *volumeDriverRegistry) Register(name string, params map[string]string) error {
initFunc, ok := v.nameToInitFunc[name]
if !ok {
return ErrNotSupported
}
v.lock.Lock()
defer v.lock.Unlock()
if v.isShutdown {
return ErrAlreadyShutdown
}
if _, ok := v.nameToVolumeDriver[name]; ok {
return ErrExist
}
volumeDriver, err := initFunc(params)
if err != nil {
return err
}
v.nameToVolumeDriver[name] = volumeDriver
return nil
}
func (v *volumeDriverRegistry) Shutdown() error {
v.lock.Lock()
if v.isShutdown {
return ErrAlreadyShutdown
}
for _, volumeDriver := range v.nameToVolumeDriver {
volumeDriver.Shutdown()
}
v.isShutdown = true
return nil
}

View File

@@ -0,0 +1,45 @@
package volume
import (
"github.com/libopenstorage/openstorage/api"
)
var (
// BlockNotSupported is a default (null) block driver implementation. This can be
// used by drivers that do not want to (or care about) implementing the attach,
// format and detach interfaces.
BlockNotSupported = &blockNotSupported{}
SnapshotNotSupported = &snapshotNotSupported{}
IONotSupported = &ioNotSupported{}
)
type blockNotSupported struct{}
func (b *blockNotSupported) Attach(volumeID string) (string, error) {
return "", ErrNotSupported
}
func (b *blockNotSupported) Detach(volumeID string) error {
return ErrNotSupported
}
type snapshotNotSupported struct{}
func (s *snapshotNotSupported) Snapshot(volumeID string, readonly bool, locator *api.VolumeLocator) (string, error) {
return "", ErrNotSupported
}
type ioNotSupported struct{}
func (i *ioNotSupported) Read(volumeID string, buffer []byte, size uint64, offset int64) (int64, error) {
return 0, ErrNotSupported
}
func (i *ioNotSupported) Write(volumeID string, buffer []byte, size uint64, offset int64) (int64, error) {
return 0, ErrNotSupported
}
func (i *ioNotSupported) Flush(volumeID string) error {
return ErrNotSupported
}