2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 17:17:13 +08:00
Files
panel/app/http/controllers/container_controller.go
2024-06-12 01:09:09 +08:00

1088 lines
29 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controllers
import (
"fmt"
"strconv"
"strings"
"github.com/TheTNB/panel/pkg/tools"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/docker/go-connections/nat"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/support/carbon"
commonrequests "github.com/TheTNB/panel/app/http/requests/common"
requests "github.com/TheTNB/panel/app/http/requests/container"
"github.com/TheTNB/panel/internal/services"
)
type ContainerController struct {
container services.Container
}
func NewContainerController() *ContainerController {
return &ContainerController{
container: services.NewContainer(),
}
}
// ContainerList
//
// @Summary 获取容器列表
// @Description 获取所有容器列表
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query commonrequests.Paginate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/list [get]
func (r *ContainerController) ContainerList(ctx http.Context) http.Response {
var request commonrequests.Paginate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
containers, err := r.container.ContainerListAll()
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(containers) {
return Success(ctx, http.Json{
"total": 0,
"items": []any{},
})
}
if endIndex > len(containers) {
endIndex = len(containers)
}
paged := containers[startIndex:endIndex]
items := make([]any, 0)
for _, item := range paged {
var name string
if len(item.Names) > 0 {
name = item.Names[0]
}
items = append(items, map[string]any{
"id": item.ID,
"name": strings.TrimLeft(name, "/"),
"image": item.Image,
"image_id": item.ImageID,
"command": item.Command,
"created": carbon.FromTimestamp(item.Created).ToDateTimeString(),
"ports": item.Ports,
"labels": item.Labels,
"state": item.State,
"status": item.Status,
})
}
return Success(ctx, http.Json{
"total": len(containers),
"items": items,
})
}
// ContainerSearch
//
// @Summary 搜索容器
// @Description 根据容器名称搜索容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param name query string true "容器名称"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/search [get]
func (r *ContainerController) ContainerSearch(ctx http.Context) http.Response {
fields := strings.Fields(ctx.Request().Query("name"))
containers, err := r.container.ContainerListByNames(fields)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, containers)
}
// ContainerCreate
//
// @Summary 创建容器
// @Description 创建一个容器
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.ContainerCreate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/create [post]
func (r *ContainerController) ContainerCreate(ctx http.Context) http.Response {
var request requests.ContainerCreate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
var hostConf container.HostConfig
var networkConf network.NetworkingConfig
portMap := make(nat.PortMap)
for _, port := range request.Ports {
if port.ContainerStart-port.ContainerEnd != port.HostStart-port.HostEnd {
return Error(ctx, http.StatusUnprocessableEntity, fmt.Sprintf("容器端口和主机端口数量不匹配(容器: %d 主机: %d", port.ContainerStart-port.ContainerEnd, port.HostStart-port.HostEnd))
}
if port.ContainerStart > port.ContainerEnd || port.HostStart > port.HostEnd || port.ContainerStart < 1 || port.HostStart < 1 {
return Error(ctx, http.StatusUnprocessableEntity, "端口范围不正确")
}
count := 0
for host := port.HostStart; host <= port.HostEnd; host++ {
bindItem := nat.PortBinding{HostPort: strconv.Itoa(host), HostIP: port.Host}
portMap[nat.Port(fmt.Sprintf("%d/%s", port.ContainerStart+count, port.Protocol))] = []nat.PortBinding{bindItem}
count++
}
}
exposed := make(nat.PortSet)
for port := range portMap {
exposed[port] = struct{}{}
}
if request.Network != "" {
switch request.Network {
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(request.Network)
}
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{request.Network: {}}
} else {
networkConf = network.NetworkingConfig{}
}
hostConf.Privileged = request.Privileged
hostConf.AutoRemove = request.AutoRemove
hostConf.CPUShares = request.CPUShares
hostConf.PublishAllPorts = request.PublishAllPorts
hostConf.RestartPolicy = container.RestartPolicy{Name: container.RestartPolicyMode(request.RestartPolicy)}
if request.RestartPolicy == "on-failure" {
hostConf.RestartPolicy.MaximumRetryCount = 5
}
hostConf.NanoCPUs = request.CPUs * 1000000000
hostConf.Memory = request.Memory * 1024 * 1024
hostConf.MemorySwap = 0
hostConf.PortBindings = portMap
hostConf.Binds = []string{}
volumes := make(map[string]struct{})
for _, v := range request.Volumes {
volumes[v.Container] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", v.Host, v.Container, v.Mode))
}
id, err := r.container.ContainerCreate(request.Name,
container.Config{
Image: request.Image,
Env: r.container.KVToSlice(request.Env),
Entrypoint: request.Entrypoint,
Cmd: request.Command,
Labels: r.container.KVToMap(request.Labels),
ExposedPorts: exposed,
OpenStdin: request.OpenStdin,
Tty: request.Tty,
Volumes: volumes,
},
hostConf,
networkConf,
)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
if err = r.container.ContainerStart(id); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, id)
}
// ContainerRemove
//
// @Summary 删除容器
// @Description 删除一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/remove [post]
func (r *ContainerController) ContainerRemove(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerRemove(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerStart
//
// @Summary 启动容器
// @Description 启动一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/start [post]
func (r *ContainerController) ContainerStart(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerStart(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerStop
//
// @Summary 停止容器
// @Description 停止一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/stop [post]
func (r *ContainerController) ContainerStop(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerStop(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerRestart
//
// @Summary 重启容器
// @Description 重启一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/restart [post]
func (r *ContainerController) ContainerRestart(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerRestart(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerPause
//
// @Summary 暂停容器
// @Description 暂停一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
func (r *ContainerController) ContainerPause(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerPause(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerUnpause
//
// @Summary 取消暂停容器
// @Description 取消暂停一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
//
// @Router /panel/container/unpause [post]
func (r *ContainerController) ContainerUnpause(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerUnpause(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerInspect
//
// @Summary 查看容器
// @Description 查看一个容器的详细信息
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/inspect [get]
func (r *ContainerController) ContainerInspect(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.ContainerInspect(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// ContainerKill
//
// @Summary 杀死容器
// @Description 杀死一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/kill [post]
func (r *ContainerController) ContainerKill(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerKill(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerRename
//
// @Summary 重命名容器
// @Description 重命名一个容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ContainerRename true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/rename [post]
func (r *ContainerController) ContainerRename(ctx http.Context) http.Response {
var request requests.ContainerRename
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ContainerRename(request.ID, request.Name); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ContainerStats
//
// @Summary 查看容器状态
// @Description 查看一个容器的状态信息
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/stats [get]
func (r *ContainerController) ContainerStats(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.ContainerStats(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// ContainerExist
//
// @Summary 检查容器是否存在
// @Description 检查一个容器是否存在
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/exist [get]
func (r *ContainerController) ContainerExist(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
exist, err := r.container.ContainerExist(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, exist)
}
// ContainerLogs
//
// @Summary 查看容器日志
// @Description 查看一个容器的日志
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/logs [get]
func (r *ContainerController) ContainerLogs(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.ContainerLogs(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// ContainerPrune
//
// @Summary 清理容器
// @Description 清理无用的容器
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/container/prune [post]
func (r *ContainerController) ContainerPrune(ctx http.Context) http.Response {
if err := r.container.ContainerPrune(); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// NetworkList
//
// @Summary 获取网络列表
// @Description 获取所有网络列表
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query commonrequests.Paginate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/list [get]
func (r *ContainerController) NetworkList(ctx http.Context) http.Response {
var request commonrequests.Paginate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
networks, err := r.container.NetworkList()
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(networks) {
return Success(ctx, http.Json{
"total": 0,
"items": []any{},
})
}
if endIndex > len(networks) {
endIndex = len(networks)
}
paged := networks[startIndex:endIndex]
if paged == nil {
paged = []types.NetworkResource{}
}
var items []any
for _, item := range paged {
var ipamConfig []any
for _, v := range item.IPAM.Config {
ipamConfig = append(ipamConfig, map[string]any{
"subnet": v.Subnet,
"gateway": v.Gateway,
"ip_range": v.IPRange,
"aux_address": v.AuxAddress,
})
}
items = append(items, map[string]any{
"id": item.ID,
"name": item.Name,
"driver": item.Driver,
"ipv6": item.EnableIPv6,
"scope": item.Scope,
"internal": item.Internal,
"attachable": item.Attachable,
"ingress": item.Ingress,
"labels": item.Labels,
"options": item.Options,
"ipam": map[string]any{
"config": ipamConfig,
"driver": item.IPAM.Driver,
"options": item.IPAM.Options,
},
"created": carbon.FromStdTime(item.Created).ToDateTimeString(),
})
}
return Success(ctx, http.Json{
"total": len(networks),
"items": items,
})
}
// NetworkCreate
//
// @Summary 创建网络
// @Description 创建一个网络
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.NetworkCreate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/create [post]
func (r *ContainerController) NetworkCreate(ctx http.Context) http.Response {
var request requests.NetworkCreate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
id, err := r.container.NetworkCreate(request)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, id)
}
// NetworkRemove
//
// @Summary 删除网络
// @Description 删除一个网络
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/remove [post]
func (r *ContainerController) NetworkRemove(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.NetworkRemove(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// NetworkExist
//
// @Summary 检查网络是否存在
// @Description 检查一个网络是否存在
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/exist [get]
func (r *ContainerController) NetworkExist(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
exist, err := r.container.NetworkExist(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, exist)
}
// NetworkInspect
//
// @Summary 查看网络
// @Description 查看一个网络的详细信息
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/inspect [get]
func (r *ContainerController) NetworkInspect(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.NetworkInspect(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// NetworkConnect
//
// @Summary 连接容器到网络
// @Description 连接一个容器到一个网络
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.NetworkConnectDisConnect true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/connect [post]
func (r *ContainerController) NetworkConnect(ctx http.Context) http.Response {
var request requests.NetworkConnectDisConnect
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.NetworkConnect(request.Network, request.Container); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// NetworkDisconnect
//
// @Summary 从网络断开容器
// @Description 从一个网络断开一个容器
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.NetworkConnectDisConnect true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/disconnect [post]
func (r *ContainerController) NetworkDisconnect(ctx http.Context) http.Response {
var request requests.NetworkConnectDisConnect
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.NetworkDisconnect(request.Network, request.Container); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// NetworkPrune
//
// @Summary 清理网络
// @Description 清理无用的网络
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/container/network/prune [post]
func (r *ContainerController) NetworkPrune(ctx http.Context) http.Response {
if err := r.container.NetworkPrune(); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ImageList
//
// @Summary 获取镜像列表
// @Description 获取所有镜像列表
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query commonrequests.Paginate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/list [get]
func (r *ContainerController) ImageList(ctx http.Context) http.Response {
var request commonrequests.Paginate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
images, err := r.container.ImageList()
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(images) {
return Success(ctx, http.Json{
"total": 0,
"items": []any{},
})
}
if endIndex > len(images) {
endIndex = len(images)
}
paged := images[startIndex:endIndex]
if paged == nil {
paged = []image.Summary{}
}
var items []any
for _, item := range paged {
items = append(items, map[string]any{
"id": item.ID,
"created": carbon.FromTimestamp(item.Created).ToDateTimeString(),
"containers": item.Containers,
"size": tools.FormatBytes(float64(item.Size)),
"labels": item.Labels,
"repo_tags": item.RepoTags,
"repo_digests": item.RepoDigests,
})
}
return Success(ctx, http.Json{
"total": len(images),
"items": items,
})
}
// ImageExist
//
// @Summary 检查镜像是否存在
// @Description 检查一个镜像是否存在
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/exist [get]
func (r *ContainerController) ImageExist(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
exist, err := r.container.ImageExist(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, exist)
}
// ImagePull
//
// @Summary 拉取镜像
// @Description 拉取一个镜像
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.ImagePull true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/pull [post]
func (r *ContainerController) ImagePull(ctx http.Context) http.Response {
var request requests.ImagePull
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ImagePull(request); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ImageRemove
//
// @Summary 删除镜像
// @Description 删除一个镜像
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/remove [post]
func (r *ContainerController) ImageRemove(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.ImageRemove(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ImagePrune
//
// @Summary 清理镜像
// @Description 清理无用的镜像
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/prune [post]
func (r *ContainerController) ImagePrune(ctx http.Context) http.Response {
if err := r.container.ImagePrune(); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// ImageInspect
//
// @Summary 查看镜像
// @Description 查看一个镜像的详细信息
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/image/inspect [get]
func (r *ContainerController) ImageInspect(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.ImageInspect(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// VolumeList
//
// @Summary 获取卷列表
// @Description 获取所有卷列表
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query commonrequests.Paginate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/list [get]
func (r *ContainerController) VolumeList(ctx http.Context) http.Response {
var request commonrequests.Paginate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
volumes, err := r.container.VolumeList()
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(volumes) {
return Success(ctx, http.Json{
"total": 0,
"items": []any{},
})
}
if endIndex > len(volumes) {
endIndex = len(volumes)
}
paged := volumes[startIndex:endIndex]
if paged == nil {
paged = []*volume.Volume{}
}
var items []any
for _, item := range paged {
var usage any
if item.UsageData != nil {
usage = map[string]any{
"ref_count": item.UsageData.RefCount,
"size": tools.FormatBytes(float64(item.UsageData.Size)),
}
}
items = append(items, map[string]any{
"id": item.Name,
"created": carbon.Parse(item.CreatedAt).ToDateTimeString(),
"driver": item.Driver,
"mount": item.Mountpoint,
"labels": item.Labels,
"options": item.Options,
"scope": item.Scope,
"status": item.Status,
"usage": usage,
})
}
return Success(ctx, http.Json{
"total": len(volumes),
"items": items,
})
}
// VolumeCreate
//
// @Summary 创建卷
// @Description 创建一个卷
// @Tags 容器
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.VolumeCreate true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/create [post]
func (r *ContainerController) VolumeCreate(ctx http.Context) http.Response {
var request requests.VolumeCreate
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.VolumeCreate(request)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data.Name)
}
// VolumeExist
//
// @Summary 检查卷是否存在
// @Description 检查一个卷是否存在
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/exist [get]
func (r *ContainerController) VolumeExist(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
exist, err := r.container.VolumeExist(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, exist)
}
// VolumeInspect
//
// @Summary 查看卷
// @Description 查看一个卷的详细信息
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data query requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/inspect [get]
func (r *ContainerController) VolumeInspect(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
data, err := r.container.VolumeInspect(request.ID)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, data)
}
// VolumeRemove
//
// @Summary 删除卷
// @Description 删除一个卷
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Param data body requests.ID true "request"
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/remove [post]
func (r *ContainerController) VolumeRemove(ctx http.Context) http.Response {
var request requests.ID
if sanitize := Sanitize(ctx, &request); sanitize != nil {
return sanitize
}
if err := r.container.VolumeRemove(request.ID); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}
// VolumePrune
//
// @Summary 清理卷
// @Description 清理无用的卷
// @Tags 容器
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
// @Router /panel/container/volume/prune [post]
func (r *ContainerController) VolumePrune(ctx http.Context) http.Response {
if err := r.container.VolumePrune(); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, nil)
}