Skip to content

Commit

Permalink
Use flags instead of env variables + docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Johannes Scheuermann committed Jul 13, 2016
1 parent 0bd6f23 commit 0eccaf7
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
docker-quobyte-plugin
bin
60 changes: 42 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,60 @@
# Quobyte volume plug-in for Docker

Tested with `CentOS 7.2` and `Docker 1.10.3`. This plugin allows you to use [Quobyte](www.quobyte.com) with Docker without installing the Quobyte client on the host system (e.q. Rancher/CoreOS).
This plugin allows you to use [Quobyte](www.quobyte.com) with Docker without installing the Quobyte client on the host system (e.q. Rancher/CoreOS).

## Tested

OS | Docker Version
--------------- | :------------:
CentOS 7.2 | 1.10.3
Ubuntu 16.04 | 1.11.2
CoreOS 1097.0.0 | 1.11.2

## Build

Get the code

```
$ go get -u github.com/quobyte/api
$ go get -u github.com/quobyte/docker-volume
```

### Linux

```
$ go build -o docker-quobyte-plugin .
$ cp quobyte-docker-plugin /usr/libexec/docker/docker-quobyte-plugin
$ go build -o bin/docker-quobyte-plugin .
```

### OSX/MacOS

```
$ GOOS=linux GOARCH=amd64 go build -o docker-quobyte-plugin
$ cp quobyte-docker-plugin /usr/libexec/docker/docker-quobyte-plugin
$ GOOS=linux GOARCH=amd64 go build -o bin/docker-quobyte-plugin .
```

### Docker

```
$ docker run --rm -v "$GOPATH":/work -e "GOPATH=/work" -w /work/src/github.com/quobyte/docker-volume golang:1.6 go build -v -o bin/quobyte-docker-plugin
```

## Usage

```
$ bin/docker-quobyte-plugin -h
Usage of /opt/bin/docker-quobyte-plugin:
-api string
URL to the API server(s) in the form host[:port][,host:port] or SRV record name (default "localhost:7860")
-group string
Group to create the unix socket (default "root")
-options string
Fuse options to be used when Quobyte is mounted (default "-o user_xattr")
-password string
Password for the user to connect to the Quobyte API server (default "quobyte")
-path string
Path where Quobyte is mounted on the host (default "/run/docker/quobyte/mnt")
-registry string
URL to the registry server(s) in the form of host[:port][,host:port] or SRV record name (default "localhost:7861")
-user string
User to connect to the Quobyte API server (default "root")
```

