"crypto/md5"
"encoding/json"
"fmt"
- "github.com/gorilla/mux"
"io"
"net/http"
"os"
"sync"
"time"
+ "github.com/gorilla/mux"
+
"git.curoverse.com/arvados.git/sdk/go/httpserver"
log "github.com/Sirupsen/logrus"
)
// List volumes: path, device number, bytes used/avail.
rest.HandleFunc(`/status.json`, rtr.StatusHandler).Methods("GET", "HEAD")
+ // List mounts: UUID, readonly, tier, device ID, ...
+ rest.HandleFunc(`/mounts`, rtr.Mounts).Methods("GET")
+
// Replace the current pull queue.
rest.HandleFunc(`/pull`, PullHandler).Methods("PUT")
resp.Write([]byte{'\n'})
}
+// Mounts responds to "GET /mounts" requests.
+func (rtr *router) Mounts(resp http.ResponseWriter, req *http.Request) {
+ err := json.NewEncoder(resp).Encode(KeepVM.Mounts())
+ if err != nil {
+ http.Error(resp, err.Error(), http.StatusInternalServerError)
+ }
+}
+
// PoolStatus struct
type PoolStatus struct {
Alloc uint64 `json:"BytesAllocated"`
import (
"context"
+ "crypto/rand"
"io"
+ "math/big"
"sync/atomic"
"time"
)
// A VolumeManager tells callers which volumes can read, which volumes
// can write, and on which volume the next write should be attempted.
type VolumeManager interface {
+ // Mounts returns all mounts (volume attachments).
+ Mounts() []*VolumeMount
+
// AllReadable returns all volumes.
AllReadable() []Volume
Close()
}
+// A VolumeMount is an attachment of a Volume to a VolumeManager.
+type VolumeMount struct {
+ UUID string
+ DeviceID string
+ ReadOnly bool
+ Tier int
+ volume Volume
+}
+
+// Generate a UUID the way API server would for a "KeepVolumeMount"
+// object.
+func (*VolumeMount) generateUUID() string {
+ var max big.Int
+ _, ok := max.SetString("zzzzzzzzzzzzzzz", 36)
+ if !ok {
+ panic("big.Int parse failed")
+ }
+ r, err := rand.Int(rand.Reader, &max)
+ if err != nil {
+ panic(err)
+ }
+ return "zzzzz-ivpuk-" + r.Text(36)
+}
+
// RRVolumeManager is a round-robin VolumeManager: the Nth call to
// NextWritable returns the (N % len(writables))th writable Volume
// (where writables are all Volumes v where v.Writable()==true).
type RRVolumeManager struct {
+ mounts []*VolumeMount
readables []Volume
writables []Volume
counter uint32
iostats: make(map[Volume]*ioStats),
}
for _, v := range volumes {
+ mnt := &VolumeMount{
+ UUID: (*VolumeMount)(nil).generateUUID(),
+ DeviceID: "",
+ ReadOnly: !v.Writable(),
+ Tier: 1,
+ volume: v,
+ }
+ if v, ok := v.(interface {
+ DeviceID() string
+ }); ok {
+ mnt.DeviceID = v.DeviceID()
+ }
vm.iostats[v] = &ioStats{}
+ vm.mounts = append(vm.mounts, mnt)
vm.readables = append(vm.readables, v)
if v.Writable() {
vm.writables = append(vm.writables, v)
return vm
}
+func (vm *RRVolumeManager) Mounts() []*VolumeMount {
+ return vm.mounts
+}
+
// AllReadable returns an array of all readable volumes
func (vm *RRVolumeManager) AllReadable() []Volume {
return vm.readables