forked from Ivasoft/objectivefs-docker-volume
Initial commit.
This commit is contained in:
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# ObjectiveFS Docker Volume Driver
|
||||
|
||||
This is a Docker Volume Driver which uses [ObjectiveFS](https://objectivefs.com/) to provide persistent scalable storage to Docker containers.
|
||||
|
||||
## Usage
|
||||
|
||||
See [ObjectiveFS Docker Volume Plugin](https://objectivefs.com/howto/docker-plugin-objectivefs)
|
||||
197
main.go
Normal file
197
main.go
Normal file
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2020, Objective Security Corporation
|
||||
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/docker/go-plugins-helpers/volume"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ofsVolume struct {
|
||||
volume *volume.Volume
|
||||
fs string
|
||||
opts string
|
||||
env []string
|
||||
use map[string]bool
|
||||
mounted bool
|
||||
asap bool
|
||||
}
|
||||
|
||||
type ofsDriver struct {
|
||||
sync.RWMutex
|
||||
volumes map[string]*ofsVolume
|
||||
}
|
||||
|
||||
var version = "1.0"
|
||||
|
||||
func (d ofsDriver) Create(r *volume.CreateRequest) error {
|
||||
log.Printf("Create ObjectiveFS Volume '%s'", r.Name)
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if _, ok := d.volumes[r.Name]; ok {
|
||||
return fmt.Errorf("volume '%s' already exists", r.Name)
|
||||
}
|
||||
v := &ofsVolume{}
|
||||
v.volume = &volume.Volume{Name: r.Name, Mountpoint: filepath.Join(volume.DefaultDockerRootDirectory, "objectivefs", r.Name), CreatedAt: time.Now().Format(time.RFC3339Nano)}
|
||||
v.use = make(map[string]bool)
|
||||
v.opts = "auto"
|
||||
for key, val := range r.Options {
|
||||
switch key {
|
||||
case "fs":
|
||||
v.fs = val
|
||||
case "options", "ptions":
|
||||
v.opts = v.opts + "," + val
|
||||
case "asap":
|
||||
v.asap = true
|
||||
default:
|
||||
v.env = append(v.env, key+"="+val)
|
||||
}
|
||||
}
|
||||
d.volumes[r.Name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) List() (*volume.ListResponse, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
var vs []*volume.Volume
|
||||
for _, v := range d.volumes {
|
||||
vs = append(vs, v.volume)
|
||||
}
|
||||
return &volume.ListResponse{Volumes: vs}, nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Get(r *volume.GetRequest) (*volume.GetResponse, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
v, ok := d.volumes[r.Name]
|
||||
if !ok {
|
||||
return &volume.GetResponse{}, fmt.Errorf("volume '%s' not found", r.Name)
|
||||
}
|
||||
return &volume.GetResponse{Volume: v.volume}, nil
|
||||
}
|
||||
|
||||
func umount(v *ofsVolume) error {
|
||||
log.Printf("Unmount ObjectiveFS Volume '%s'", v.volume.Name)
|
||||
if !v.mounted {
|
||||
return nil
|
||||
}
|
||||
if err := exec.Command("umount", v.volume.Mountpoint).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(v.volume.Mountpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
v.mounted = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Remove(r *volume.RemoveRequest) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
v, ok := d.volumes[r.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("volume '%s' not found", r.Name)
|
||||
}
|
||||
if len(v.use) != 0 {
|
||||
return fmt.Errorf("volume '%s' currently in use (%d unique)", r.Name, len(v.use))
|
||||
}
|
||||
if err := umount(v); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(d.volumes, r.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Path(r *volume.PathRequest) (*volume.PathResponse, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
v, ok := d.volumes[r.Name]
|
||||
if !ok {
|
||||
return &volume.PathResponse{}, fmt.Errorf("volume '%s' not found", r.Name)
|
||||
}
|
||||
return &volume.PathResponse{Mountpoint: v.volume.Mountpoint}, nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Mount(r *volume.MountRequest) (*volume.MountResponse, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
v, ok := d.volumes[r.Name]
|
||||
if !ok {
|
||||
return &volume.MountResponse{}, fmt.Errorf("volume '%s' not found", r.Name)
|
||||
}
|
||||
log.Printf("Attach ObjectiveFS Volume '%s' to '%s'", r.Name, r.ID)
|
||||
if !v.mounted {
|
||||
if err := os.MkdirAll(v.volume.Mountpoint, 0755); err != nil {
|
||||
return &volume.MountResponse{}, err
|
||||
}
|
||||
cmd := exec.Command("/sbin/mount.objectivefs", "-o"+v.opts, v.fs, v.volume.Mountpoint)
|
||||
cmd.Env = v.env
|
||||
log.Printf("Mount ObjectiveFS Volume '%s': '%s'", r.Name, cmd)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return &volume.MountResponse{}, fmt.Errorf("unexpected error mounting '%s' check log (/var/log/syslog or /var/log/messages): %s", r.Name, err.Error())
|
||||
}
|
||||
v.mounted = true
|
||||
}
|
||||
v.use[r.ID] = true
|
||||
return &volume.MountResponse{Mountpoint: v.volume.Mountpoint}, nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Unmount(r *volume.UnmountRequest) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
v, ok := d.volumes[r.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("volume '%s' not found", r.Name)
|
||||
}
|
||||
log.Printf("Detach ObjectiveFS Volume '%s' from '%s'", r.Name, r.ID)
|
||||
delete(v.use, r.ID)
|
||||
if len(v.use) == 0 && v.asap {
|
||||
if err := umount(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d ofsDriver) Capabilities() *volume.CapabilitiesResponse {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
return &volume.CapabilitiesResponse{Capabilities: volume.Capability{Scope: "local"}}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Printf("Starting ObjectiveFS Volume Driver, version " + version)
|
||||
d := ofsDriver{volumes: make(map[string]*ofsVolume)}
|
||||
h := volume.NewHandler(d)
|
||||
u, _ := user.Lookup("root")
|
||||
gid, _ := strconv.Atoi(u.Gid)
|
||||
h.ServeUnix("objectivefs", gid)
|
||||
}
|
||||
Reference in New Issue
Block a user