## Setup
Expand All @@ -35,22 +67,14 @@ This step is optional.
$ qmgmt -u <api-url> user config add docker <email>
```

### Set mandatory configuration in environment

```
$ export QUOBYTE_API_USER=docker
$ export QUOBYTE_API_PASSWORD=...
$ export QUOBYTE_API_URL=http://<host>:7860/
# host[:port][,host:port] or SRV record name
$ export QUOBYTE_REGISTRY=quobyte.corp
```
### systemd

### Install systemd files Set the variables in systemd/docker-quobyte.env.sample
Install systemd files and set your variables in systemd/docker-quobyte.env.sample

```
$ cp systemd/docker-quobyte.env.sample /etc/quobyte/docker-quobyte.env
$ cp docker-quobyte-plugin /usr/libexec/docker/
$ cp systemd/* /lib/systemd/system
$ cp bin/docker-quobyte-plugin /usr/local/bin/
$ cp systemd/docker-quobyte-plugin.service /lib/systemd/system
$ systemctl daemon-reload
$ systemctl start docker-quobyte-plugin
Expand Down
Binary file added docker-quobyte-plugin
Binary file not shown.
3 changes: 3 additions & 0 deletions docs/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Documentation

- [Setup at CoreOS](coreos.md)
72 changes: 72 additions & 0 deletions docs/coreos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Setup on CoreOS

Set the mount flags to `shared` this step shouldn't be needed with docker 1.12+.

```
$ sudo mkdir /etc/systemd/system/docker.service.d/
$ sudo sh -c 'echo -e "[Service]
MountFlags=shared
" > /etc/systemd/system/docker.service.d/slave-mount-flags.conf'
# Restart Docker
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
```

Create a directory to mount quobyte.

```
$ sudo mkdir /mnt/quobyte
```

Now mount Quobyte with Docker. If the command below fails use `-h $(hostname)` instead of `-h $(hostname -f)`.

```
$ docker run -d --name quobyte-client --privileged \
-e QUOBYTE_REGISTRY=localhost:7861 \
-p 55000:55000 \
-v /mnt/quobyte:/quobyte:shared \
-h $(hostname -f) \
quay.io/quobyte/quobyte-client:1.2.12
# Validate mount
$ mount | grep quobyte
```

Create the config file for the plugin:

```
$ sudo mkdir /etc/quobyte
$ sudo cat /etc/quobyte/docker-quobyte.env
QUOBYTE_API_USER=admin
QUOBYTE_API_PASSWORD=quobyte
QUOBYTE_API_URL=http://quobyte:7860
QUOBYTE_REGISTRY=quobyte:7861
```

Create the systemd service

```
$ sudo cat /etc/systemd/system/docker-quobyte-plugin.service
[Unit]
Description=Docker Quobyte Plugin
Documentation=https://github.com/johscheuer/go-quobyte-docker
Before=docker.service
After=network.target docker.service
Requires=docker.service
[Service]
EnvironmentFile=/etc/quobyte/docker-quobyte.env
ExecStart=/opt/bin/docker-quobyte-plugin --user ${QUOBYTE_API_USER} --password ${QUOBYTE_API_PASSWORD} --api ${QUOBYTE_API_URL} --registry ${QUOBYTE_REGISTRY} --path /mnt/quobyte --group docker
[Install]
WantedBy=multi-user.target
```

Start the Plugin

```
$ sudo systemctl daemon-reload
$ sudo systemctl start docker-quobyte-plugin
$ sudo systemctl enable docker-quobyte-plugin
```
33 changes: 16 additions & 17 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"flag"
"log"
"os"

Expand All @@ -9,30 +10,28 @@ import (

const quobyteID string = "quobyte"

// Mandatory configuration
var qmgmtUser string
var qmgmtPassword string
var quobyteAPIURL string
var quobyteRegistry string
func main() {
quobyteMountPath := flag.String("path", "/run/docker/quobyte/mnt", "Path where Quobyte is mounted on the host")
quobyteMountOptions := flag.String("options", "-o user_xattr", "Fuse options to be used when Quobyte is mounted")

// Optional configuration
var mountQuobytePath string
var mountQuobyteOptions string
quobyteUser := flag.String("user", "root", "User to connect to the Quobyte API server")
quobytePassword := flag.String("password", "quobyte", "Password for the user to connect to the Quobyte API server")
quobyteAPIURL := flag.String("api", "localhost:7860", "URL to the API server(s) in the form host[:port][,host:port] or SRV record name")
quobyteRegistry := flag.String("registry", "localhost:7861", "URL to the registry server(s) in the form of host[:port][,host:port] or SRV record name")

func main() {
readMandatoryConfig()
readOptionalConfig()
group := flag.String("group", "root", "Group to create the unix socket")
flag.Parse()

if err := os.MkdirAll(mountQuobytePath, 0555); err != nil {
if err := os.MkdirAll(*quobyteMountPath, 0555); err != nil {
log.Println(err.Error())
}

if !isMounted(mountQuobytePath) {
log.Printf("Mounting Quobyte namespace in %s", mountQuobytePath)
mountAll()
if !isMounted(*quobyteMountPath) {
log.Printf("Mounting Quobyte namespace in %s", *quobyteMountPath)
mountAll(*quobyteMountOptions, *quobyteRegistry, *quobyteMountPath)
}

qDriver := newQuobyteDriver(quobyteAPIURL, qmgmtUser, qmgmtPassword)
qDriver := newQuobyteDriver(*quobyteAPIURL, *quobyteUser, *quobytePassword, *quobyteMountPath)
handler := volume.NewHandler(qDriver)
log.Println(handler.ServeUnix("root", quobyteID))
log.Println(handler.ServeUnix(*group, quobyteID))
}
24 changes: 13 additions & 11 deletions quobyte_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (
)

type quobyteDriver struct {
client *quobyte_api.QuobyteClient
m *sync.Mutex
client *quobyte_api.QuobyteClient
quobyteMount string
m *sync.Mutex
}

func newQuobyteDriver(apiURL string, username string, password string) quobyteDriver {
func newQuobyteDriver(apiURL string, username string, password string, quobyteMount string) quobyteDriver {
driver := quobyteDriver{
client: quobyte_api.NewQuobyteClient(apiURL, username, password),
m: &sync.Mutex{},
client: quobyte_api.NewQuobyteClient(apiURL, username, password),
quobyteMount: quobyteMount,
m: &sync.Mutex{},
}

return driver
Expand Down Expand Up @@ -63,7 +65,7 @@ func (driver quobyteDriver) Remove(request volume.Request) volume.Response {
func (driver quobyteDriver) Mount(request volume.Request) volume.Response {
driver.m.Lock()
defer driver.m.Unlock()
mPoint := filepath.Join(mountQuobytePath, request.Name)
mPoint := filepath.Join(driver.quobyteMount, request.Name)
log.Printf("Mounting volume %s on %s\n", request.Name, mPoint)
if fi, err := os.Lstat(mPoint); err != nil || !fi.IsDir() {
return volume.Response{Err: fmt.Sprintf("%v not mounted", mPoint)}
Expand All @@ -73,7 +75,7 @@ func (driver quobyteDriver) Mount(request volume.Request) volume.Response {
}

func (driver quobyteDriver) Path(request volume.Request) volume.Response {
return volume.Response{Mountpoint: filepath.Join(mountQuobytePath, request.Name)}
return volume.Response{Mountpoint: filepath.Join(driver.quobyteMount, request.Name)}
}

func (driver quobyteDriver) Unmount(request volume.Request) volume.Response {
Expand All @@ -84,7 +86,7 @@ func (driver quobyteDriver) Get(request volume.Request) volume.Response {
driver.m.Lock()
defer driver.m.Unlock()

mPoint := filepath.Join(mountQuobytePath, request.Name)
mPoint := filepath.Join(driver.quobyteMount, request.Name)

if fi, err := os.Lstat(mPoint); err != nil || !fi.IsDir() {
return volume.Response{Err: fmt.Sprintf("%v not mounted", mPoint)}
Expand All @@ -98,20 +100,20 @@ func (driver quobyteDriver) List(request volume.Request) volume.Response {
defer driver.m.Unlock()

var vols []*volume.Volume
files, err := ioutil.ReadDir(mountQuobytePath)
files, err := ioutil.ReadDir(driver.quobyteMount)
if err != nil {
return volume.Response{Err: err.Error()}
}

for _, entry := range files {
if entry.IsDir() {
vols = append(vols, &volume.Volume{Name: entry.Name(), Mountpoint: filepath.Join(mountQuobytePath, entry.Name())})
vols = append(vols, &volume.Volume{Name: entry.Name(), Mountpoint: filepath.Join(driver.quobyteMount, entry.Name())})
}
}

return volume.Response{Volumes: vols}
}

func (driver quobyteDriver) Capabilities(request volume.Request) volume.Response {
return volume.Response{Capabilities: volume.Capability{Scope: "local"}}
return volume.Response{Capabilities: volume.Capability{Scope: "global"}}
}
2 changes: 1 addition & 1 deletion systemd/docker-quobyte-plugin.service
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Requires=docker.service

[Service]
EnvironmentFile=/etc/quobyte/docker-quobyte.env
ExecStart=/usr/libexec/docker/docker-quobyte-plugin
ExecStart=/usr/local/bin/docker-quobyte-plugin --user ${QUOBYTE_API_USER} --password ${QUOBYTE_API_PASSWORD} --api ${QUOBYTE_API_URL} --registry ${QUOBYTE_REGISTRY}

[Install]
WantedBy=multi-user.target
8 changes: 4 additions & 4 deletions systemd/docker-quobyte.env.sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
QUOBYTE_API_USER=docker
QUOBYTE_API_PASSWORD=...
QUOBYTE_API_URL=http://<host>:7860/
QUOBYTE_REGISTRY=quobyte.corp
QUOBYTE_API_USER=admin
QUOBYTE_API_PASSWORD=quobyte
QUOBYTE_API_URL=http://localhost:7860
QUOBYTE_REGISTRY=localhost:7861
34 changes: 5 additions & 29 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,10 @@ import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
)

func readOptionalConfig() {
mountQuobytePath = os.Getenv("MOUNT_QUOBYTE_PATH")
if len(mountQuobyteOptions) == 0 {
mountQuobytePath = "/run/docker/quobyte/mnt"
}
mountQuobyteOptions = os.Getenv("MOUNT_QUOBYTE_OPTIONS")
if len(mountQuobyteOptions) == 0 {
mountQuobyteOptions = "-o user_xattr"
}
}

func readMandatoryConfig() {
qmgmtUser = getMandatoryEnv("QUOBYTE_API_USER")
qmgmtPassword = getMandatoryEnv("QUOBYTE_API_PASSWORD")
quobyteAPIURL = getMandatoryEnv("QUOBYTE_API_URL")
quobyteRegistry = getMandatoryEnv("QUOBYTE_REGISTRY")
}

func getMandatoryEnv(name string) string {
env := os.Getenv(name)
if len(env) < 0 {
log.Fatalf("Please set %s in environment\n", name)
}

return env
}

func isMounted(mountPath string) bool {
content, err := ioutil.ReadFile("/proc/mounts")
if err != nil {
Expand All @@ -47,6 +19,10 @@ func isMounted(mountPath string) bool {
continue
}

if !strings.HasPrefix(splitted[0], "quobyte") {
continue
}

if splitted[1] == mountPath {
log.Printf("Found Mountpoint: %s\n", mountPath)
return true
Expand All @@ -56,7 +32,7 @@ func isMounted(mountPath string) bool {
return false
}

func mountAll() {
func mountAll(mountQuobyteOptions, quobyteRegistry, mountQuobytePath string) {
cmdStr := fmt.Sprintf("mount %s -t quobyte %s %s", mountQuobyteOptions, fmt.Sprintf("%s/", quobyteRegistry), mountQuobytePath)
if out, err := exec.Command("/bin/sh", "-c", cmdStr).CombinedOutput(); err != nil {
log.Fatalln(string(out))
Expand Down

0 comments on commit 0eccaf7

Please sign in to comment.