2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 17:17:13 +08:00

feat: 完善容器接口

This commit is contained in:
耗子
2024-03-16 15:29:00 +08:00
parent e7e5d4b283
commit 26d8aacabd
12 changed files with 4599 additions and 54 deletions

View File

@@ -5,10 +5,15 @@ import (
"strconv"
"strings"
"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"
commonrequests "panel/app/http/requests/common"
requests "panel/app/http/requests/container"
"panel/internal/services"
)
@@ -23,17 +28,61 @@ func NewContainerController() *ContainerController {
}
}
// 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())
}
return Success(ctx, containers)
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(containers) {
return Success(ctx, http.Json{
"total": 0,
"items": []types.Container{},
})
}
if endIndex > len(containers) {
endIndex = len(containers)
}
paged := containers[startIndex:endIndex]
if paged == nil {
paged = []types.Container{}
}
return Success(ctx, http.Json{
"total": len(containers),
"items": paged,
})
}
// 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("names"))
fields := strings.Fields(ctx.Request().Query("name"))
containers, err := r.container.ContainerListByNames(fields)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
@@ -42,6 +91,17 @@ func (r *ContainerController) ContainerSearch(ctx http.Context) http.Response {
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 {
@@ -125,6 +185,16 @@ func (r *ContainerController) ContainerCreate(ctx http.Context) http.Response {
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 {
@@ -138,6 +208,16 @@ func (r *ContainerController) ContainerRemove(ctx http.Context) http.Response {
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 {
@@ -151,6 +231,16 @@ func (r *ContainerController) ContainerStart(ctx http.Context) http.Response {
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 {
@@ -164,6 +254,16 @@ func (r *ContainerController) ContainerStop(ctx http.Context) http.Response {
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 {
@@ -177,6 +277,15 @@ func (r *ContainerController) ContainerRestart(ctx http.Context) http.Response {
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 {
@@ -190,6 +299,17 @@ func (r *ContainerController) ContainerPause(ctx http.Context) http.Response {
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 {
@@ -203,6 +323,16 @@ func (r *ContainerController) ContainerUnpause(ctx http.Context) http.Response {
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 {
@@ -217,6 +347,16 @@ func (r *ContainerController) ContainerInspect(ctx http.Context) http.Response {
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 {
@@ -230,6 +370,16 @@ func (r *ContainerController) ContainerKill(ctx http.Context) http.Response {
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 {
@@ -243,6 +393,16 @@ func (r *ContainerController) ContainerRename(ctx http.Context) http.Response {
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 {
@@ -257,6 +417,16 @@ func (r *ContainerController) ContainerStats(ctx http.Context) http.Response {
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 {
@@ -271,6 +441,16 @@ func (r *ContainerController) ContainerExist(ctx http.Context) http.Response {
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 {
@@ -285,6 +465,15 @@ func (r *ContainerController) ContainerLogs(ctx http.Context) http.Response {
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())
@@ -293,92 +482,517 @@ func (r *ContainerController) ContainerPrune(ctx http.Context) http.Response {
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())
}
return Success(ctx, networks)
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(networks) {
return Success(ctx, http.Json{
"total": 0,
"items": []types.NetworkResource{},
})
}
if endIndex > len(networks) {
endIndex = len(networks)
}
paged := networks[startIndex:endIndex]
if paged == nil {
paged = []types.NetworkResource{}
}
return Success(ctx, http.Json{
"total": len(networks),
"items": paged,
})
}
// 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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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": []image.Summary{},
})
}
if endIndex > len(images) {
endIndex = len(images)
}
paged := images[startIndex:endIndex]
if paged == nil {
paged = []image.Summary{}
}
return Success(ctx, http.Json{
"total": len(images),
"items": paged,
})
}
// 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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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())
}
return Success(ctx, volumes)
startIndex := (request.Page - 1) * request.Limit
endIndex := request.Page * request.Limit
if startIndex > len(volumes) {
return Success(ctx, http.Json{
"total": 0,
"items": []*volume.Volume{},
})
}
if endIndex > len(volumes) {
endIndex = len(volumes)
}
paged := volumes[startIndex:endIndex]
if paged == nil {
paged = []*volume.Volume{}
}
return Success(ctx, http.Json{
"total": len(volumes),
"items": paged,
})
}
// 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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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 {
return Success(ctx, nil)
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)
}

View File

@@ -0,0 +1,38 @@
package requests
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/contracts/validation"
)
type ImagePull struct {
Name string `form:"name" json:"name"`
Auth bool `form:"auth" json:"auth"`
Username string `form:"username" json:"username"`
Password string `form:"password" json:"password"`
}
func (r *ImagePull) Authorize(ctx http.Context) error {
return nil
}
func (r *ImagePull) Rules(ctx http.Context) map[string]string {
return map[string]string{
"name": "required|string",
"auth": "bool",
"username": "string",
"password": "string",
}
}
func (r *ImagePull) Messages(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *ImagePull) Attributes(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *ImagePull) PrepareForValidation(ctx http.Context, data validation.Data) error {
return nil
}

View File

@@ -0,0 +1,34 @@
package requests
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/contracts/validation"
)
type NetworkConnectDisConnect struct {
Network string `form:"network" json:"network"`
Container string `form:"container" json:"container"`
}
func (r *NetworkConnectDisConnect) Authorize(ctx http.Context) error {
return nil
}
func (r *NetworkConnectDisConnect) Rules(ctx http.Context) map[string]string {
return map[string]string{
"network": "required|string",
"container": "required|string",
}
}
func (r *NetworkConnectDisConnect) Messages(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *NetworkConnectDisConnect) Attributes(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *NetworkConnectDisConnect) PrepareForValidation(ctx http.Context, data validation.Data) error {
return nil
}

View File

@@ -0,0 +1,42 @@
package requests
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/contracts/validation"
)
type NetworkCreate struct {
Name string `form:"name" json:"name"`
Driver string `form:"driver" json:"driver"`
Ipv4 Network `form:"ipv4" json:"ipv4"`
Ipv6 Network `form:"ipv6" json:"ipv6"`
Labels []string `form:"labels" json:"labels"`
Options []string `form:"options" json:"options"`
}
func (r *NetworkCreate) Authorize(ctx http.Context) error {
return nil
}
func (r *NetworkCreate) Rules(ctx http.Context) map[string]string {
return map[string]string{
"name": "required|string",
"driver": "required|string|in:bridge,overlay,macvlan,ipvlan",
"ipv4": "required",
"ipv6": "required",
"labels": "slice",
"options": "slice",
}
}
func (r *NetworkCreate) Messages(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *NetworkCreate) Attributes(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *NetworkCreate) PrepareForValidation(ctx http.Context, data validation.Data) error {
return nil
}

View File

@@ -1,16 +1,23 @@
package requests
type ContainerPort struct {
ContainerStart int `json:"start"`
ContainerEnd int `json:"end"`
Host string `json:"host"`
HostStart int `json:"hostStart"`
HostEnd int `json:"hostEnd"`
Protocol string `json:"protocol"`
ContainerStart int `form:"start" json:"start"`
ContainerEnd int `form:"end" json:"end"`
Host string `form:"host" json:"host"`
HostStart int `form:"host_start" json:"host_start"`
HostEnd int `form:"host_end" json:"host_end"`
Protocol string `form:"protocol" json:"protocol"`
}
type ContainerVolume struct {
Host string `json:"host"`
Container string `json:"container"`
Mode string `json:"mode"`
Host string `form:"start" json:"host"`
Container string `form:"start" json:"container"`
Mode string `form:"start" json:"mode"`
}
type Network struct {
Enabled bool `form:"enabled" json:"enabled"`
Gateway string `form:"gateway" json:"gateway"`
IPRange string `form:"ip_range" json:"ip_range"`
Subnet string `form:"subnet" json:"subnet"`
}

View File

@@ -0,0 +1,38 @@
package requests
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/contracts/validation"
)
type VolumeCreate struct {
Name string `form:"name" json:"name"`
Driver string `form:"driver" json:"driver"`
Labels []string `form:"labels" json:"labels"`
Options []string `form:"options" json:"options"`
}
func (r *VolumeCreate) Authorize(ctx http.Context) error {
return nil
}
func (r *VolumeCreate) Rules(ctx http.Context) map[string]string {
return map[string]string{
"name": "required|string",
"driver": "required|string|in:local",
"labels": "slice",
"options": "slice",
}
}
func (r *VolumeCreate) Messages(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *VolumeCreate) Attributes(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *VolumeCreate) PrepareForValidation(ctx http.Context, data validation.Data) error {
return nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -180,6 +180,11 @@ definitions:
updated_at:
type: string
type: object
panel_app_http_requests_container.ID:
properties:
id:
type: string
type: object
panel_app_http_requests_plugins_rsync.Update:
properties:
auth_user:
@@ -288,6 +293,88 @@ definitions:
website_id:
type: integer
type: object
requests.ContainerCreate:
properties:
auto_remove:
type: boolean
command:
items:
type: string
type: array
cpu_shares:
type: integer
cpus:
type: integer
entrypoint:
items:
type: string
type: array
env:
items:
type: string
type: array
image:
type: string
labels:
items:
type: string
type: array
memory:
type: integer
name:
type: string
network:
type: string
open_stdin:
type: boolean
ports:
items:
$ref: '#/definitions/requests.ContainerPort'
type: array
privileged:
type: boolean
publish_all_ports:
type: boolean
restart_policy:
type: string
tty:
type: boolean
volumes:
items:
$ref: '#/definitions/requests.ContainerVolume'
type: array
type: object
requests.ContainerPort:
properties:
end:
type: integer
host:
type: string
host_end:
type: integer
host_start:
type: integer
protocol:
type: string
start:
type: integer
type: object
requests.ContainerRename:
properties:
id:
type: string
name:
type: string
type: object
requests.ContainerVolume:
properties:
container:
type: string
host:
type: string
mode:
type: string
type: object
requests.Copy:
properties:
new:
@@ -340,6 +427,17 @@ definitions:
path:
type: string
type: object
requests.ImagePull:
properties:
auth:
type: boolean
name:
type: string
password:
type: string
username:
type: string
type: object
requests.Login:
properties:
password:
@@ -354,6 +452,43 @@ definitions:
old:
type: string
type: object
requests.Network:
properties:
enabled:
type: boolean
gateway:
type: string
ip_range:
type: string
subnet:
type: string
type: object
requests.NetworkConnectDisConnect:
properties:
container:
type: string
network:
type: string
type: object
requests.NetworkCreate:
properties:
driver:
type: string
ipv4:
$ref: '#/definitions/requests.Network'
ipv6:
$ref: '#/definitions/requests.Network'
labels:
items:
type: string
type: array
name:
type: string
options:
items:
type: string
type: array
type: object
requests.NotExist:
properties:
path:
@@ -479,6 +614,21 @@ definitions:
kid:
type: string
type: object
requests.VolumeCreate:
properties:
driver:
type: string
labels:
items:
type: string
type: array
name:
type: string
options:
items:
type: string
type: array
type: object
info:
contact:
email: i@haozi.net
@@ -976,6 +1126,729 @@ paths:
summary: 更新 ACME 用户
tags:
- 证书管理
/panel/container/create:
post:
consumes:
- application/json
description: 创建一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.ContainerCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 创建容器
tags:
- 容器
/panel/container/exist:
get:
description: 检查一个容器是否存在
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 检查容器是否存在
tags:
- 容器
/panel/container/image/exist:
get:
description: 检查一个镜像是否存在
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 检查镜像是否存在
tags:
- 容器
/panel/container/image/inspect:
get:
description: 查看一个镜像的详细信息
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看镜像
tags:
- 容器
/panel/container/image/list:
get:
description: 获取所有镜像列表
parameters:
- in: query
name: limit
type: integer
- in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 获取镜像列表
tags:
- 容器
/panel/container/image/prune:
post:
description: 清理无用的镜像
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 清理镜像
tags:
- 容器
/panel/container/image/pull:
post:
consumes:
- application/json
description: 拉取一个镜像
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.ImagePull'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 拉取镜像
tags:
- 容器
/panel/container/image/remove:
post:
description: 删除一个镜像
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 删除镜像
tags:
- 容器
/panel/container/inspect:
get:
description: 查看一个容器的详细信息
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看容器
tags:
- 容器
/panel/container/kill:
post:
description: 杀死一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 杀死容器
tags:
- 容器
/panel/container/list:
get:
description: 获取所有容器列表
parameters:
- in: query
name: limit
type: integer
- in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 获取容器列表
tags:
- 容器
/panel/container/logs:
get:
description: 查看一个容器的日志
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看容器日志
tags:
- 容器
/panel/container/network/connect:
post:
consumes:
- application/json
description: 连接一个容器到一个网络
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.NetworkConnectDisConnect'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 连接容器到网络
tags:
- 容器
/panel/container/network/create:
post:
consumes:
- application/json
description: 创建一个网络
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.NetworkCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 创建网络
tags:
- 容器
/panel/container/network/disconnect:
post:
consumes:
- application/json
description: 从一个网络断开一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.NetworkConnectDisConnect'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 从网络断开容器
tags:
- 容器
/panel/container/network/exist:
get:
description: 检查一个网络是否存在
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 检查网络是否存在
tags:
- 容器
/panel/container/network/inspect:
get:
description: 查看一个网络的详细信息
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看网络
tags:
- 容器
/panel/container/network/list:
get:
description: 获取所有网络列表
parameters:
- in: query
name: limit
type: integer
- in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 获取网络列表
tags:
- 容器
/panel/container/network/prune:
post:
description: 清理无用的网络
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 清理网络
tags:
- 容器
/panel/container/network/remove:
post:
description: 删除一个网络
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 删除网络
tags:
- 容器
/panel/container/prune:
post:
description: 清理无用的容器
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 清理容器
tags:
- 容器
/panel/container/remove:
post:
description: 删除一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 删除容器
tags:
- 容器
/panel/container/rename:
post:
description: 重命名一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.ContainerRename'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 重命名容器
tags:
- 容器
/panel/container/restart:
post:
description: 重启一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 重启容器
tags:
- 容器
/panel/container/search:
get:
description: 根据容器名称搜索容器
parameters:
- description: 容器名称
in: query
name: name
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 搜索容器
tags:
- 容器
/panel/container/start:
post:
description: 启动一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 启动容器
tags:
- 容器
/panel/container/stats:
get:
description: 查看一个容器的状态信息
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看容器状态
tags:
- 容器
/panel/container/stop:
post:
description: 停止一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 停止容器
tags:
- 容器
/panel/container/unpause:
post:
description: 取消暂停一个容器
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 取消暂停容器
tags:
- 容器
/panel/container/volume/create:
post:
consumes:
- application/json
description: 创建一个卷
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.VolumeCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 创建卷
tags:
- 容器
/panel/container/volume/exist:
get:
description: 检查一个卷是否存在
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 检查卷是否存在
tags:
- 容器
/panel/container/volume/inspect:
get:
description: 查看一个卷的详细信息
parameters:
- in: query
name: id
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 查看卷
tags:
- 容器
/panel/container/volume/list:
get:
description: 获取所有卷列表
parameters:
- in: query
name: limit
type: integer
- in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 获取卷列表
tags:
- 容器
/panel/container/volume/prune:
post:
description: 清理无用的卷
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 清理卷
tags:
- 容器
/panel/container/volume/remove:
post:
description: 删除一个卷
parameters:
- description: request
in: body
name: data
required: true
schema:
$ref: '#/definitions/panel_app_http_requests_container.ID'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
security:
- BearerToken: []
summary: 删除卷
tags:
- 容器
/panel/file/archive:
post:
consumes:

View File

@@ -6,6 +6,8 @@ import (
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
requests "panel/app/http/requests/container"
)
type Container interface {
@@ -27,7 +29,7 @@ type Container interface {
ContainerLogs(id string) (string, error)
ContainerPrune() error
NetworkList() ([]types.NetworkResource, error)
NetworkCreate(name string) error
NetworkCreate(config requests.NetworkCreate) (string, error)
NetworkRemove(id string) error
NetworkExist(name string) (bool, error)
NetworkInspect(id string) (types.NetworkResource, error)
@@ -35,16 +37,16 @@ type Container interface {
NetworkDisconnect(networkID string, containerID string) error
NetworkPrune() error
ImageList() ([]image.Summary, error)
ImageExist(reference string) (bool, error)
ImagePull(reference string) error
ImageRemove(imageID string) error
ImageExist(id string) (bool, error)
ImagePull(config requests.ImagePull) error
ImageRemove(id string) error
ImagePrune() error
ImageInspect(imageID string) (types.ImageInspect, error)
ImageInspect(id string) (types.ImageInspect, error)
VolumeList() ([]*volume.Volume, error)
VolumeCreate(name string, options, labels map[string]string) (volume.Volume, error)
VolumeCreate(config requests.VolumeCreate) (volume.Volume, error)
VolumeExist(name string) (bool, error)
VolumeInspect(volumeID string) (volume.Volume, error)
VolumeRemove(volumeID string) error
VolumeInspect(id string) (volume.Volume, error)
VolumeRemove(id string) error
VolumePrune() error
SliceToMap(slice []string) map[string]string
}

View File

@@ -2,6 +2,7 @@ package services
import (
"context"
"encoding/base64"
"io"
"strings"
@@ -10,8 +11,12 @@ import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/goravel/framework/support/json"
requests "panel/app/http/requests/container"
)
type Container struct {
@@ -167,12 +172,37 @@ func (r *Container) NetworkList() ([]types.NetworkResource, error) {
}
// NetworkCreate 创建网络
func (r *Container) NetworkCreate(name string) error {
_, err := r.client.NetworkCreate(context.Background(), name, types.NetworkCreate{
Driver: "bridge",
})
func (r *Container) NetworkCreate(config requests.NetworkCreate) (string, error) {
var ipamConfigs []network.IPAMConfig
if config.Ipv4.Enabled {
ipamConfigs = append(ipamConfigs, network.IPAMConfig{
Subnet: config.Ipv4.Subnet,
Gateway: config.Ipv4.Gateway,
IPRange: config.Ipv4.IPRange,
})
}
if config.Ipv6.Enabled {
ipamConfigs = append(ipamConfigs, network.IPAMConfig{
Subnet: config.Ipv6.Subnet,
Gateway: config.Ipv6.Gateway,
IPRange: config.Ipv6.IPRange,
})
}
return err
options := types.NetworkCreate{
EnableIPv6: config.Ipv6.Enabled,
Driver: config.Driver,
Options: r.SliceToMap(config.Options),
Labels: r.SliceToMap(config.Labels),
}
if len(ipamConfigs) > 0 {
options.IPAM = &network.IPAM{
Config: ipamConfigs,
}
}
resp, err := r.client.NetworkCreate(context.Background(), config.Name, options)
return resp.ID, err
}
// NetworkRemove 删除网络
@@ -198,13 +228,13 @@ func (r *Container) NetworkInspect(id string) (types.NetworkResource, error) {
}
// NetworkConnect 连接网络
func (r *Container) NetworkConnect(id string, containerID string) error {
return r.client.NetworkConnect(context.Background(), id, containerID, nil)
func (r *Container) NetworkConnect(networkID string, containerID string) error {
return r.client.NetworkConnect(context.Background(), networkID, containerID, nil)
}
// NetworkDisconnect 断开网络
func (r *Container) NetworkDisconnect(id string, containerID string) error {
return r.client.NetworkDisconnect(context.Background(), id, containerID, true)
func (r *Container) NetworkDisconnect(networkID string, containerID string) error {
return r.client.NetworkDisconnect(context.Background(), networkID, containerID, true)
}
// NetworkPrune 清理未使用的网络
@@ -221,9 +251,9 @@ func (r *Container) ImageList() ([]image.Summary, error) {
}
// ImageExist 判断镜像是否存在
func (r *Container) ImageExist(str string) (bool, error) {
func (r *Container) ImageExist(id string) (bool, error) {
var options types.ImageListOptions
options.Filters = filters.NewArgs(filters.Arg("reference", str))
options.Filters = filters.NewArgs(filters.Arg("reference", id))
images, err := r.client.ImageList(context.Background(), options)
if err != nil {
return false, err
@@ -233,8 +263,22 @@ func (r *Container) ImageExist(str string) (bool, error) {
}
// ImagePull 拉取镜像
func (r *Container) ImagePull(str string) error {
_, err := r.client.ImagePull(context.Background(), str, types.ImagePullOptions{})
func (r *Container) ImagePull(config requests.ImagePull) error {
options := types.ImagePullOptions{}
if config.Auth {
authConfig := registry.AuthConfig{
Username: config.Username,
Password: config.Password,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return err
}
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
options.RegistryAuth = authStr
}
_, err := r.client.ImagePull(context.Background(), config.Name, options)
return err
}
@@ -266,19 +310,19 @@ func (r *Container) VolumeList() ([]*volume.Volume, error) {
}
// VolumeCreate 创建存储卷
func (r *Container) VolumeCreate(name string, options, labels map[string]string) (volume.Volume, error) {
func (r *Container) VolumeCreate(config requests.VolumeCreate) (volume.Volume, error) {
return r.client.VolumeCreate(context.Background(), volume.CreateOptions{
Name: name,
Driver: "local",
DriverOpts: options,
Labels: labels,
Name: config.Name,
Driver: config.Driver,
DriverOpts: r.SliceToMap(config.Options),
Labels: r.SliceToMap(config.Labels),
})
}
// VolumeExist 判断存储卷是否存在
func (r *Container) VolumeExist(name string) (bool, error) {
func (r *Container) VolumeExist(id string) (bool, error) {
var options volume.ListOptions
options.Filters = filters.NewArgs(filters.Arg("name", name))
options.Filters = filters.NewArgs(filters.Arg("name", id))
volumes, err := r.client.VolumeList(context.Background(), options)
if err != nil {
return false, err
@@ -312,5 +356,6 @@ func (r *Container) SliceToMap(slice []string) map[string]string {
m[sps[0]] = sps[1]
}
}
return m
}

View File

@@ -128,7 +128,7 @@ func Api() {
r.Post("kill", containerController.ContainerKill)
r.Post("rename", containerController.ContainerRename)
r.Get("stats", containerController.ContainerStats)
r.Post("exist", containerController.ContainerExist)
r.Get("exist", containerController.ContainerExist)
r.Get("logs", containerController.ContainerLogs)
r.Post("prune", containerController.ContainerPrune)
@@ -136,7 +136,7 @@ func Api() {
r.Get("list", containerController.NetworkList)
r.Post("create", containerController.NetworkCreate)
r.Post("remove", containerController.NetworkRemove)
r.Post("exist", containerController.NetworkExist)
r.Get("exist", containerController.NetworkExist)
r.Get("inspect", containerController.NetworkInspect)
r.Post("connect", containerController.NetworkConnect)
r.Post("disconnect", containerController.NetworkDisconnect)
@@ -145,7 +145,7 @@ func Api() {
r.Prefix("image").Group(func(r route.Router) {
r.Get("list", containerController.ImageList)
r.Post("exist", containerController.ImageExist)
r.Get("exist", containerController.ImageExist)
r.Post("pull", containerController.ImagePull)
r.Post("remove", containerController.ImageRemove)
r.Post("prune", containerController.ImagePrune)
@@ -155,7 +155,7 @@ func Api() {
r.Prefix("volume").Group(func(r route.Router) {
r.Get("list", containerController.VolumeList)
r.Post("create", containerController.VolumeCreate)
r.Post("exist", containerController.VolumeExist)
r.Get("exist", containerController.VolumeExist)
r.Get("inspect", containerController.VolumeInspect)
r.Post("remove", containerController.VolumeRemove)
r.Post("prune", containerController.VolumePrune)