2021-12-06 12:24:22 +00:00
|
|
|
package biz
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/cuigh/auxo/data"
|
|
|
|
"github.com/cuigh/auxo/net/web"
|
|
|
|
"github.com/cuigh/swirl/docker"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/volume"
|
|
|
|
)
|
|
|
|
|
|
|
|
type VolumeBiz interface {
|
2022-01-06 08:54:14 +00:00
|
|
|
Search(ctx context.Context, node, name string, pageIndex, pageSize int) ([]*Volume, int, error)
|
|
|
|
Find(ctx context.Context, node, name string) (volume *Volume, raw string, err error)
|
|
|
|
Delete(ctx context.Context, node, name string, user web.User) (err error)
|
|
|
|
Create(ctx context.Context, volume *Volume, user web.User) (err error)
|
|
|
|
Prune(ctx context.Context, node string, user web.User) (count int, size uint64, err error)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewVolume(d *docker.Docker, eb EventBiz) VolumeBiz {
|
|
|
|
return &volumeBiz{d: d, eb: eb}
|
|
|
|
}
|
|
|
|
|
|
|
|
type volumeBiz struct {
|
|
|
|
d *docker.Docker
|
|
|
|
eb EventBiz
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *volumeBiz) Find(ctx context.Context, node, name string) (volume *Volume, raw string, err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
var (
|
|
|
|
v types.Volume
|
|
|
|
r []byte
|
|
|
|
)
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
if v, r, err = b.d.VolumeInspect(ctx, node, name); err == nil {
|
2021-12-06 12:24:22 +00:00
|
|
|
raw, err = indentJSON(r)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
volume = newVolume(&v)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *volumeBiz) Search(ctx context.Context, node, name string, pageIndex, pageSize int) (volumes []*Volume, total int, err error) {
|
|
|
|
list, total, err := b.d.VolumeList(ctx, node, name, pageIndex, pageSize)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
volumes = make([]*Volume, len(list))
|
|
|
|
for i, v := range list {
|
|
|
|
volumes[i] = newVolume(v)
|
|
|
|
}
|
|
|
|
return volumes, total, nil
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *volumeBiz) Delete(ctx context.Context, node, name string, user web.User) (err error) {
|
|
|
|
err = b.d.VolumeRemove(ctx, node, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
2021-12-24 07:04:15 +00:00
|
|
|
b.eb.CreateVolume(EventActionDelete, node, name, user)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *volumeBiz) Create(ctx context.Context, vol *Volume, user web.User) (err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
options := &volume.VolumeCreateBody{
|
|
|
|
Name: vol.Name,
|
|
|
|
Driver: vol.Driver,
|
|
|
|
DriverOpts: toMap(vol.Options),
|
|
|
|
Labels: toMap(vol.Labels),
|
|
|
|
}
|
|
|
|
if vol.Driver == "other" {
|
|
|
|
options.Driver = vol.CustomDriver
|
|
|
|
} else {
|
|
|
|
options.Driver = vol.Driver
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
err = b.d.VolumeCreate(ctx, vol.Node, options)
|
2021-12-24 07:04:15 +00:00
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateVolume(EventActionDelete, vol.Node, vol.Name, user)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *volumeBiz) Prune(ctx context.Context, node string, user web.User) (count int, size uint64, err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
var report types.VolumesPruneReport
|
2022-01-06 08:54:14 +00:00
|
|
|
report, err = b.d.VolumePrune(ctx, node)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
2021-12-23 07:25:51 +00:00
|
|
|
count, size = len(report.VolumesDeleted), report.SpaceReclaimed
|
2021-12-24 07:04:15 +00:00
|
|
|
b.eb.CreateVolume(EventActionPrune, node, "", user)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-12-16 12:23:08 +00:00
|
|
|
|
|
|
|
type Volume struct {
|
2021-12-20 06:28:43 +00:00
|
|
|
Node string `json:"node"`
|
2021-12-16 12:23:08 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
Driver string `json:"driver,omitempty"`
|
|
|
|
CustomDriver string `json:"customDriver,omitempty"`
|
|
|
|
CreatedAt string `json:"createdAt"`
|
|
|
|
MountPoint string `json:"mountPoint,omitempty"`
|
|
|
|
Scope string `json:"scope"`
|
|
|
|
Labels data.Options `json:"labels,omitempty"`
|
|
|
|
Options data.Options `json:"options,omitempty"`
|
|
|
|
Status map[string]interface{} `json:"status,omitempty"`
|
|
|
|
RefCount int64 `json:"refCount"`
|
|
|
|
Size int64 `json:"size"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func newVolume(v *types.Volume) *Volume {
|
|
|
|
createdAt, _ := time.Parse(time.RFC3339Nano, v.CreatedAt)
|
|
|
|
vol := &Volume{
|
|
|
|
Name: v.Name,
|
|
|
|
Driver: v.Driver,
|
|
|
|
CreatedAt: formatTime(createdAt),
|
|
|
|
MountPoint: v.Mountpoint,
|
|
|
|
Scope: v.Scope,
|
|
|
|
Status: v.Status,
|
|
|
|
Labels: mapToOptions(v.Labels),
|
|
|
|
Options: mapToOptions(v.Options),
|
|
|
|
RefCount: -1,
|
|
|
|
Size: -1,
|
|
|
|
}
|
|
|
|
if v.UsageData != nil {
|
|
|
|
vol.RefCount = v.UsageData.RefCount
|
|
|
|
vol.Size = v.UsageData.Size
|
|
|
|
}
|
|
|
|
return vol
|
|
|
|
}
|