CasaOS/route/v1/docker.go
link b3aa22605d Add authentication
Add user authentication module, Login page and initialization page.
Fixed the problem that the application could not start after the system restarted.
2021-10-22 16:49:09 +08:00

1192 lines
39 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 v1
import (
"bytes"
json2 "encoding/json"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/service/docker_base"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
HandshakeTimeout: time.Duration(time.Second * 5),
}
//打开docker的terminal
func DockerTerminal(c *gin.Context) {
col := c.DefaultQuery("cols", "100")
row := c.DefaultQuery("rows", "30")
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
defer conn.Close()
container := c.Param("id")
hr, err := service.Exec(container, row, col)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
// 关闭I/O流
defer hr.Close()
// 退出进程
defer func() {
hr.Conn.Write([]byte("exit\r"))
}()
go func() {
docker.WsWriterCopy(hr.Conn, conn)
}()
docker.WsReaderCopy(conn, hr.Conn)
}
//打开本机的ssh接口
func WsSsh(c *gin.Context) {
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
defer wsConn.Close()
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
client, _ := docker.NewSshClient()
defer client.Close()
ssConn, _ := docker.NewSshConn(cols, rows, client)
defer ssConn.Close()
quitChan := make(chan bool, 3)
var logBuff = new(bytes.Buffer)
go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
go ssConn.SendComboOutput(wsConn, quitChan)
go ssConn.SessionWait(quitChan)
<-quitChan
}
//安装进度推送
func SpeedPush(c *gin.Context) {
//token := c.Query("token")
//if len(token) == 0 || token != config.UserInfo.Token {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_AUTH_TOKEN, Message: oasis_err2.GetMsg(oasis_err2.ERROR_AUTH_TOKEN)})
// return
//}
//ws, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
//defer ws.Close()
//
//for {
// select {
// case msg := <-WSMSG:
// ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintln(msg)))
// }
//}
}
// @Summary 安装app(该接口需要post json数据)
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path int true "id"
// @Param port formData int true "主端口"
// @Param tcp formData string false "tcp端口"
// @Param udp formData string false "udp端口"
// @Param env formData string false "环境变量"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/{id} [post]
func InstallApp(c *gin.Context) {
appId := c.Param("id")
var appInfo model.ServerAppList
m := model.CustomizationPostData{}
c.BindJSON(&m)
const CUSTOM = "custom"
var dockerImage string
var dockerImageVersion string
//检查端口
if len(m.PortMap) > 0 && m.PortMap != "0" {
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
portMap, _ := strconv.Atoi(m.PortMap)
if !port2.IsPortAvailable(portMap, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
return
}
}
//if len(m.Port) == 0 || m.Port == "0" {
// m.Port = m.PortMap
//}
imageArr := strings.Split(m.Image, ":")
if len(imageArr) == 2 {
dockerImage = imageArr[0]
dockerImageVersion = imageArr[1]
} else {
dockerImage = m.Image
dockerImageVersion = "latest"
}
if m.Origin != "custom" {
appInfo = service.MyService.App().GetServerAppInfo(appId)
} else {
appInfo.Title = m.Label
appInfo.Description = m.Description
appInfo.Icon = m.Icon
appInfo.ScreenshotLink = model.Strings{}
appInfo.NetworkModel = m.NetworkModel
appInfo.Tags = model.Strings{}
appInfo.Tagline = ""
appInfo.Index = m.Index
}
for _, u := range m.Ports {
if u.Protocol == "udp" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "tcp" {
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "both" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
}
}
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
return
}
}
//restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
//if len(restart) > 0 {
//
//}
//
//privileged := c.PostForm("privileged") //是否处于特权模式
//if len(privileged) > 0 {
//
//}
id := uuid.NewV4().String()
var relyMap = make(map[string]string)
go func() {
installLog := model2.AppNotify{}
installLog.CustomId = id
installLog.State = 0
installLog.Message = "installing rely"
installLog.Speed = 10
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
service.MyService.Notify().AddLog(installLog)
if m.Origin != "custom" {
for _, plugin := range appInfo.Plugins {
if plugin == "mysql" {
mid := uuid.NewV4().String()
mc := docker_base.MysqlConfig{}
mc.DataBasePassword = random.RandomString(6, false)
mc.DataBaseDB = appInfo.Title
mc.DataBaseUser = "root"
mc.DataBasePort = "3306"
mysqlContainerId, err := docker_base.MysqlCreate(mc, mid, m.CpuShares, m.Memory)
if len(mysqlContainerId) > 0 && err == nil {
mc.DataBaseHost = mid
m.Envs = docker_base.MysqlFilter(mc, m.Envs)
rely := model2.RelyDBModel{}
rely.Type = types.RELY_TYPE_MYSQL
rely.ContainerId = mysqlContainerId
rely.CustomId = mid
rely.ContainerCustomId = id
var msqlConfig model2.MysqlConfigs
//结构体转换
copier.Copy(&msqlConfig, &mc)
rely.Config = msqlConfig
service.MyService.Rely().Create(rely)
relyMap["mysql"] = mid
} else {
docker_base.MysqlDelete(mysqlContainerId)
installLog.State = 0
installLog.Speed = 30
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
}
}
}
}
installLog.Speed = 50
installLog.Message = "pulling"
service.MyService.Notify().UpdateLog(installLog)
// step下载镜像
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
if err != nil {
installLog.State = 0
installLog.Speed = 70
installLog.Message = err.Error()
installLog.Type = types.NOTIFY_TYPE_ERROR
service.MyService.Notify().UpdateLog(installLog)
return
}
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
time.Sleep(time.Second)
}
//if {
//}
//step创建容器
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
// if err != nil {
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
// installLog.State = 0
// installLog.Speed = 75
// installLog.Type = types.NOTIFY_TYPE_ERROR
// installLog.Message = err.Error()
// service.MyService.Notify().UpdateLog(installLog)
// return
// }
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
installLog.ContainerId = containerId
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
installLog.State = 0
installLog.Speed = 80
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
installLog.Speed = 80
installLog.Message = "starting"
service.MyService.Notify().UpdateLog(installLog)
}
//step启动容器
err = service.MyService.Docker().DockerContainerStart(id)
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
installLog.State = 0
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Speed = 90
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
installLog.Speed = 90
if m.Origin != CUSTOM {
installLog.Message = "setting upnp"
} else {
installLog.Message = "nearing completion"
}
service.MyService.Notify().UpdateLog(installLog)
}
if m.Origin != CUSTOM {
//step:启动upnp
if m.EnableUPNP {
upnp, err := upnp2.Gateway()
if err == nil {
for _, p := range m.Ports {
if p.Protocol == "udp" {
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
upnp.LocalHost = ip_helper2.GetLoclIp()
tComment, _ := strconv.Atoi(p.CommendPort)
upnp.AddPortMapping(tComment, tComment, "UDP")
time.Sleep(time.Millisecond * 200)
} else if p.Protocol == "tcp" {
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
upnp.LocalHost = ip_helper2.GetLoclIp()
tComment, _ := strconv.Atoi(p.CommendPort)
upnp.AddPortMapping(tComment, tComment, "TCP")
time.Sleep(time.Millisecond * 200)
} else if p.Protocol == "both" {
upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
upnp.LocalHost = ip_helper2.GetLoclIp()
tComment, _ := strconv.Atoi(p.CommendPort)
upnp.AddPortMapping(tComment, tComment, "UDP")
time.Sleep(time.Millisecond * 200)
upnp.AddPortMapping(tComment, tComment, "TCP")
time.Sleep(time.Millisecond * 200)
}
}
}
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
installLog.State = 0
installLog.Speed = 95
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
installLog.Speed = 95
installLog.Message = "checking"
service.MyService.Notify().UpdateLog(installLog)
}
}
}
//step: 启动成功 检查容器状态确认启动成功
container, err := service.MyService.Docker().DockerContainerInfo(id)
if err != nil && container.ContainerJSONBase.State.Running {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
installLog.State = 0
installLog.Speed = 100
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
installLog.Speed = 100
installLog.Message = "installed"
service.MyService.Notify().UpdateLog(installLog)
}
rely := model.MapStrings{}
copier.Copy(&rely, &relyMap)
portsStr, _ := json2.Marshal(m.Ports)
envsStr, _ := json2.Marshal(m.Envs)
volumesStr, _ := json2.Marshal(m.Volumes)
devicesStr, _ := json2.Marshal(m.Devices)
//step: 保存数据到数据库
md := model2.AppListDBModel{
CustomId: id,
Title: appInfo.Title,
//ScreenshotLink: appInfo.ScreenshotLink,
Slogan: appInfo.Tagline,
Description: appInfo.Description,
//Tags: appInfo.Tags,
Icon: appInfo.Icon,
Version: dockerImageVersion,
ContainerId: containerId,
Image: dockerImage,
Index: appInfo.Index,
//Port: m.Port,
PortMap: m.PortMap,
Label: m.Label,
EnableUPNP: m.EnableUPNP,
Ports: string(portsStr),
Envs: string(envsStr),
Volumes: string(volumesStr),
Position: m.Position,
NetModel: appInfo.NetworkModel,
Restart: m.Restart,
CpuShares: m.CpuShares,
Memory: m.Memory,
Devices: string(devicesStr),
//Rely: rely,
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
}
//if appInfo.NetworkModel == "host" {
// m.PortMap = m.Port
//}
service.MyService.App().SaveContainer(md)
}()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
}
//// @Summary 自定义安装app(该接口需要post json数据)
//// @Produce application/json
//// @Accept application/json
//// @Tags app
//// @Param id path int true "id"
//// @Param port formData int true "主端口"
//// @Param tcp formData string false "tcp端口"
//// @Param udp formData string false "udp端口"
//// @Param env formData string false "环境变量"
//// @Security ApiKeyAuth
//// @Success 200 {string} string "ok"
//// @Router /app/install/{id} [post]
//func CustomInstallApp(c *gin.Context) {
// //appId := c.Param("id")
// // appInfo := service.MyService.App().GetServerAppInfo(appId)
//
// m := model.CustomizationPostData{}
// c.BindJSON(&m)
// //检查端口
// if len(m.PortMap) == 0 || m.PortMap == "0" {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// if len(m.Port) == 0 || m.Port == "0" {
// m.Port = m.PortMap
// }
//
// portMap, _ := strconv.Atoi(m.PortMap)
// if !port2.IsPortAvailable(portMap, "tcp") {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
// return
// }
//
// for _, u := range m.Udp {
// t, _ := strconv.Atoi(u.CommendPort)
// if !port2.IsPortAvailable(t, "udp") {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
// return
// }
// }
//
// for _, t := range m.Tcp {
// te, _ := strconv.Atoi(t.CommendPort)
// if !port2.IsPortAvailable(te, "tcp") {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + t.CommendPort})
// return
// }
// }
//
// //restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
// //if len(restart) > 0 {
// //
// //}
// //
// //privileged := c.PostForm("privileged") //是否处于特权模式
// //if len(privileged) > 0 {
// //
// //}
//
// err := service.MyService.Docker().DockerPullImage(m.Image)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PULL_IMAGE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PULL_IMAGE_ERROR)})
// }
//
// id := uuid.NewV4().String()
//
// var relyMap = make(map[string]string)
// go func() {
// installLog := model2.AppNotify{}
// installLog.CustomId = id
// installLog.State = 0
// installLog.Message = "installing rely"
// installLog.Speed = 30
// installLog.CreatedAt = time.Now()
// installLog.UpdatedAt = time.Now()
// service.MyService.Notify().AddLog(installLog)
//
// for !service.MyService.Docker().IsExistImage(m.Image) {
// time.Sleep(time.Second)
// }
//
// installLog.Speed = 50
// installLog.Message = "pulling"
// service.MyService.Notify().UpdateLog(installLog)
// // step下载镜像
//
// var cpd model.PostData
// copier.Copy(&cpd, &m)
// //step创建容器
// containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, id, cpd, m.NetworkModel, m.Image, "custom")
// installLog.ContainerId = containerId
// if err != nil {
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
// installLog.State = 0
// installLog.Speed = 80
// installLog.Message = err.Error()
// service.MyService.Notify().UpdateLog(installLog)
// return
// } else {
// //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
// installLog.Speed = 80
// installLog.Message = "starting"
// service.MyService.Notify().UpdateLog(installLog)
// }
//
// //step启动容器
// err = service.MyService.Docker().DockerContainerStart(id)
// if err != nil {
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
// installLog.State = 0
// installLog.Speed = 90
// installLog.Message = err.Error()
// service.MyService.Notify().UpdateLog(installLog)
// return
// } else {
// //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
// installLog.Speed = 90
// installLog.Message = "setting upnp"
// service.MyService.Notify().UpdateLog(installLog)
// }
//
// //step: 启动成功 检查容器状态确认启动成功
// containerStatus, err := service.MyService.Docker().DockerContainerInfo(id)
// if err != nil && containerStatus.ContainerJSONBase.State.Running {
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
// installLog.State = 0
// installLog.Speed = 100
// installLog.Message = err.Error()
// service.MyService.Notify().UpdateLog(installLog)
// return
// } else {
// //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
// installLog.Speed = 100
// installLog.Message = "installed"
// service.MyService.Notify().UpdateLog(installLog)
// }
//
// rely := model.MapStrings{}
//
// copier.Copy(&rely, &relyMap)
//
// //step: 保存数据到数据库
// md := model2.AppListDBModel{
// CustomId: id,
// Title: m.Label,
// // ScreenshotLink: []string,
// Slogan: "",
// Description: m.Description,
// // Tags: ,
// Icon: m.Icon,
// Version: m.Image,
// ContainerId: containerId,
// Image: m.Image,
// Index: "",
// Port: m.Port,
// PortMap: m.PortMap,
// Label: m.Label,
// EnableUPNP: m.EnableUPNP,
// UdpPorts: m.Udp,
// TcpPorts: m.Tcp,
// Envs: m.Envs,
// Volumes: m.Volumes,
// Position: m.Position,
// NetModel: m.NetworkModel,
// Restart: m.Restart,
// CpuShares: m.CpuShares,
// Memory: m.Memory,
// Devices: m.Devices,
// Rely: rely,
// Origin: "custom",
// }
// if m.NetworkModel == "host" {
// m.PortMap = m.Port
// }
// service.MyService.App().SaveContainer(md)
//
// }()
//
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
//
//}
// @Summary 卸载app
// @Produce application/json
// @Accept multipart/form-data
// @Tags app
// @Param id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/uninstall/{id} [delete]
func UnInstallApp(c *gin.Context) {
appId := c.Param("id")
if len(appId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.App().GetUninstallInfo(appId)
//step停止容器
err := service.MyService.Docker().DockerContainerStop(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
return
}
//step删除容器
err = service.MyService.Docker().DockerContainerRemove(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
return
}
//存在镜像正在使用的情况
// step删除镜像
service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)
//step: 删除本地数据
service.MyService.App().RemoveContainerById(appId)
if info.Origin != "custom" {
//step: 删除文件夹
service.MyService.App().DelAppConfigDir(appId)
//step: 删除install log
service.MyService.Notify().DelLog(appId)
// for k, v := range info.Rely {
//
// if k == "mysql" {
// docker_base.MysqlDelete(v)
// service.MyService.Rely().Delete(v)
// }
// }
//if info.EnableUPNP {
// upnp, err := upnp2.Gateway()
// if err == nil {
// for _, p := range info.Ports {
// if p.Protocol == "udp" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "UDP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "tcp" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "both" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "UDP")
//
// upnp.DelPortMapping(tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// }
// }
// }
//}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary 修改app状态
// @Produce application/json
// @Accept multipart/form-data
// @Tags app
// @Param id path string true "appid"
// @Param state query string false "是否停止 start stop restart"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/state/{id} [put]
func ChangAppState(c *gin.Context) {
appId := c.Param("id")
state := c.DefaultPostForm("state", "stop")
var err error
if state == "stop" {
err = service.MyService.Docker().DockerContainerStop(appId)
} else if state == "start" {
err = service.MyService.Docker().DockerContainerStart(appId)
} else if state == "restart" {
err = service.MyService.Docker().DockerContainerStop(appId)
err = service.MyService.Docker().DockerContainerStart(appId)
}
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
info, err := service.MyService.App().GetContainerInfo(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info.State})
}
// @Summary 查看容器日志
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/logs/{id} [get]
func ContainerLog(c *gin.Context) {
appId := c.Param("id")
log, _ := service.MyService.Docker().DockerContainerLog(appId)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
}
// @Summary 获取安装进度
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/speed/{id} [get]
func GetInstallSpeed(c *gin.Context) {
id := c.Param("id")
b := service.MyService.Notify().GetLog(id)
b.Id = b.CustomId
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
}
// @Summary 获取容器状态
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "容器id"
// @Param type query string false "type=1"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/state/{id} [get]
func GetContainerState(c *gin.Context) {
id := c.Param("id")
t := c.DefaultQuery("type", "0")
containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
if e != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: e.Error()})
return
}
var data = make(map[string]interface{})
data["state"] = containerInfo.State
if t == "1" {
appInfo := service.MyService.App().GetAppDBInfo(id)
data["app"] = appInfo
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary 更新设置
// @Produce application/json
// @Accept multipart/form-data
// @Tags app
// @Param id path string true "容器id"
// @Param shares formData string false "cpu权重"
// @Param mem formData string false "内存大小MB"
// @Param restart formData string false "重启策略"
// @Param label formData string false "应用名称"
// @Param position formData bool true "是否放到首页"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/update/{id}/setting [put]
func UpdateSetting(c *gin.Context) {
id := c.Param("id")
const CUSTOM = "custom"
m := model.CustomizationPostData{}
c.BindJSON(&m)
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
var cpd model.CustomizationPostData
copier.Copy(&cpd, &m)
appInfo := service.MyService.App().GetAppDBInfo(id)
var containerId string
containerId = appInfo.ContainerId
service.MyService.Docker().DockerContainerStop(id)
portMap, _ := strconv.Atoi(m.PortMap)
if !port2.IsPortAvailable(portMap, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
return
}
for _, u := range m.Ports {
if u.Protocol == "udp" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "tcp" {
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "both" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
}
}
//如果容器端口均未修改,这不进行处理
portsStr, _ := json2.Marshal(m.Ports)
envsStr, _ := json2.Marshal(m.Envs)
volumesStr, _ := json2.Marshal(m.Volumes)
devicesStr, _ := json2.Marshal(m.Devices)
if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
var newUUid = uuid.NewV4().String()
var err error
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetModel)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
// return
// }
containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
err = service.MyService.Docker().DockerContainerRemove(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
} else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
service.MyService.Docker().DockerContainerUpdate(cpd, id)
}
err := service.MyService.Docker().DockerContainerStart(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
//更新upnp
if m.Origin != CUSTOM {
//if appInfo.EnableUPNP != appInfo.EnableUPNP {
// if appInfo.EnableUPNP {
// upnp, err := upnp2.Gateway()
// if err == nil {
//
// for _, p := range appInfo.Ports {
// if p.Protocol == "udp" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.AddPortMapping(tComment, tComment, "UDP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "tcp" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.AddPortMapping(tComment, tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "both" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.AddPortMapping(tComment, tComment, "UDP")
// time.Sleep(time.Millisecond * 200)
//
// upnp.AddPortMapping(tComment, tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// }
// }
// }
// } else {
// upnp, err := upnp2.Gateway()
// if err == nil {
// for _, p := range appInfo.Ports {
// if p.Protocol == "udp" {
//
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "UDP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "tcp" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// } else if p.Protocol == "both" {
// upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
// upnp.LocalHost = ip_helper2.GetLoclIp()
// tComment, _ := strconv.Atoi(p.CommendPort)
// upnp.DelPortMapping(tComment, "UDP")
// time.Sleep(time.Millisecond * 200)
//
// upnp.DelPortMapping(tComment, "TCP")
// time.Sleep(time.Millisecond * 200)
// }
// }
// }
// }
//}
}
appInfo.ContainerId = containerId
appInfo.PortMap = m.PortMap
appInfo.Label = m.Label
appInfo.Index = m.Index
appInfo.Ports = string(portsStr)
appInfo.Envs = string(envsStr)
appInfo.Icon = m.Icon
appInfo.Volumes = string(volumesStr)
appInfo.Devices = string(devicesStr)
appInfo.NetModel = m.NetworkModel
appInfo.Position = m.Position
appInfo.EnableUPNP = m.EnableUPNP
appInfo.Restart = m.Restart
appInfo.Memory = m.Memory
appInfo.CpuShares = m.CpuShares
appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
service.MyService.App().UpdateApp(appInfo)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary 获取容器详情
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/info/{id} [get]
func ContainerInfo(c *gin.Context) {
appId := c.Param("id")
appInfo := service.MyService.App().GetAppDBInfo(appId)
containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
var cpuModel = "arm"
if cpu := service.MyService.ZiMa().GetCpuInfo(); len(cpu) > 0 {
if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
cpuModel = "intel"
} else if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "amd") > 0 {
cpuModel = "amd"
}
}
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
//todo 需要自定义错误
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
return
}
con := struct {
Status string `json:"status"`
StartedAt string `json:"started_at"`
CPUShares int64 `json:"cpu_shares"`
Memory int64 `json:"memory"`
Restart string `json:"restart"`
}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
data := make(map[string]interface{}, 5)
data["app"] = appInfo
data["cpu"] = cpuModel
data["memory"] = service.MyService.ZiMa().GetMemInfo().Total
data["container"] = json2.RawMessage(containerInfo)
data["info"] = con
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary 获取安装所需要的数据
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/config [get]
func GetDockerInstallConfig(c *gin.Context) {
networks := service.MyService.Docker().DockerNetworkModelList()
data := make(map[string]interface{}, 2)
list := []map[string]string{}
for _, network := range networks {
if network.Driver != "null" {
list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
}
}
data["networks"] = list
data["memory"] = service.MyService.ZiMa().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary 获取依赖数据
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "rely id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/rely/{id}/info [get]
func ContainerRelyInfo(c *gin.Context) {
id := c.Param("id")
appInfo := service.MyService.Rely().GetInfo(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: appInfo})
}
// @Summary 获取可更新数据
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/update/{id}/info [get]
func ContainerUpdateInfo(c *gin.Context) {
appId := c.Param("id")
appInfo := service.MyService.App().GetAppDBInfo(appId)
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
//todo 需要自定义错误
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
return
}
var port model.PortArrey
json2.Unmarshal([]byte(appInfo.Ports), &port)
var envs model.EnvArrey
json2.Unmarshal([]byte(appInfo.Envs), &envs)
var vol model.PathArrey
json2.Unmarshal([]byte(appInfo.Volumes), &vol)
var dir model.PathArrey
json2.Unmarshal([]byte(appInfo.Devices), &dir)
//volumesStr, _ := json2.Marshal(m.Volumes)
//devicesStr, _ := json2.Marshal(m.Devices)
m := model.CustomizationPostData{}
m.Index = appInfo.Index
m.Icon = appInfo.Icon
m.Ports = port
m.Image = appInfo.Image + ":" + appInfo.Version
m.Origin = appInfo.Origin
m.NetworkModel = appInfo.NetModel
m.Description = appInfo.Description
m.Label = appInfo.Label
m.PortMap = appInfo.PortMap
m.Devices = dir //appInfo.Devices
m.Envs = envs
m.Memory = info.HostConfig.Memory >> 20
m.CpuShares = info.HostConfig.CPUShares
m.Volumes = vol //appInfo.Volumes
m.Restart = info.HostConfig.RestartPolicy.Name
m.EnableUPNP = appInfo.EnableUPNP
m.Position = appInfo.Position
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
}
////准备安装(暂时不需要)
//func ReadyInstall(c *gin.Context) {
// _, tcp, udp := service.MyService.GetManifestJsonByRepo()
// data := make(map[string]interface{}, 2)
// if t := gjson.Parse(tcp).Array(); len(t) > 0 {
// //tcpList := []model.TcpPorts{}
// //e := json2.Unmarshal([]byte(tcp), tcpList)
// //if e!=nil {
// // return
// //}
// //for _, port := range tcpList {
// // if port.ContainerPort>0&&port.ExtranetPort {
// //
// // }
// //}
// var inarr []interface{}
// for _, result := range t {
//
// var p int
// ok := true
// for ok {
// p, _ = port.GetAvailablePort()
// ok = !port.IsPortAvailable(p)
// }
// pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
// inarr = append(inarr, pm)
// }
// data["tcp"] = inarr
// }
// if u := gjson.Parse(udp).Array(); len(u) > 0 {
// //udpList := []model.UdpPorts{}
// //e := json2.Unmarshal([]byte(udp), udpList)
// //if e != nil {
// // return
// //}
// var inarr []model.PortMap
// for _, result := range u {
// var p int
// ok := true
// for ok {
// p, _ = port.GetAvailablePort()
// ok = !port.IsPortAvailable(p)
// }
// pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
// inarr = append(inarr, pm)
// }
// data["udp"] = inarr
// }
// c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
//}