From 441f26ba56b13c1b778b5311e9ce38b60b83e4e8 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 15 Nov 2022 22:16:40 -0500 Subject: [PATCH] wip --- go.mod | 2 +- go.sum | 10 + model/app.go | 128 ----- model/category.go | 23 - model/docker.go | 24 - model/manifest.go | 133 ----- model/sys_common.go | 6 +- pkg/config/init.go | 13 +- pkg/docker/emum.go | 3 - pkg/docker/helper.go | 402 --------------- pkg/docker/volumes.go | 11 - pkg/docker/volumes_test.go | 10 - pkg/sqlite/db.go | 7 +- pkg/utils/port/port.go | 68 --- pkg/utils/port/port_test.go | 18 - route/route.go | 6 - route/v1/app.go | 355 ------------- service/app.go | 480 ----------------- service/casa.go | 248 +-------- service/docker.go | 962 ----------------------------------- service/docker_test.go | 50 -- service/model/o_container.go | 78 --- service/service.go | 28 +- 23 files changed, 29 insertions(+), 3036 deletions(-) delete mode 100644 model/app.go delete mode 100644 model/category.go delete mode 100644 model/docker.go delete mode 100644 model/manifest.go delete mode 100644 pkg/docker/emum.go delete mode 100644 pkg/docker/helper.go delete mode 100644 pkg/docker/volumes.go delete mode 100644 pkg/docker/volumes_test.go delete mode 100644 pkg/utils/port/port.go delete mode 100644 pkg/utils/port/port_test.go delete mode 100644 route/v1/app.go delete mode 100644 service/app.go delete mode 100644 service/docker.go delete mode 100644 service/docker_test.go delete mode 100644 service/model/o_container.go diff --git a/go.mod b/go.mod index b6ca74b..e098c5a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d - github.com/IceWhaleTech/CasaOS-Common v0.3.7-5 + github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221116011801-d8017d2ff420 github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 github.com/Microsoft/go-winio v0.5.0 // indirect github.com/ambelovsky/go-structs v1.1.0 // indirect diff --git a/go.sum b/go.sum index 2443326..f5fe5f5 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,16 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= github.com/IceWhaleTech/CasaOS-Common v0.3.7-5 h1:CLPeUaFoGCA3WNnOWxtdFbBmLIg7odCQglZJ/c878uU= github.com/IceWhaleTech/CasaOS-Common v0.3.7-5/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= +github.com/IceWhaleTech/CasaOS-Common v0.3.8-alpha1.0.20221115211401-d8d4e6d34dba h1:nR7WopK3GV8P85cLl1nc+FgQ96lY0JHGgxJqj2jHdr8= +github.com/IceWhaleTech/CasaOS-Common v0.3.8-alpha1.0.20221115211401-d8d4e6d34dba/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221115211401-d8d4e6d34dba h1:T+GUchTbGC5GcwnQhg+lIlwQr78Eh2wsWndujFQDPbE= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221115211401-d8d4e6d34dba/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221115215907-b2c57ac643f4 h1:XKj5y1u8FGHldch5/MOlbkeyXqW7am3nnHfUPBKc230= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221115215907-b2c57ac643f4/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221116004806-159ec400f70f h1:zRL+qfjnUDMBWvhMULH2JVZb+Y6lvAzAnGFjBO1pX+0= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221116004806-159ec400f70f/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221116011801-d8017d2ff420 h1:4M+5/doXry6Y8iKS3Cl/SLJIZPrRH1cmwQfMrj57T3I= +github.com/IceWhaleTech/CasaOS-Common v0.3.9-0.20221116011801-d8017d2ff420/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 h1:2tQQo85+jzbbjqIsKKn77QlAA73bc7vZsVCFvWnK4mg= github.com/IceWhaleTech/CasaOS-Gateway v0.3.6/go.mod h1:hnZwGUzcOyiufMpVO7l3gu2gAm6Ws4TY4Nlj3kMshXA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= diff --git a/model/app.go b/model/app.go deleted file mode 100644 index 58b69c2..0000000 --- a/model/app.go +++ /dev/null @@ -1,128 +0,0 @@ -package model - -import ( - "database/sql/driver" - "encoding/json" - "time" -) - -type ServerAppListCollection struct { - List []ServerAppList `json:"list"` - Recommend []ServerAppList `json:"recommend"` - Community []ServerAppList `json:"community"` - Version string `json:"version"` -} - -// @tiger - 对于用于出参的数据结构,静态信息(例如 title)和 -// 动态信息(例如 state、query_count)应该划分到不同的数据结构中 -// -// 这样的好处是 -// 1 - 多次获取动态信息时可以减少出参复杂度,因为静态信息只获取一次就好 -// 2 - 在未来的迭代中,可以降低维护成本(所有字段都展开放在一个层级维护成本略高) -// -// 另外,一些针对性字段,例如 Docker 相关的,可以用 map 来保存。 -// 这样在未来增加多态 App,例如 Snap,不需要维护多个结构,或者一个结构保存不必要的字段 -type ServerAppList struct { - Id uint `gorm:"column:id;primary_key" json:"id"` - Title string `json:"title"` - Description string `json:"description"` - Tagline string `json:"tagline"` - Tags Strings `gorm:"type:json" json:"tags"` - Icon string `json:"icon"` - ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"` - Category string `json:"category"` - CategoryId int `json:"category_id"` - CategoryFont string `json:"category_font"` - PortMap string `json:"port_map"` - ImageVersion string `json:"image_version"` - Tip string `json:"tip"` - Envs EnvArray `json:"envs"` - Ports PortArray `json:"ports"` - Volumes PathArray `json:"volumes"` - Devices PathArray `json:"devices"` - NetworkModel string `json:"network_model"` - Image string `json:"image"` - Index string `json:"index"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - State int `json:"state"` - Author string `json:"author"` - MinMemory int `json:"min_memory"` - MinDisk int `json:"min_disk"` - MaxMemory uint64 `json:"max_memory"` - Thumbnail string `json:"thumbnail"` - Healthy string `json:"healthy"` - Plugins Strings `json:"plugins"` - Origin string `json:"origin"` - Type int `json:"type"` - QueryCount int `json:"query_count"` - Developer string `json:"developer"` - HostName string `json:"host_name"` - Privileged bool `json:"privileged"` - CapAdd Strings `json:"cap_add"` - Cmd Strings `json:"cmd"` -} - -type Ports struct { - ContainerPort uint `json:"container_port"` - CommendPort int `json:"commend_port"` - Desc string `json:"desc"` - Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑 -} - -type Volume struct { - ContainerPath string `json:"container_path"` - Path string `json:"path"` - Desc string `json:"desc"` - Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑 -} - -type Envs struct { - Name string `json:"name"` - Value string `json:"value"` - Desc string `json:"desc"` - Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑 -} - -type Devices struct { - ContainerPath string `json:"container_path"` - Path string `json:"path"` - Desc string `json:"desc"` - Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑 -} - -type configures struct { - TcpPorts []Ports `json:"tcp_ports"` - UdpPorts []Ports `json:"udp_ports"` - Envs []Envs `json:"envs"` - Volumes []Volume `json:"volumes"` - Devices []Devices `json:"devices"` -} - -/****************使gorm支持[]string结构*******************/ -type Strings []string - -func (c Strings) Value() (driver.Value, error) { - b, err := json.Marshal(c) - return string(b), err -} - -func (c *Strings) Scan(input interface{}) error { - return json.Unmarshal(input.([]byte), c) -} - -/****************使gorm支持[]string结构*******************/ - -/****************使gorm支持[]string结构*******************/ -type MapStrings []map[string]string - -func (c MapStrings) Value() (driver.Value, error) { - b, err := json.Marshal(c) - return string(b), err -} - -func (c *MapStrings) Scan(input interface{}) error { - return json.Unmarshal(input.([]byte), c) -} - -/****************使gorm支持[]string结构*******************/ diff --git a/model/category.go b/model/category.go deleted file mode 100644 index 3005491..0000000 --- a/model/category.go +++ /dev/null @@ -1,23 +0,0 @@ -/* - * @Author: link a624669980@163.com - * @Date: 2022-05-16 17:37:08 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-13 10:46:38 - * @FilePath: /CasaOS/model/category.go - * @Description: - */ -package model - -type ServerCategoryList struct { - Version string `json:"version"` - Item []CategoryList `json:"item"` -} -type CategoryList struct { - Id uint `gorm:"column:id;primary_key" json:"id"` - //CreatedAt time.Time `json:"created_at"` - // - //UpdatedAt time.Time `json:"updated_at"` - Font string `json:"font"` // @tiger - 如果这个和前端有关,应该不属于后端的出参范围,而是前端去界定 - Name string `json:"name"` - Count uint `json:"count"` // @tiger - count 属于动态信息,应该单独放在一个出参结构中(原因见另外一个关于 静态/动态 出参的注释) -} diff --git a/model/docker.go b/model/docker.go deleted file mode 100644 index 34412cd..0000000 --- a/model/docker.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * @Author: LinkLeong link@icewhale.com - * @Date: 2021-12-08 18:10:25 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-13 10:49:16 - * @FilePath: /CasaOS/model/docker.go - * @Description: - * @Website: https://www.casaos.io - * Copyright (c) 2022 by icewhale, All Rights Reserved. - */ -package model - -type DockerStatsModel struct { - Icon string `json:"icon"` - Title string `json:"title"` - Data interface{} `json:"data"` - Previous interface{} `json:"previous"` -} - -// reference - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file -type DockerDaemonConfigurationModel struct { - // e.g. `/var/lib/docker` - Root string `json:"data-root,omitempty"` -} diff --git a/model/manifest.go b/model/manifest.go deleted file mode 100644 index 0888fb0..0000000 --- a/model/manifest.go +++ /dev/null @@ -1,133 +0,0 @@ -package model - -import ( - "database/sql/driver" - "encoding/json" -) - -type TcpPorts struct { - Desc string `json:"desc"` - ContainerPort int `json:"container_port"` -} -type UdpPorts struct { - Desc string `json:"desc"` - ContainerPort int `json:"container_port"` -} - -/*******************使用gorm支持json************************************/ - -type PortMap struct { - ContainerPort string `json:"container"` - CommendPort string `json:"host"` - Protocol string `json:"protocol"` - Desc string `json:"desc"` - Type int `json:"type"` -} - -type PortArray []PortMap - -// Value 实现方法 -func (p PortArray) Value() (driver.Value, error) { - return json.Marshal(p) -} - -// Scan 实现方法 -func (p *PortArray) Scan(input interface{}) error { - return json.Unmarshal(input.([]byte), p) -} - -/************************************************************************/ - -/*******************使用gorm支持json************************************/ - -type Env struct { - Name string `json:"container"` - Value string `json:"host"` - Desc string `json:"desc"` - Type int `json:"type"` -} - -type JSON json.RawMessage - -type EnvArray []Env - -// Value 实现方法 -func (p EnvArray) Value() (driver.Value, error) { - return json.Marshal(p) - //return .MarshalJSON() -} - -// Scan 实现方法 -func (p *EnvArray) Scan(input interface{}) error { - return json.Unmarshal(input.([]byte), p) -} - -/************************************************************************/ - -/*******************使用gorm支持json************************************/ - -type PathMap struct { - ContainerPath string `json:"container"` - Path string `json:"host"` - Type int `json:"type"` - Desc string `json:"desc"` -} - -type PathArray []PathMap - -// Value 实现方法 -func (p PathArray) Value() (driver.Value, error) { - return json.Marshal(p) -} - -// Scan 实现方法 -func (p *PathArray) Scan(input interface{}) error { - return json.Unmarshal(input.([]byte), p) -} - -/************************************************************************/ - -//type PostData struct { -// Envs EnvArrey `json:"envs,omitempty"` -// Udp PortArrey `json:"udp_ports"` -// Tcp PortArrey `json:"tcp_ports"` -// Volumes PathArrey `json:"volumes"` -// Devices PathArrey `json:"devices"` -// Port string `json:"port,omitempty"` -// PortMap string `json:"port_map"` -// CpuShares int64 `json:"cpu_shares,omitempty"` -// Memory int64 `json:"memory,omitempty"` -// Restart string `json:"restart,omitempty"` -// EnableUPNP bool `json:"enable_upnp"` -// Label string `json:"label"` -// Position bool `json:"position"` -//} - -type CustomizationPostData struct { - ContainerName string `json:"container_name"` - CustomId string `json:"custom_id"` - Origin string `json:"origin"` - NetworkModel string `json:"network_model"` - Index string `json:"index"` - Icon string `json:"icon"` - Image string `json:"image"` - Envs EnvArray `json:"envs"` - Ports PortArray `json:"ports"` - Volumes PathArray `json:"volumes"` - Devices PathArray `json:"devices"` - //Port string `json:"port,omitempty"` - PortMap string `json:"port_map"` - CpuShares int64 `json:"cpu_shares"` - Memory int64 `json:"memory"` - Restart string `json:"restart"` - EnableUPNP bool `json:"enable_upnp"` - Label string `json:"label"` - Description string `json:"description"` - Position bool `json:"position"` - HostName string `json:"host_name"` - Privileged bool `json:"privileged"` - CapAdd []string `json:"cap_add"` - Cmd []string `json:"cmd"` - Protocol string `json:"protocol"` - Host string `json:"host"` -} diff --git a/model/sys_common.go b/model/sys_common.go index 098ba97..6e56e25 100644 --- a/model/sys_common.go +++ b/model/sys_common.go @@ -14,7 +14,7 @@ import "time" // 系统配置 type SysInfoModel struct { - Name string //系统名称 + Name string // 系统名称 } // 服务配置 @@ -66,10 +66,6 @@ type SystemConfig struct { ConfigPath string `json:"config_path"` } -type CasaOSGlobalVariables struct { - AppChange bool -} - type FileSetting struct { ShareDir []string `json:"share_dir" delim:"|"` DownloadDir string `json:"download_dir"` diff --git a/pkg/config/init.go b/pkg/config/init.go index b2de00f..abd6068 100644 --- a/pkg/config/init.go +++ b/pkg/config/init.go @@ -31,23 +31,20 @@ var AppInfo = &model.APPModel{} var CommonInfo = &model.CommonModel{} -//var RedisInfo = &model.RedisModel{} +// var RedisInfo = &model.RedisModel{} // server相关 var ServerInfo = &model.ServerModel{} var SystemConfigInfo = &model.SystemConfig{} -var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{} - var FileSettingInfo = &model.FileSetting{} var Cfg *ini.File // 初始化设置,获取系统的部分信息。 func InitSetup(config string) { - - var configDir = USERCONFIGURL + configDir := USERCONFIGURL if len(config) > 0 { configDir = config } @@ -55,7 +52,7 @@ func InitSetup(config string) { configDir = "./conf/conf.conf" } var err error - //读取文件 + // 读取文件 Cfg, err = ini.Load(configDir) if err != nil { Cfg, err = ini.Load("/etc/casaos.conf") @@ -68,7 +65,7 @@ func InitSetup(config string) { } } mapTo("app", AppInfo) - //mapTo("redis", RedisInfo) + // mapTo("redis", RedisInfo) mapTo("server", ServerInfo) mapTo("system", SystemConfigInfo) mapTo("file", FileSettingInfo) @@ -91,7 +88,6 @@ func InitSetup(config string) { } Cfg.SaveTo(configDir) // AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd() - } // 映射 @@ -111,6 +107,7 @@ func getCurrentAbPathByCaller() string { } return abPath } + func getCurrentDirectory() string { dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { diff --git a/pkg/docker/emum.go b/pkg/docker/emum.go deleted file mode 100644 index fad329b..0000000 --- a/pkg/docker/emum.go +++ /dev/null @@ -1,3 +0,0 @@ -package docker - -const NETWORKNAME = "oasis" diff --git a/pkg/docker/helper.go b/pkg/docker/helper.go deleted file mode 100644 index 0aef117..0000000 --- a/pkg/docker/helper.go +++ /dev/null @@ -1,402 +0,0 @@ -package docker - -import ( - "bytes" - json2 "encoding/json" - "fmt" - "io" - "regexp" - "sync" - "time" - - "github.com/gorilla/websocket" - "github.com/sirupsen/logrus" - "golang.org/x/crypto/ssh" -) - -func NewSshClient(user, password string, port string) (*ssh.Client, error) { - // connet to ssh - // addr = fmt.Sprintf("%s:%d", host, port) - - config := &ssh.ClientConfig{ - Timeout: time.Second * 5, - User: user, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - // HostKeyCallback: , - // HostKeyCallback: hostKeyCallBackFunc(h.Host), - } - // if h.Type == "password" { - config.Auth = []ssh.AuthMethod{ssh.Password(password)} - //} else { - // config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)} - //} - addr := fmt.Sprintf("%s:%s", "127.0.0.1", port) - c, err := ssh.Dial("tcp", addr, config) - if err != nil { - return nil, err - } - return c, nil -} - -// setup ssh shell session -// set Session and StdinPipe here, -// and the Session.Stdout and Session.Sdterr are also set. -func NewSshConn(cols, rows int, sshClient *ssh.Client) (*SshConn, error) { - sshSession, err := sshClient.NewSession() - if err != nil { - return nil, err - } - - stdinP, err := sshSession.StdinPipe() - if err != nil { - return nil, err - } - comboWriter := new(wsBufferWriter) - - sshSession.Stdout = comboWriter - sshSession.Stderr = comboWriter - - modes := ssh.TerminalModes{ - ssh.ECHO: 1, // disable echo - ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud - ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud - } - // Request pseudo terminal - if err := sshSession.RequestPty("xterm", rows, cols, modes); err != nil { - return nil, err - } - // Start remote shell - if err := sshSession.Shell(); err != nil { - return nil, err - } - return &SshConn{StdinPipe: stdinP, ComboOutput: comboWriter, Session: sshSession}, nil -} - -type SshConn struct { - // calling Write() to write data into ssh server - StdinPipe io.WriteCloser - // Write() be called to receive data from ssh server - ComboOutput *wsBufferWriter - Session *ssh.Session -} -type wsBufferWriter struct { - buffer bytes.Buffer - mu sync.Mutex -} - -func (w *wsBufferWriter) Write(p []byte) (int, error) { - w.mu.Lock() - defer w.mu.Unlock() - return w.buffer.Write(p) -} - -func (s *SshConn) Close() { - if s.Session != nil { - s.Session.Close() - } -} - -const ( - wsMsgCmd = "cmd" - wsMsgResize = "resize" -) - -// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin -func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { - // tells other go routine quit - username := "" - for { - - // read websocket msg - _, wsData, err := wsConn.ReadMessage() - if err != nil { - return "" - } - - msgObj := wsMsg{} - if err := json2.Unmarshal(wsData, &msgObj); err != nil { - msgObj.Type = "cmd" - msgObj.Cmd = string(wsData) - } - //if err := json.Unmarshal(wsData, &msgObj); err != nil { - // logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed") - //} - switch msgObj.Type { - case wsMsgCmd: - // handle xterm.js stdin - // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) - decodeBytes := []byte(msgObj.Cmd) - if msgObj.Cmd == "\u007f" { - if len(username) == 0 { - continue - } - wsConn.WriteMessage(websocket.TextMessage, []byte("\b\x1b[K")) - username = username[:len(username)-1] - continue - } - if msgObj.Cmd == "\r" { - return username - } - username += msgObj.Cmd - - if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil { - logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") - } - // write input cmd to log buffer - if _, err := logBuff.Write(decodeBytes); err != nil { - logrus.WithError(err).Error("write received cmd into log buffer failed") - } - } - - } -} - -func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { - // tells other go routine quit - password := "" - for { - - // read websocket msg - _, wsData, err := wsConn.ReadMessage() - if err != nil { - logrus.WithError(err).Error("reading webSocket message failed") - return "" - } - - msgObj := wsMsg{} - if err := json2.Unmarshal(wsData, &msgObj); err != nil { - msgObj.Type = "cmd" - msgObj.Cmd = string(wsData) - } - //if err := json.Unmarshal(wsData, &msgObj); err != nil { - // logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed") - //} - switch msgObj.Type { - case wsMsgCmd: - // handle xterm.js stdin - // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) - if msgObj.Cmd == "\r" { - return password - } - - if msgObj.Cmd == "\u007f" { - if len(password) == 0 { - continue - } - password = password[:len(password)-1] - continue - } - password += msgObj.Cmd - } - - } -} - -// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin -func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) { - // tells other go routine quit - defer setQuit(exitCh) - for { - select { - case <-exitCh: - return - default: - // read websocket msg - _, wsData, err := wsConn.ReadMessage() - if err != nil { - logrus.WithError(err).Error("reading webSocket message failed") - return - } - //unmashal bytes into struct - //msgObj := wsMsg{ - // Type: "cmd", - // Cmd: "", - // Rows: 50, - // Cols: 180, - //} - msgObj := wsMsg{} - if err := json2.Unmarshal(wsData, &msgObj); err != nil { - msgObj.Type = "cmd" - msgObj.Cmd = string(wsData) - } - //if err := json.Unmarshal(wsData, &msgObj); err != nil { - // logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed") - //} - switch msgObj.Type { - - case wsMsgResize: - // handle xterm.js size change - if msgObj.Cols > 0 && msgObj.Rows > 0 { - if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil { - logrus.WithError(err).Error("ssh pty change windows size failed") - } - } - case wsMsgCmd: - // handle xterm.js stdin - // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) - decodeBytes := []byte(msgObj.Cmd) - if err != nil { - logrus.WithError(err).Error("websock cmd string base64 decoding failed") - } - if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil { - logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") - } - // write input cmd to log buffer - if _, err := logBuff.Write(decodeBytes); err != nil { - logrus.WithError(err).Error("write received cmd into log buffer failed") - } - } - } - } -} - -func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool) { - // tells other go routine quit - // defer setQuit(exitCh) - - // every 120ms write combine output bytes into websocket response - tick := time.NewTicker(time.Millisecond * time.Duration(120)) - // for range time.Tick(120 * time.Millisecond){} - defer tick.Stop() - for { - select { - case <-tick.C: - // write combine output bytes into websocket response - if err := flushComboOutput(ssConn.ComboOutput, wsConn); err != nil { - logrus.WithError(err).Error("ssh sending combo output to webSocket failed") - return - } - case <-exitCh: - return - } - } -} - -func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error { - if w.buffer.Len() != 0 { - err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes()) - if err != nil { - return err - } - w.buffer.Reset() - } - return nil -} - -// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin -func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) { - // tells other go routine quit - defer setQuit(exitCh) - for { - select { - case <-exitCh: - return - default: - // read websocket msg - _, wsData, err := wsConn.ReadMessage() - if err != nil { - logrus.WithError(err).Error("reading webSocket message failed") - return - } - //unmashal bytes into struct - //msgObj := wsMsg{ - // Type: "cmd", - // Cmd: "", - // Rows: 50, - // Cols: 180, - //} - msgObj := wsMsg{} - if err := json2.Unmarshal(wsData, &msgObj); err != nil { - msgObj.Type = "cmd" - msgObj.Cmd = string(wsData) - } - //if err := json.Unmarshal(wsData, &msgObj); err != nil { - // logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed") - //} - switch msgObj.Type { - - case wsMsgResize: - // handle xterm.js size change - if msgObj.Cols > 0 && msgObj.Rows > 0 { - if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil { - logrus.WithError(err).Error("ssh pty change windows size failed") - } - } - case wsMsgCmd: - // handle xterm.js stdin - // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) - decodeBytes := []byte(msgObj.Cmd) - if err != nil { - logrus.WithError(err).Error("websock cmd string base64 decoding failed") - } - if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil { - logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") - } - // write input cmd to log buffer - if _, err := logBuff.Write(decodeBytes); err != nil { - logrus.WithError(err).Error("write received cmd into log buffer failed") - } - } - } - } -} - -func (ssConn *SshConn) SessionWait(quitChan chan bool) { - if err := ssConn.Session.Wait(); err != nil { - logrus.WithError(err).Error("ssh session wait failed") - setQuit(quitChan) - } -} - -func setQuit(ch chan bool) { - ch <- true -} - -type wsMsg struct { - Type string `json:"type"` - Cmd string `json:"cmd"` - Cols int `json:"cols"` - Rows int `json:"rows"` -} - -// 将终端的输出转发到前端 -func WsWriterCopy(reader io.Reader, writer *websocket.Conn) { - buf := make([]byte, 8192) - reg1 := regexp.MustCompile(`stty rows \d+ && stty cols \d+ `) - for { - nr, err := reader.Read(buf) - if nr > 0 { - result1 := reg1.FindIndex(buf[0:nr]) - if len(result1) > 0 { - fmt.Println(result1) - } else { - err := writer.WriteMessage(websocket.BinaryMessage, buf[0:nr]) - if err != nil { - return - } - } - - } - if err != nil { - return - } - } -} - -// 将前端的输入转发到终端 -func WsReaderCopy(reader *websocket.Conn, writer io.Writer) { - for { - messageType, p, err := reader.ReadMessage() - if err != nil { - return - } - if messageType == websocket.TextMessage { - msgObj := wsMsg{} - if err = json2.Unmarshal(p, &msgObj); err != nil { - writer.Write(p) - } else if msgObj.Type == wsMsgResize { - // writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r")) - } - } - } -} diff --git a/pkg/docker/volumes.go b/pkg/docker/volumes.go deleted file mode 100644 index d782a20..0000000 --- a/pkg/docker/volumes.go +++ /dev/null @@ -1,11 +0,0 @@ -package docker - -import "strings" - -func GetDir(id, envName string) string { - - if strings.Contains(envName, "$AppID") && len(id) > 0 { - return strings.ReplaceAll(envName, "$AppID", id) - } - return envName -} diff --git a/pkg/docker/volumes_test.go b/pkg/docker/volumes_test.go deleted file mode 100644 index c5d45fb..0000000 --- a/pkg/docker/volumes_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package docker - -import ( - "fmt" - "testing" -) - -func TestGetDir(t *testing.T) { - fmt.Println(GetDir("", "config")) -} diff --git a/pkg/sqlite/db.go b/pkg/sqlite/db.go index e5d7595..b64d288 100644 --- a/pkg/sqlite/db.go +++ b/pkg/sqlite/db.go @@ -28,8 +28,8 @@ func GetDb(dbPath string) *gorm.DB { return gdb } // Refer https://github.com/go-sql-driver/mysql#dsn-data-source-name - //dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName) - //db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{}) + // dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName) + // db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{}) file.IsNotExistMkDir(dbPath) db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{}) c, _ := db.DB() @@ -39,11 +39,10 @@ func GetDb(dbPath string) *gorm.DB { if err != nil { loger.Error("sqlite connect error", zap.Any("db connect error", err)) panic("sqlite connect error") - return nil } gdb = db - err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}) + err = db.AutoMigrate(&model2.AppNotify{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}) db.Exec("DROP TABLE IF EXISTS o_application") db.Exec("DROP TABLE IF EXISTS o_friend") db.Exec("DROP TABLE IF EXISTS o_person_download") diff --git a/pkg/utils/port/port.go b/pkg/utils/port/port.go deleted file mode 100644 index 8daf1a2..0000000 --- a/pkg/utils/port/port.go +++ /dev/null @@ -1,68 +0,0 @@ -package port - -import ( - "fmt" - "net" -) - -// 获取可用端口 -func GetAvailablePort(t string) (int, error) { - address := fmt.Sprintf("%s:0", "0.0.0.0") - if t == "udp" { - add, err := net.ResolveUDPAddr(t, address) - if err != nil { - return 0, err - } - - listener, err := net.ListenUDP(t, add) - if err != nil { - return 0, err - } - - defer listener.Close() - return listener.LocalAddr().(*net.UDPAddr).Port, nil - } else { - add, err := net.ResolveTCPAddr(t, address) - if err != nil { - return 0, err - } - - listener, err := net.ListenTCP(t, add) - if err != nil { - return 0, err - } - - defer listener.Close() - return listener.Addr().(*net.TCPAddr).Port, nil - } - -} - -// 判断端口是否可以(未被占用) -// param t tcp/udp -func IsPortAvailable(port int, t string) bool { - address := fmt.Sprintf("%s:%d", "0.0.0.0", port) - if t == "udp" { - sadd, err := net.ResolveUDPAddr("udp", address) - uc, err := net.ListenUDP("udp", sadd) - - if err != nil { - fmt.Println(err.Error()) - return false - } else { - defer uc.Close() - return true - } - - } else { - listener, err := net.Listen(t, address) - - if err != nil { - //log.Infof("port %s is taken: %s", address, err) - return false - } - defer listener.Close() - return true - } - -} diff --git a/pkg/utils/port/port_test.go b/pkg/utils/port/port_test.go deleted file mode 100644 index 85a4140..0000000 --- a/pkg/utils/port/port_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package port - -import ( - "fmt" - "testing" -) - -func TestPortAvailable(t *testing.T) { - // fmt.Println(PortAvailable()) - //fmt.Println(IsPortAvailable(6881,"tcp")) - p, _ := GetAvailablePort("udp") - fmt.Println("udp", p) - fmt.Println(IsPortAvailable(p, "udp")) - - t1, _ := GetAvailablePort("tcp") - fmt.Println("tcp", t1) - fmt.Println(IsPortAvailable(t1, "tcp")) -} diff --git a/route/route.go b/route/route.go index 7e388a7..1ed7466 100644 --- a/route/route.go +++ b/route/route.go @@ -81,12 +81,6 @@ func InitRouter() *gin.Engine { // v1UsersGroup.DELETE("", v1.DeleteUserAll) // } - v1AppsGroup := v1Group.Group("/apps") - v1AppsGroup.Use() - { - v1AppsGroup.GET("", v1.AppList) // list - v1AppsGroup.GET("/:id", v1.AppInfo) - } v1ContainerGroup := v1Group.Group("/container") v1ContainerGroup.Use() { diff --git a/route/v1/app.go b/route/v1/app.go deleted file mode 100644 index 8e39347..0000000 --- a/route/v1/app.go +++ /dev/null @@ -1,355 +0,0 @@ -package v1 - -import ( - "encoding/json" - "io/ioutil" - "net/http" - "path/filepath" - "strconv" - - "github.com/IceWhaleTech/CasaOS/model" - "github.com/IceWhaleTech/CasaOS/pkg/utils/command" - "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" - "github.com/IceWhaleTech/CasaOS/pkg/utils/file" - - port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port" - "github.com/IceWhaleTech/CasaOS/service" - "github.com/gin-gonic/gin" -) - -const ( - dockerRootDirFilePath = "/var/lib/casaos/docker_root" - dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json" -) - -// @Summary 获取远程列表 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Param index query int false "页码" -// @Param size query int false "每页数量" -// @Param category_id query int false "分类id" -// @Param type query string false "rank,new" -// @Param key query string false "search key" -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/list [get] -func AppList(c *gin.Context) { - // service.MyService.Docker().DockerContainerCommit("test2") - - index := c.DefaultQuery("index", "1") - size := c.DefaultQuery("size", "10000") - t := c.DefaultQuery("type", "rank") - categoryId := c.DefaultQuery("category_id", "0") - key := c.DefaultQuery("key", "") - if len(index) == 0 || len(size) == 0 || len(t) == 0 || len(categoryId) == 0 { - c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - return - } - collection, err := service.MyService.Casa().GetServerList(index, size, t, categoryId, key) - if err != nil { - c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) - return - } - // for i := 0; i < len(recommend); i++ { - // ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion) - // if ct != nil { - // recommend[i].State = ct.State - // } - // } - // for i := 0; i < len(list); i++ { - // ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion) - // if ct != nil { - // list[i].State = ct.State - // } - // } - // for i := 0; i < len(community); i++ { - // ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion) - // if ct != nil { - // community[i].State = ct.State - // } - // } - data := make(map[string]interface{}, 3) - data["recommend"] = collection.Recommend - data["list"] = collection.List - data["community"] = collection.Community - - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) -} - -// @Summary 获取一个可用端口 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Param type query string true "端口类型 udp/tcp" -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/getport [get] -func GetPort(c *gin.Context) { - t := c.DefaultQuery("type", "tcp") - var p int - ok := true - for ok { - p, _ = port2.GetAvailablePort(t) - ok = !port2.IsPortAvailable(p, t) - } - // @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文 - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p}) -} - -// @Summary 检查端口是否可用 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Param port path int true "端口号" -// @Param type query string true "端口类型 udp/tcp" -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/check/{port} [get] -func PortCheck(c *gin.Context) { - p, _ := strconv.Atoi(c.Param("port")) - t := c.DefaultQuery("type", "tcp") - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port2.IsPortAvailable(p, t)}) -} - -// @Summary 我的应用列表 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Security ApiKeyAuth -// @Param index query int false "index" -// @Param size query int false "size" -// @Param position query bool false "是否是首页应用" -// @Success 200 {string} string "ok" -// @Router /app/my/list [get] -func MyAppList(c *gin.Context) { - index, _ := strconv.Atoi(c.DefaultQuery("index", "1")) - size, _ := strconv.Atoi(c.DefaultQuery("size", "0")) - position, _ := strconv.ParseBool(c.DefaultQuery("position", "true")) - list, unTranslation := service.MyService.App().GetMyList(index, size, position) - data := make(map[string]interface{}, 2) - data["casaos_apps"] = list - data["local_apps"] = unTranslation - - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) -} - -// @Summary my app hardware usage list -// @Produce application/json -// @Accept application/json -// @Tags app -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/usage [get] -func AppUsageList(c *gin.Context) { - list := service.MyService.App().GetHardwareUsage() - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list}) - // c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil}) -} - -// @Summary 应用详情 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Param id path int true "id" -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/appinfo/{id} [get] -func AppInfo(c *gin.Context) { - id := c.Param("id") - language := c.GetHeader("Language") - info, err := service.MyService.Casa().GetServerAppInfo(id, "", language) - if err != nil { - c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) - return - } - if info.NetworkModel != "host" { - for i := 0; i < len(info.Ports); i++ { - if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) { - info.Ports[i].CommendPort = strconv.Itoa(p) - } else { - if info.Ports[i].Protocol == "tcp" { - if p, err := port2.GetAvailablePort("tcp"); err == nil { - info.Ports[i].CommendPort = strconv.Itoa(p) - } - } else if info.Ports[i].Protocol == "upd" { - if p, err := port2.GetAvailablePort("udp"); err == nil { - info.Ports[i].CommendPort = strconv.Itoa(p) - } - } - } - - if info.Ports[i].Type == 0 { - info.PortMap = info.Ports[i].CommendPort - } - } - } else { - for i := 0; i < len(info.Ports); i++ { - if info.Ports[i].Type == 0 { - info.PortMap = info.Ports[i].ContainerPort - break - } - } - } - - for i := 0; i < len(info.Devices); i++ { - if !file.CheckNotExist(info.Devices[i].ContainerPath) { - info.Devices[i].Path = info.Devices[i].ContainerPath - } - } - // if len(info.Tip) > 0 { - // info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip) - // } - - // portOrder := func(c1, c2 *model.Ports) bool { - // return c1.Type < c2.Type - // } - - // envOrder := func(c1, c2 *model.Envs) bool { - // return c1.Type < c2.Type - // } - - // volOrder := func(c1, c2 *model.Volume) bool { - // return c1.Type < c2.Type - // } - - // devOrder := func(c1, c2 *model.Devices) bool { - // return c1.Type < c2.Type - // } - - // sort - // if info.NetworkModel != "host" { - // sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts) - // sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts) - // } - - // sort.EnvSort(envOrder).Sort(info.Envs) - // sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap)) - // sort.DevSort(devOrder).Sort(info.Devices) - info.Image += ":" + info.ImageVersion - info.MaxMemory = (service.MyService.System().GetMemInfo()["total"]).(uint64) >> 20 - - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info}) -} - -// @Summary 获取远程分类列表 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/category [get] -func CategoryList(c *gin.Context) { - list, err := service.MyService.Casa().GetServerCategoryList() - if err != nil { - c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) - return - } - var count uint = 0 - for _, category := range list { - count += category.Count - } - - rear := append([]model.CategoryList{}, list[0:]...) - list = append(list[:0], model.CategoryList{Count: count, Name: "All", Font: "apps"}) - list = append(list, rear...) - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list}) -} - -// @Summary 分享该应用配置 -// @Produce application/json -// @Accept application/json -// @Tags app -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /app/share [post] -func ShareAppFile(c *gin.Context) { - str, _ := ioutil.ReadAll(c.Request.Body) - content := service.MyService.Casa().ShareAppFile(str) - c.JSON(common_err.SUCCESS, json.RawMessage(content)) -} - -func GetDockerDaemonConfiguration(c *gin.Context) { - // info, err := service.MyService.Docker().GetDockerInfo() - // if err != nil { - // c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) - // return - // } - data := make(map[string]interface{}) - - if file.Exists(dockerRootDirFilePath) { - buf := file.ReadFullFile(dockerRootDirFilePath) - err := json.Unmarshal(buf, &data) - if err != nil { - c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err}) - return - } - } - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) -} - -func PutDockerDaemonConfiguration(c *gin.Context) { - request := make(map[string]interface{}) - if err := c.BindJSON(&request); err != nil { - c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err}) - return - } - - value, ok := request["docker_root_dir"] - if !ok { - c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "`docker_root_dir` should not empty"}) - return - } - - dockerConfig := model.DockerDaemonConfigurationModel{} - if file.Exists(dockerDaemonConfigurationFilePath) { - byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath) - err := json.Unmarshal(byteResult, &dockerConfig) - if err != nil { - c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err}) - return - } - } - - dockerRootDir := value.(string) - if dockerRootDir == "/" { - dockerConfig.Root = "" // omitempty - empty string will not be serialized - } else { - if !file.Exists(dockerRootDir) { - c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) - return - } - - dockerConfig.Root = filepath.Join(dockerRootDir, "docker") - - if err := file.IsNotExistMkDir(dockerConfig.Root); err != nil { - c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err}) - return - } - } - - if buf, err := json.Marshal(request); err != nil { - c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker root json", Data: err}) - return - } else { - if err := file.WriteToFullPath(buf, dockerRootDirFilePath, 0o644); err != nil { - c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write " + dockerRootDirFilePath, Data: err}) - return - } - } - - if buf, err := json.Marshal(dockerConfig); err != nil { - c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig}) - return - } else { - if err := file.WriteToFullPath(buf, dockerDaemonConfigurationFilePath, 0o644); err != nil { - c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write to " + dockerDaemonConfigurationFilePath, Data: err}) - return - } - } - - println(command.ExecResultStr("systemctl daemon-reload")) - println(command.ExecResultStr("systemctl restart docker")) - - c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: request}) -} diff --git a/service/app.go b/service/app.go deleted file mode 100644 index a2bb58b..0000000 --- a/service/app.go +++ /dev/null @@ -1,480 +0,0 @@ -package service - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "runtime" - "strings" - "sync" - "time" - - "github.com/IceWhaleTech/CasaOS/model" - "github.com/IceWhaleTech/CasaOS/pkg/config" - "github.com/IceWhaleTech/CasaOS/pkg/utils/command" - "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" - model2 "github.com/IceWhaleTech/CasaOS/service/model" - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - client2 "github.com/docker/docker/client" - "github.com/pkg/errors" - uuid "github.com/satori/go.uuid" - "go.uber.org/zap" - "gorm.io/gorm" -) - -type AppService interface { - GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) - SaveContainer(m model2.AppListDBModel) - GetUninstallInfo(id string) model2.AppListDBModel - DeleteApp(id string) - GetContainerInfo(id string) (types.Container, error) - GetAppDBInfo(id string) model2.AppListDBModel - UpdateApp(m model2.AppListDBModel) - GetSimpleContainerInfo(id string) (types.Container, error) - DelAppConfigDir(path string) - GetSystemAppList() []types.Container - GetHardwareUsageStream() - GetHardwareUsage() []model.DockerStatsModel - GetAppStats(id string) string - GetAllDBApps() []model2.AppListDBModel - ImportApplications(casaApp bool) - CheckNewImage() -} - -type appStruct struct { - db *gorm.DB -} - -func (a *appStruct) CheckNewImage() { - list := MyService.Docker().DockerContainerList() - for _, v := range list { - inspect, err := MyService.Docker().DockerImageInfo(strings.Split(v.Image, ":")[0]) - if err != nil { - NewVersionApp[v.ID] = inspect.ID - continue - } - if inspect.ID == v.ImageID { - delete(NewVersionApp, v.ID) - continue - } - NewVersionApp[v.ID] = inspect.ID - } - -} -func (a *appStruct) ImportApplications(casaApp bool) { - if casaApp { - list := MyService.App().GetAllDBApps() - for _, app := range list { - info, err := MyService.Docker().DockerContainerInfo(app.CustomId) - if err != nil { - MyService.App().DeleteApp(app.CustomId) - continue - } - //info.NetworkSettings - info.Config.Labels["casaos"] = "casaos" - info.Config.Labels["web"] = app.PortMap - info.Config.Labels["icon"] = app.Icon - info.Config.Labels["desc"] = app.Description - info.Config.Labels["index"] = app.Index - info.Config.Labels["custom_id"] = app.CustomId - info.Name = app.Title - container_id, err := MyService.Docker().DockerContainerCopyCreate(info) - if err != nil { - fmt.Println(err) - continue - } - MyService.App().DeleteApp(app.CustomId) - MyService.Docker().DockerContainerStop(app.CustomId) - MyService.Docker().DockerContainerRemove(app.CustomId, false) - MyService.Docker().DockerContainerStart(container_id) - - } - } else { - list := MyService.Docker().DockerContainerList() - for _, app := range list { - info, err := MyService.Docker().DockerContainerInfo(app.ID) - if err != nil || info.Config.Labels["casaos"] == "casaos" { - continue - } - info.Config.Labels["casaos"] = "casaos" - info.Config.Labels["web"] = "" - info.Config.Labels["icon"] = "" - info.Config.Labels["desc"] = "" - info.Config.Labels["index"] = "" - info.Config.Labels["custom_id"] = uuid.NewV4().String() - - _, err = MyService.Docker().DockerContainerCopyCreate(info) - if err != nil { - continue - } - - } - } - - // allcontainer := MyService.Docker().DockerContainerList() - // for _, app := range allcontainer { - // info, err := MyService.Docker().DockerContainerInfo(app.ID) - // if err != nil { - // continue - // } - // MyService.Docker().DockerContainerStop(app.ID) - // MyService.Docker().DockerContainerRemove(app.ID, false) - // //info.NetworkSettings - // info.Config.Labels["custom_id"] = uuid.NewV4().String() - // container_id, err := MyService.Docker().DockerContainerCopyCreate(info) - // if err != nil { - // fmt.Println(err) - // continue - // } - // MyService.Docker().DockerContainerStart(container_id) - //} -} - -//获取我的应用列表 -func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) { - cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5)) - if err != nil { - loger.Error("Failed to init client", zap.Any("err", err)) - } - defer cli.Close() - // fts := filters.NewArgs() - // fts.Add("label", "casaos=casaos") - //fts.Add("label", "casaos") - //fts.Add("casaos", "casaos") - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true}) - if err != nil { - loger.Error("Failed to get container_list", zap.Any("err", err)) - } - //获取本地数据库应用 - - unTranslation := []model2.MyAppList{} - - list := []model2.MyAppList{} - - for _, m := range containers { - if m.Labels["casaos"] == "casaos" { - - _, newVersion := NewVersionApp[m.ID] - name := strings.ReplaceAll(m.Names[0], "/", "") - icon := m.Labels["icon"] - if len(m.Labels["name"]) > 0 { - name = m.Labels["name"] - } - if m.Labels["origin"] == "system" { - name = strings.Split(m.Image, ":")[0] - if len(strings.Split(name, "/")) > 1 { - icon = "https://icon.casaos.io/main/all/" + strings.Split(name, "/")[1] + ".png" - } - } - - list = append(list, model2.MyAppList{ - Name: name, - Icon: icon, - State: m.State, - CustomId: m.Labels["custom_id"], - Id: m.ID, - Port: m.Labels["web"], - Index: m.Labels["index"], - //Order: m.Labels["order"], - Image: m.Image, - Latest: newVersion, - //Type: m.Labels["origin"], - //Slogan: m.Slogan, - //Rely: m.Rely, - Host: m.Labels["host"], - Protocol: m.Labels["protocol"], - }) - } else { - unTranslation = append(unTranslation, model2.MyAppList{ - Name: strings.ReplaceAll(m.Names[0], "/", ""), - Icon: "", - State: m.State, - CustomId: m.ID, - Id: m.ID, - Port: "", - Latest: false, - Host: "", - Protocol: "", - Image: m.Image, - }) - } - } - - //lMap := make(map[string]interface{}) - // for _, dbModel := range lm { - // if position { - // if dbModel.Position { - // lMap[dbModel.ContainerId] = dbModel - // } - // } else { - // lMap[dbModel.ContainerId] = dbModel - // } - // } - // for _, container := range containers { - - // if lMap[container.ID] != nil && container.Labels["origin"] != "system" { - // m := lMap[container.ID].(model2.AppListDBModel) - // if len(m.Label) == 0 { - // m.Label = m.Title - // } - - // // info, err := cli.ContainerInspect(context.Background(), container.ID) - // // var tm string - // // if err != nil { - // // tm = time.Now().String() - // // } else { - // // tm = info.State.StartedAt - // //} - // list = append(list, model2.MyAppList{ - // Name: m.Label, - // Icon: m.Icon, - // State: container.State, - // CustomId: strings.ReplaceAll(container.Names[0], "/", ""), - // Port: m.PortMap, - // Index: m.Index, - // //UpTime: tm, - // Image: m.Image, - // Slogan: m.Slogan, - // //Rely: m.Rely, - // }) - // } - - // } - - return &list, &unTranslation - -} - -//system application list -func (a *appStruct) GetSystemAppList() []types.Container { - //获取docker应用 - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - loger.Error("Failed to init client", zap.Any("err", err)) - } - defer cli.Close() - fts := filters.NewArgs() - fts.Add("label", "origin=system") - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts}) - if err != nil { - loger.Error("Failed to get container_list", zap.Any("err", err)) - } - - //获取本地数据库应用 - - // var lm []model2.AppListDBModel - // a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm) - - //list := []model2.MyAppList{} - //lMap := make(map[string]interface{}) - // for _, dbModel := range lm { - // lMap[dbModel.ContainerId] = dbModel - // } - - return containers - -} -func (a *appStruct) GetAllDBApps() []model2.AppListDBModel { - var lm []model2.AppListDBModel - a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image,port_map").Find(&lm) - return lm -} - -//获取我的应用列表 -func (a *appStruct) GetContainerInfo(id string) (types.Container, error) { - //获取docker应用 - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - loger.Error("Failed to init client", zap.Any("err", err)) - } - filters := filters.NewArgs() - filters.Add("id", id) - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters}) - if err != nil { - loger.Error("Failed to get container_list", zap.Any("err", err)) - } - - if len(containers) > 0 { - return containers[0], nil - } - return types.Container{}, nil - -} - -func (a *appStruct) GetSimpleContainerInfo(id string) (types.Container, error) { - //获取docker应用 - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return types.Container{}, err - } - defer cli.Close() - filters := filters.NewArgs() - filters.Add("id", id) - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters}) - if err != nil { - return types.Container{}, err - } - - if len(containers) > 0 { - return containers[0], nil - } - return types.Container{}, errors.New("container not existent") -} - -//获取我的应用列表 -func (a *appStruct) GetAppDBInfo(id string) model2.AppListDBModel { - var m model2.AppListDBModel - a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).First(&m) - return m -} - -//根据容器id获取镜像名称 -func (a *appStruct) GetUninstallInfo(id string) model2.AppListDBModel { - var m model2.AppListDBModel - a.db.Table(model2.CONTAINERTABLENAME).Select("image,version,enable_upnp,ports,envs,volumes,origin").Where("custom_id = ?", id).First(&m) - return m -} - -//创建容器成功后保存容器 -func (a *appStruct) SaveContainer(m model2.AppListDBModel) { - a.db.Table(model2.CONTAINERTABLENAME).Create(&m) -} - -func (a *appStruct) UpdateApp(m model2.AppListDBModel) { - a.db.Table(model2.CONTAINERTABLENAME).Save(&m) -} - -func (a *appStruct) DelAppConfigDir(path string) { - command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;DelAppConfigDir " + path) -} - -func (a *appStruct) DeleteApp(id string) { - a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{}) -} - -var dataStats sync.Map - -var isFinish bool = false - -func (a *appStruct) GetAppStats(id string) string { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return "" - } - defer cli.Close() - con, err := cli.ContainerStats(context.Background(), id, false) - if err != nil { - return err.Error() - } - defer con.Body.Close() - c, _ := ioutil.ReadAll(con.Body) - return string(c) -} - -func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel { - - stream := true - for !isFinish { - if stream { - stream = false - go func() { - a.GetHardwareUsageStream() - }() - } - runtime.Gosched() - } - list := []model.DockerStatsModel{} - - dataStats.Range(func(key, value interface{}) bool { - list = append(list, value.(model.DockerStatsModel)) - return true - }) - return list - -} - -func (a *appStruct) GetHardwareUsageStream() { - - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return - } - defer cli.Close() - - ctx := context.Background() - ctx, cancel := context.WithCancel(ctx) - - fts := filters.NewArgs() - fts.Add("label", "casaos=casaos") - //fts.Add("status", "running") - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts}) - if err != nil { - loger.Error("Failed to get container_list", zap.Any("err", err)) - } - for i := 0; i < 100; i++ { - if i%10 == 0 { - containers, err = cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts}) - if err != nil { - loger.Error("Failed to get container_list", zap.Any("err", err)) - continue - } - } - if config.CasaOSGlobalVariables.AppChange { - config.CasaOSGlobalVariables.AppChange = false - dataStats.Range(func(key, value interface{}) bool { - dataStats.Delete(key) - return true - }) - } - - var temp sync.Map - var wg sync.WaitGroup - for _, v := range containers { - if v.State != "running" { - continue - } - wg.Add(1) - go func(v types.Container, i int) { - defer wg.Done() - stats, err := cli.ContainerStatsOneShot(ctx, v.ID) - if err != nil { - return - } - decode := json.NewDecoder(stats.Body) - var data interface{} - if err := decode.Decode(&data); err == io.EOF { - return - } - m, _ := dataStats.Load(v.ID) - dockerStats := model.DockerStatsModel{} - if m != nil { - dockerStats.Previous = m.(model.DockerStatsModel).Data - } - dockerStats.Data = data - dockerStats.Icon = v.Labels["icon"] - dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "") - - // @tiger - 不建议直接把依赖的数据结构封装返回。 - // 如果依赖的数据结构有变化,应该在这里适配或者保存,这样更加对客户端负责 - temp.Store(v.ID, dockerStats) - if i == 99 { - stats.Body.Close() - } - }(v, i) - } - wg.Wait() - dataStats = temp - isFinish = true - - time.Sleep(time.Second * 1) - } - isFinish = false - cancel() -} - -func NewAppService(db *gorm.DB) AppService { - return &appStruct{db: db} -} diff --git a/service/casa.go b/service/casa.go index 4d80bf4..88e1c45 100644 --- a/service/casa.go +++ b/service/casa.go @@ -1,266 +1,20 @@ package service import ( - "encoding/json" json2 "encoding/json" - "fmt" - "sort" - "strconv" "time" "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/config" - "github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" - httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" - "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" - "github.com/pkg/errors" "github.com/tidwall/gjson" - "go.uber.org/zap" ) type CasaService interface { - GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error) - GetServerCategoryList() (list []model.CategoryList, err error) - GetServerAppInfo(id, t string, language string) (model.ServerAppList, error) - ShareAppFile(body []byte) string GetCasaosVersion() model.Version - AsyncGetServerList() (collection model.ServerAppListCollection, err error) - AsyncGetServerCategoryList() ([]model.CategoryList, error) } -type casaService struct { -} - -func (o *casaService) ShareAppFile(body []byte) string { - head := make(map[string]string) - - head["Authorization"] = GetToken() - - content := httper2.Post(config.ServerInfo.ServerApi+"/v1/community/add", body, "application/json", head) - return content -} - -func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error) { - - keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, "en") - collection := model.ServerAppListCollection{} - if result, ok := Cache.Get(keyName); ok { - res, ok := result.(string) - if ok { - json2.Unmarshal([]byte(res), &collection) - return collection, nil - } - } - - collectionStr := file.ReadFullFile(config.AppInfo.DBPath + "/app_list.json") - - err := json2.Unmarshal(collectionStr, &collection) - if err != nil { - loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(collectionStr))) - collection, err = o.AsyncGetServerList() - if err != nil { - return collection, err - } - } - - go o.AsyncGetServerList() - - if categoryId != "0" { - categoryInt, _ := strconv.Atoi(categoryId) - nList := []model.ServerAppList{} - for _, v := range collection.List { - if v.CategoryId == categoryInt { - nList = append(nList, v) - } - } - collection.List = nList - nCommunity := []model.ServerAppList{} - for _, v := range collection.Community { - if v.CategoryId == categoryInt { - nCommunity = append(nCommunity, v) - } - } - collection.Community = nCommunity - } - if tp != "name" { - if tp == "new" { - sort.Slice(collection.List, func(i, j int) bool { - return collection.List[i].CreatedAt.After(collection.List[j].CreatedAt) - }) - sort.Slice(collection.Community, func(i, j int) bool { - return collection.Community[i].CreatedAt.After(collection.Community[j].CreatedAt) - }) - } else if tp == "rank" { - sort.Slice(collection.List, func(i, j int) bool { - return collection.List[i].QueryCount > collection.List[j].QueryCount - }) - sort.Slice(collection.Community, func(i, j int) bool { - return collection.Community[i].QueryCount > collection.Community[j].QueryCount - }) - } - } - sizeInt, _ := strconv.Atoi(size) - - if index != "1" { - indexInt, _ := strconv.Atoi(index) - collection.List = collection.List[(indexInt-1)*sizeInt : indexInt*sizeInt] - collection.Community = collection.Community[(indexInt-1)*sizeInt : indexInt*sizeInt] - } else { - if len(collection.List) > sizeInt { - collection.List = collection.List[:sizeInt] - } - if len(collection.Community) > sizeInt { - collection.Community = collection.Community[:sizeInt] - } - } - - if len(collection.List) > 0 { - by, _ := json.Marshal(collection) - Cache.Set(keyName, string(by), time.Minute*10) - } - - return collection, nil - -} - -func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollection, err error) { - - results := file.ReadFullFile(config.AppInfo.DBPath + "/app_list.json") - errr := json2.Unmarshal(results, &collection) - if errr != nil { - loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results))) - } - - head := make(map[string]string) - - head["Authorization"] = GetToken() - - listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index=1&size=1000&rank=name&category_id=0&key=&language=en", head) - listModel := []model.ServerAppList{} - communityModel := []model.ServerAppList{} - recommendModel := []model.ServerAppList{} - err = json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &listModel) - json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommendModel) - json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &communityModel) - - if len(listModel) > 0 { - collection.Community = communityModel - collection.List = listModel - collection.Recommend = recommendModel - collection.Version = o.GetCasaosVersion().Version - var by []byte - by, err = json.Marshal(collection) - if err != nil { - loger.Error("marshal error", zap.Any("err", err)) - } - file.WriteToPath(by, config.AppInfo.DBPath, "app_list.json") - } - return -} - -// func (o *casaService) GetServerCategoryList() (list []model.ServerCategoryList) { - -// keyName := fmt.Sprintf("category_list") -// if result, ok := Cache.Get(keyName); ok { -// res, ok := result.(string) -// if ok { -// json2.Unmarshal([]byte(gjson.Get(res, "data").String()), &list) -// return list -// } -// } - -// head := make(map[string]string) -// head["Authorization"] = GetToken() - -// listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head) - -// json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list) -// if len(list) > 0 { -// Cache.Set(keyName, listS, time.Hour*24) -// } -// return list -// } - -func (o *casaService) GetServerCategoryList() (list []model.CategoryList, err error) { - category := model.ServerCategoryList{} - results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json") - err = json2.Unmarshal(results, &category) - if err != nil { - loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results))) - return o.AsyncGetServerCategoryList() - } - go o.AsyncGetServerCategoryList() - return category.Item, err -} - -func (o *casaService) AsyncGetServerCategoryList() ([]model.CategoryList, error) { - list := model.ServerCategoryList{} - results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json") - err := json2.Unmarshal(results, &list) - if err != nil { - loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results))) - } - item := []model.CategoryList{} - head := make(map[string]string) - head["Authorization"] = GetToken() - listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head) - if len(listS) == 0 { - return item, errors.New("server error") - } - json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &item) - if len(item) > 0 { - list.Version = o.GetCasaosVersion().Version - list.Item = item - by, err := json.Marshal(list) - if err != nil { - loger.Error("marshal error", zap.Any("err", err)) - } - file.WriteToPath(by, config.AppInfo.DBPath, "app_category.json") - } - return item, nil -} - -func (o *casaService) GetServerAppInfo(id, t string, language string) (model.ServerAppList, error) { - - head := make(map[string]string) - - head["Authorization"] = GetToken() - infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t+"&language="+language, head) - - info := model.ServerAppList{} - if infoS == "" { - return info, errors.New("server error") - } - err := json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info) - if err != nil { - fmt.Println(infoS) - return info, err - } - - return info, nil -} -func GetToken() string { - t := make(chan string) - keyName := "casa_token" - - var auth string - if result, ok := Cache.Get(keyName); ok { - auth, ok = result.(string) - if ok { - - return auth - } - } - go func() { - str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil) - t <- gjson.Get(str, "data").String() - }() - auth = <-t - - Cache.SetDefault(keyName, auth) - return auth -} +type casaService struct{} /** * @description: get remote version diff --git a/service/docker.go b/service/docker.go deleted file mode 100644 index 8963dc5..0000000 --- a/service/docker.go +++ /dev/null @@ -1,962 +0,0 @@ -package service - -import ( - "bytes" - "context" - "encoding/base64" - "encoding/binary" - json2 "encoding/json" - "fmt" - - "github.com/IceWhaleTech/CasaOS/model/notify" - "github.com/pkg/errors" - "go.uber.org/zap" - - "github.com/IceWhaleTech/CasaOS/model" - "github.com/IceWhaleTech/CasaOS/pkg/docker" - command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" - "github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper" - "github.com/IceWhaleTech/CasaOS/pkg/utils/file" - "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" - - //"github.com/containerd/containerd/oci" - "io" - "io/ioutil" - "log" - "os" - "strconv" - "strings" - "time" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/network" - client2 "github.com/docker/docker/client" - "github.com/docker/go-connections/nat" -) - -type DockerService interface { - DockerPullImage(imageName string, icon, name string) error - IsExistImage(imageName string) bool - DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) - DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) - DockerContainerStart(name string) error - DockerContainerStats(name string) (string, error) - DockerListByName(name string) (*types.Container, error) - DockerListByImage(image, version string) (*types.Container, error) - DockerContainerInfo(name string) (*types.ContainerJSON, error) - DockerImageRemove(name string) error - DockerContainerRemove(name string, update bool) error - DockerContainerStop(id string) error - DockerContainerUpdateName(name, id string) (err error) - DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) - DockerContainerLog(name string) ([]byte, error) - DockerContainerCommit(name string) - DockerContainerList() []types.Container - DockerNetworkModelList() []types.NetworkResource - DockerImageInfo(image string) (types.ImageInspect, error) - GetNetWorkNameByNetWorkID(id string) (string, error) - ContainerExecShell(container_id string) string - GetDockerInfo() (types.Info, error) -} - -type dockerService struct { - rootDir string -} - -func (ds *dockerService) DockerContainerList() []types.Container { - cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5)) - if err != nil { - return nil - } - defer cli.Close() - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true}) - if err != nil { - return containers - } - return containers -} - -func (ds *dockerService) ContainerExecShell(container_id string) string { - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{ - User: "1000:1000", - Cmd: []string{"echo -e \"hellow\nworld\" >> /a.txt"}, - }) - if err != nil { - os.Exit(5) - } - err = cli.ContainerExecStart(context.Background(), exec.ID, types.ExecStartCheck{}) - if err != nil { - fmt.Println("exec script error ", err) - } - return exec.ID -} - -// 创建默认网络 -func DockerNetwork() { - - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - d, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{}) - - for _, resource := range d { - if resource.Name == docker.NETWORKNAME { - return - } - } - cli.NetworkCreate(context.Background(), docker.NETWORKNAME, types.NetworkCreate{}) -} - -// 根据网络id获取网络名 -func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) { - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - filter := filters.NewArgs() - filter.Add("id", id) - d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter}) - if err == nil && len(d) > 0 { - return d[0].Name, nil - } - return "", err -} - -// 拉取镜像 -func DockerPull() { - - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - - authConfig := types.AuthConfig{} - encodedJSON, err := json2.Marshal(authConfig) - fmt.Println(err) - - authStr := base64.URLEncoding.EncodeToString(encodedJSON) - reader, err := cli.ImagePull(context.Background(), "swr.cn-north-4.myhuaweicloud.com/root/swr-demo-2048:latest", types.ImagePullOptions{RegistryAuth: authStr}) - - buf := new(bytes.Buffer) - buf.ReadFrom(reader) - fmt.Println(buf.String()) - -} - -// 拉取镜像 -func DockerEx() { - - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - - importResponse, err := cli.ImageImport(context.Background(), types.ImageImportSource{ - Source: strings.NewReader("source"), - SourceName: "image_source", - }, "repository_name:imported", types.ImageImportOptions{ - Tag: "imported", - Message: "A message", - Changes: []string{"change1", "change2"}, - }) - - response, err := ioutil.ReadAll(importResponse) - if err != nil { - fmt.Println(err) - } - importResponse.Close() - println(string(response)) - if string(response) != "response" { - fmt.Printf("expected response to contain 'response', got %s", string(response)) - } -} - -//func DockerContainerSize() { -// cli, err := client2.NewClientWithOpts(client2.FromEnv) -// //but := bytes.Buffer{} -// d, err := cli.ContainerExecCreate(context.Background(), "c3adcef92bae648890941ac00e6c4024d7f2959c2e629f0b581d6a19d77b5eda") -// fmt.Println(d) -// st, _ := ioutil.ReadAll(d.Body) -// fmt.Println(string(st)) -// if err != nil { -// fmt.Print(err) -// } -// -//} - -func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return types.ImageInspect{}, err - } - inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image) - if err != nil { - return inspect, err - } - return inspect, nil -} - -func MsqlExec(container string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - ctx := context.Background() - // 执行/bin/bash命令 - ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{ - AttachStdin: false, - AttachStdout: true, - AttachStderr: true, - Cmd: []string{"date"}, - Tty: true, - Env: []string{"aaa=ddd"}, - }) - err = cli.ContainerExecStart(ctx, ir.ID, types.ExecStartCheck{}) - - fmt.Println(err) - - return err -} - -func Exec(container, row, col string) (hr types.HijackedResponse, err error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - ctx := context.Background() - // 执行/bin/bash命令 - ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{ - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - Env: []string{"COLUMNS=" + col, "LINES=" + row}, - Cmd: []string{"/bin/bash"}, - Tty: true, - }) - if err != nil { - return - } - // 附加到上面创建的/bin/bash进程中 - hr, err = cli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true}) - if err != nil { - return - } - return -} - -func DockerLog() { - //cli, err := client2.NewClientWithOpts(client2.FromEnv) - //ctx := context.Background() - //ir, err := cli.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{}) - //str, err := ioutil.ReadAll(ir) - //fmt.Println(string(str)) - //fmt.Println(err) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - client, _ := client2.NewClientWithOpts(client2.FromEnv) - reader, err := client.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{}) - if err != nil { - log.Fatal(err) - } - _, err = io.Copy(os.Stdout, reader) - if err != nil && err != io.EOF { - log.Fatal(err) - } -} - -func DockerLogs() { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - i, err := cli.ContainerLogs(context.Background(), "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: false, - Follow: true, - Tail: "40", - }) - if err != nil { - log.Fatal(err) - } - defer i.Close() - - hdr := make([]byte, 8) - for { - _, err := i.Read(hdr) - if err != nil { - log.Fatal(err) - } - var w io.Writer - switch hdr[0] { - case 1: - w = os.Stdout - default: - w = os.Stderr - } - count := binary.BigEndian.Uint32(hdr[4:]) - dat := make([]byte, count) - _, err = i.Read(dat) - fmt.Fprint(w, string(dat)) - } -} - -//正式内容 - -// 检查镜像是否存在 -func (ds *dockerService) IsExistImage(imageName string) bool { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return false - } - defer cli.Close() - filter := filters.NewArgs() - filter.Add("reference", imageName) - - list, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter}) - - if err == nil && len(list) > 0 { - return true - } - - return false -} - -// 安装镜像 -func (ds *dockerService) DockerPullImage(imageName string, icon, name string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - out, err := cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{}) - if err != nil { - return err - } - defer out.Close() - if err != nil { - - return err - } - //io.Copy() - buf := make([]byte, 2048*4) - for { - n, err := out.Read(buf) - if err != nil { - if err != io.EOF { - fmt.Println("read error:", err) - } - break - } - if len(icon) > 0 && len(name) > 0 { - notify := notify.Application{} - notify.Icon = icon - notify.Name = name - notify.State = "PULLING" - notify.Type = "INSTALL" - notify.Finished = false - notify.Success = true - notify.Message = string(buf[:n]) - MyService.Notify().SendInstallAppBySocket(notify) - } - - } - return err -} -func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return "", err - } - defer cli.Close() - container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name) - if err != nil { - return "", err - } - return container.ID, err -} - -// param imageName 镜像名称 -// param containerDbId 数据库的id -// param port 容器内部主端口 -// param mapPort 容器主端口映射到外部的端口 -// param tcp 容器其他tcp端口 -// param udp 容器其他udp端口 -func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) { - if len(m.NetworkModel) == 0 { - m.NetworkModel = "bridge" - } - - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return "", err - } - - defer cli.Close() - ports := make(nat.PortSet) - portMaps := make(nat.PortMap) - // ports[nat.Port(fmt.Sprint(m.PortMap)+"/tcp")] = struct{}{} - // if net != "host" { - // portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}} - // } - //port := "" - for _, portMap := range m.Ports { - // if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" { - // port = portMap.ContainerPort - // } - if portMap.Protocol == "tcp" { - - tContainer, _ := strconv.Atoi(portMap.ContainerPort) - if tContainer > 0 { - ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{} - if m.NetworkModel != "host" { - portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}} - } - } - } else if portMap.Protocol == "both" { - - tContainer, _ := strconv.Atoi(portMap.ContainerPort) - if tContainer > 0 { - ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{} - if m.NetworkModel != "host" { - portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}} - } - } - - uContainer, _ := strconv.Atoi(portMap.ContainerPort) - if uContainer > 0 { - ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{} - if m.NetworkModel != "host" { - portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}} - } - } - - } else { - uContainer, _ := strconv.Atoi(portMap.ContainerPort) - if uContainer > 0 { - ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{} - if m.NetworkModel != "host" { - portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}} - } - } - } - - } - - var envArr []string - var showENV []string - showENV = append(showENV, "casaos") - for _, e := range m.Envs { - showENV = append(showENV, e.Name) - if strings.HasPrefix(e.Value, "$") { - envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone())) - continue - } - if len(e.Value) > 0 { - if e.Value == "port_map" { - envArr = append(envArr, e.Name+"="+m.PortMap) - continue - } - envArr = append(envArr, e.Name+"="+e.Value) - } - } - - res := container.Resources{} - if m.CpuShares > 0 { - res.CPUShares = m.CpuShares - } - if m.Memory > 0 { - res.Memory = m.Memory << 20 - } - for _, p := range m.Devices { - if len(p.Path) > 0 { - res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"}) - } - } - hostConfingBind := []string{} - // volumes bind - volumes := []mount.Mount{} - for _, v := range m.Volumes { - path := v.Path - if len(path) == 0 { - path = docker.GetDir(m.Label, v.Path) - if len(path) == 0 { - continue - } - } - path = strings.ReplaceAll(path, "$AppID", m.Label) - //reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`) - //result1 := reg1.FindAllStringSubmatch(path, -1) - //if len(result1) == 0 { - err = file.IsNotExistMkDir(path) - if err != nil { - loger.Error("Failed to create a folder", zap.Any("err", err)) - continue - } - //} - // else { - // err = file.IsNotExistCreateFile(path) - // if err != nil { - // ds.log.Error("mkdir error", err) - // continue - // } - // } - - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: path, - Target: v.ContainerPath, - }) - - hostConfingBind = append(hostConfingBind, v.Path+":"+v.ContainerPath) - } - - rp := container.RestartPolicy{} - - if len(m.Restart) > 0 { - rp.Name = m.Restart - } - // healthTest := []string{} - // if len(port) > 0 { - // healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"} - // } - - // health := &container.HealthConfig{ - // Test: healthTest, - // StartPeriod: 0, - // Retries: 1000, - // } - // fmt.Print(health) - if len(m.HostName) == 0 { - m.HostName = m.Label - } - - info, err := cli.ContainerInspect(context.Background(), id) - hostConfig := &container.HostConfig{} - config := &container.Config{} - config.Labels = map[string]string{} - if err == nil { - // info.HostConfig = &container.HostConfig{} - // info.Config = &container.Config{} - // info.NetworkSettings = &types.NetworkSettings{} - hostConfig = info.HostConfig - config = info.Config - if config.Labels["casaos"] == "casaos" { - config.Cmd = m.Cmd - config.Image = m.Image - config.Env = envArr - config.Hostname = m.HostName - config.ExposedPorts = ports - } - } else { - config.Cmd = m.Cmd - config.Image = m.Image - config.Env = envArr - config.Hostname = m.HostName - config.ExposedPorts = ports - } - - config.Labels["origin"] = m.Origin - config.Labels["casaos"] = "casaos" - config.Labels["web"] = m.PortMap - config.Labels["icon"] = m.Icon - config.Labels["desc"] = m.Description - config.Labels["index"] = m.Index - config.Labels["custom_id"] = m.CustomId - config.Labels["show_env"] = strings.Join(showENV, ",") - config.Labels["protocol"] = m.Protocol - config.Labels["host"] = m.Host - config.Labels["name"] = m.Label - //container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name) - - hostConfig.Mounts = volumes - hostConfig.Binds = []string{} - hostConfig.Privileged = m.Privileged - hostConfig.CapAdd = m.CapAdd - hostConfig.NetworkMode = container.NetworkMode(m.NetworkModel) - hostConfig.RestartPolicy = rp - hostConfig.Resources = res - //hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: , Privileged: m.Privileged, CapAdd: m.CapAdd} - //if net != "host" { - - hostConfig.PortBindings = portMaps - //} - containerDb, err := cli.ContainerCreate(context.Background(), - config, - hostConfig, - &network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{m.NetworkModel: {NetworkID: "", Aliases: []string{}}}}, - nil, - m.ContainerName) - if err != nil { - return "", err - } - return containerDb.ID, err -} - -// 删除容器 -func (ds *dockerService) DockerContainerRemove(name string, update bool) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{}) - - //路径处理 - if !update { - path := docker.GetDir(name, "/config") - if !file.CheckNotExist(path) { - file.RMDir(path) - } - } - - if err != nil { - return err - } - - return err -} - -// 删除镜像 -func (ds *dockerService) DockerImageRemove(name string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{}) - - imageId := "" - -Loop: - for _, ig := range imageList { - for _, i := range ig.RepoTags { - if i == name { - imageId = ig.ID - break Loop - } - } - } - _, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{}) - return err -} - -func DockerImageRemove(name string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{}) - imageId := "" - -Loop: - for _, ig := range imageList { - fmt.Println(ig.RepoDigests) - fmt.Println(ig.Containers) - for _, i := range ig.RepoTags { - if i == name { - imageId = ig.ID - break Loop - } - } - } - _, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{}) - return err -} - -// 停止镜像 -func (ds *dockerService) DockerContainerStop(id string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - err = cli.ContainerStop(context.Background(), id, nil) - return err -} - -// 启动容器 -func (ds *dockerService) DockerContainerStart(name string) error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{}) - return err -} - -// 查看日志 -func (ds *dockerService) DockerContainerLog(name string) ([]byte, error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return []byte(""), err - } - defer cli.Close() - //body, err := cli.ContainerAttach(context.Background(), name, types.ContainerAttachOptions{Logs: true, Stream: false, Stdin: false, Stdout: false, Stderr: false}) - body, err := cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true}) - - if err != nil { - return []byte(""), err - } - - defer body.Close() - content, err := ioutil.ReadAll(body) - //content, err := ioutil.ReadAll(body) - if err != nil { - return []byte(""), err - } - return content, nil -} - -func DockerContainerStats1() error { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - dss, err := cli.ContainerStats(context.Background(), "dockermysql", false) - if err != nil { - return err - } - defer dss.Body.Close() - sts, err := ioutil.ReadAll(dss.Body) - if err != nil { - return err - } - fmt.Println(string(sts)) - return nil -} - -// 获取容器状态 -func (ds *dockerService) DockerContainerStats(name string) (string, error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return "", err - } - defer cli.Close() - dss, err := cli.ContainerStats(context.Background(), name, false) - if err != nil { - return "", err - } - defer dss.Body.Close() - sts, err := ioutil.ReadAll(dss.Body) - if err != nil { - return "", err - } - return string(sts), nil -} - -// 备份容器 -func (ds *dockerService) DockerContainerCommit(name string) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - fmt.Println(err) - } - defer cli.Close() - d, err := cli.ContainerInspect(context.Background(), name) - dss, err := cli.ContainerCommit(context.Background(), name, types.ContainerCommitOptions{Reference: "test", Config: d.Config}) - if err != nil { - fmt.Println(err) - } - fmt.Println(dss) -} - -func (ds *dockerService) DockerListByName(name string) (*types.Container, error) { - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - filter := filters.NewArgs() - filter.Add("name", name) - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter}) - if err != nil { - return &types.Container{}, err - } - if len(containers) == 0 { - return &types.Container{}, errors.New("not found") - } - return &containers[0], nil -} - -func (ds *dockerService) DockerListByImage(image, version string) (*types.Container, error) { - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - filter := filters.NewArgs() - filter.Add("ancestor", image+":"+version) - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter}) - if err != nil { - return nil, err - } - if len(containers) == 0 { - return nil, nil - } - return &containers[0], nil -} - -// 获取容器详情 -func (ds *dockerService) DockerContainerInfo(name string) (*types.ContainerJSON, error) { - - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return &types.ContainerJSON{}, err - } - defer cli.Close() - d, err := cli.ContainerInspect(context.Background(), name) - if err != nil { - return &types.ContainerJSON{}, err - } - return &d, nil -} - -// 更新容器 -// param shares cpu优先级 -// param containerDbId 数据库的id -// param port 容器内部主端口 -// param mapPort 容器主端口映射到外部的端口 -// param tcp 容器其他tcp端口 -// param udp 容器其他udp端口 -func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - //重启策略 - rp := container.RestartPolicy{ - Name: "", - MaximumRetryCount: 0, - } - if len(m.Restart) > 0 { - rp.Name = m.Restart - } - res := container.Resources{} - - if m.Memory > 0 { - res.Memory = m.Memory * 1024 * 1024 - res.MemorySwap = -1 - } - if m.CpuShares > 0 { - res.CPUShares = m.CpuShares - } - for _, p := range m.Devices { - res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"}) - } - _, err = cli.ContainerUpdate(context.Background(), id, container.UpdateConfig{RestartPolicy: rp, Resources: res}) - if err != nil { - return err - } - - return -} - -// 更新容器名称 -// param name 容器名称 -// param id 老的容器名称 -func (ds *dockerService) DockerContainerUpdateName(name, id string) (err error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return err - } - defer cli.Close() - - err = cli.ContainerRename(context.Background(), id, name) - if err != nil { - return err - } - return -} - -// 获取网络列表 -func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource { - - cli, _ := client2.NewClientWithOpts(client2.FromEnv) - defer cli.Close() - networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{}) - return networks -} -func NewDockerService() DockerService { - return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`)} -} - -func (ds *dockerService) GetDockerInfo() (types.Info, error) { - cli, err := client2.NewClientWithOpts(client2.FromEnv) - if err != nil { - return types.Info{}, err - } - defer cli.Close() - - return cli.Info(context.Background()) - -} - -// ---------------------------------------test------------------------------------ -//func ServiceCreate() { -// cli, err := client2.NewClientWithOpts(client2.FromEnv) -// r, err := cli.ServiceCreate(context.Background(), swarm.ServiceSpec{}, types.ServiceCreateOptions{}) -// if err != nil { -// fmt.Println("error", err) -// } -// -// -//} - -// func Containerd() { -// // create a new client connected to the default socket path for containerd -// cli, err := containerd.New("/run/containerd/containerd.sock") -// if err != nil { -// fmt.Println("111") -// fmt.Println(err) -// } -// defer cli.Close() - -// // create a new context with an "example" namespace -// ctx := namespaces.WithNamespace(context.Background(), "default") - -// // pull the redis image from DockerHub -// image, err := cli.Pull(ctx, "docker.io/library/busybox:latest", containerd.WithPullUnpack) -// if err != nil { -// fmt.Println("222") -// fmt.Println(err) -// } - -// // create a container -// container, err := cli.NewContainer( -// ctx, -// "test1", -// containerd.WithImage(image), -// containerd.WithNewSnapshot("redis-server-snapshot1", image), -// containerd.WithNewSpec(oci.WithImageConfig(image)), -// ) - -// if err != nil { -// fmt.Println(err) -// } -// defer container.Delete(ctx, containerd.WithSnapshotCleanup) - -// // create a task from the container -// task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio)) -// if err != nil { -// fmt.Println(err) -// } -// defer task.Delete(ctx) - -// // make sure we wait before calling start -// exitStatusC, err := task.Wait(ctx) -// if err != nil { -// fmt.Println(err) -// } - -// // call start on the task to execute the redis server -// if err = task.Start(ctx); err != nil { -// fmt.Println(err) -// } - -// fmt.Println("执行完成等待") -// // sleep for a lil bit to see the logs -// time.Sleep(3 * time.Second) - -// // kill the process and get the exit status -// if err = task.Kill(ctx, syscall.SIGTERM); err != nil { -// fmt.Println(err) -// } - -// // wait for the process to fully exit and print out the exit status - -// status := <-exitStatusC -// code, _, err := status.Result() -// if err != nil { -// fmt.Println(err) -// } -// fmt.Printf("redis-server exited with status: %d\n", code) - -// } diff --git a/service/docker_test.go b/service/docker_test.go deleted file mode 100644 index c0c99a6..0000000 --- a/service/docker_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package service - -import ( - "fmt" - "testing" -) - -//func TestDockerImageInfo(t *testing.T) { -// //DockerImageInfo() -// -// address, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:0", "0.0.0.0")) -// if err != nil { -// fmt.Println(0, err) -// } -// -// listener, err := net.ListenTCP("tcp", address) -// if err != nil { -// fmt.Println(0, err) -// } -// -// defer listener.Close() -// fmt.Println(listener.Addr().(*net.TCPAddr).Port, nil) -// -//} - -//func TestDockerNetwork(t *testing.T) { -// DockerNetwork() -//} -// -//func TestDockerPull(t *testing.T) { -// DockerPull() -//} -// -//func TestDockerLog(t *testing.T) { -// DockerLog() -//} -//func TestDockerLogs(t *testing.T) { -// DockerLogs() -//} - -func TestDockerContainerStats(t *testing.T) { - fmt.Println(DockerContainerStats1()) -} - -//func TestDockerImageRemove(t *testing.T) { -// host, domain, tld := gotld.GetSubdomain("aaa.liru-05.top", 1) -// fmt.Println(host) -// fmt.Println(domain) -// fmt.Println(tld) -//} diff --git a/service/model/o_container.go b/service/model/o_container.go deleted file mode 100644 index 69c32f7..0000000 --- a/service/model/o_container.go +++ /dev/null @@ -1,78 +0,0 @@ -/* - * @Author: LinkLeong link@icewhale.com - * @Date: 2022-05-13 18:15:46 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-13 10:56:34 - * @FilePath: /CasaOS/service/model/o_container.go - * @Description: - * @Website: https://www.casaos.io - * Copyright (c) 2022 by icewhale, All Rights Reserved. - */ -package model - -const CONTAINERTABLENAME = "o_container" - -//Soon to be removed -type AppListDBModel struct { - CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"` - Title string `json:"title"` - // ScreenshotLink model.Strings `gorm:"type:json" json:"screenshot_link,omitempty"` - ScreenshotLink string `json:"screenshot_link"` - Slogan string `json:"slogan"` - Description string `json:"description"` - //Tags model.Strings `gorm:"type:json" json:"tags"` - Tags string `json:"tags"` - Icon string `json:"icon"` - Version string `json:"version"` - ContainerId string `json:"container_id,omitempty"` - Image string `json:"image,omitempty"` - Index string `json:"index"` - CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"` - UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"` - //Port string `json:"port,omitempty"` - PortMap string `json:"port_map"` - Label string `json:"label"` - EnableUPNP bool `json:"enable_upnp"` - Envs string `json:"envs"` - Ports string `json:"ports"` - Volumes string `json:"volumes"` - Devices string `json:"devices"` - //Envs []model.Env `json:"envs"` - //Ports []model.PortMap `gorm:"type:json" json:"ports"` - //Volumes []model.PathMap `gorm:"type:json" json:"volumes"` - //Devices []model.PathMap `gorm:"type:json" json:"device"` - Position bool `json:"position"` - NetModel string `json:"net_model"` - CpuShares int64 `json:"cpu_shares"` - Memory int64 `json:"memory"` - Restart string `json:"restart"` - //Rely model.MapStrings `gorm:"type:json" json:"rely"` //[{"mysql":"id"},{"mysql":"id"}] - Origin string `json:"origin"` - HostName string `json:"host_name"` - Privileged bool `json:"privileged"` - CapAdd string `json:"cap_add"` - Cmd string `gorm:"type:json" json:"cmd"` -} - -func (p *AppListDBModel) TableName() string { - return "o_container" -} - -type MyAppList struct { - Id string `json:"id"` - Name string `json:"name"` - Icon string `json:"icon"` - State string `json:"state"` - CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"` - Index string `json:"index"` - //Order string `json:"order"` - Port string `json:"port"` - Slogan string `json:"slogan"` - Type string `json:"type"` - //Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}] - Image string `json:"image"` - Volumes string `json:"volumes"` - Latest bool `json:"latest"` - Host string `json:"host"` - Protocol string `json:"protocol"` -} diff --git a/service/service.go b/service/service.go index 3858fef..a215d56 100644 --- a/service/service.go +++ b/service/service.go @@ -21,14 +21,13 @@ var Cache *cache.Cache var MyService Repository -var WebSocketConns []*websocket.Conn -var NewVersionApp map[string]string -var SocketRun bool +var ( + WebSocketConns []*websocket.Conn + SocketRun bool +) type Repository interface { - App() AppService - //User() UserService - Docker() DockerService + // User() UserService Casa() CasaService Notify() NotifyServer Rely() RelyService @@ -39,7 +38,6 @@ type Repository interface { } func NewService(db *gorm.DB, RuntimePath string) Repository { - gatewayManagement, err := external.NewManagementService(RuntimePath) if err != nil && len(RuntimePath) > 0 { panic(err) @@ -47,8 +45,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository { return &store{ gateway: gatewayManagement, - app: NewAppService(db), - docker: NewDockerService(), casa: NewCasaService(), notify: NewNotifyService(db), rely: NewRelyService(db), @@ -60,8 +56,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository { type store struct { db *gorm.DB - app AppService - docker DockerService casa CasaService notify NotifyServer rely RelyService @@ -74,9 +68,11 @@ type store struct { func (c *store) Gateway() external.ManagementService { return c.gateway } + func (s *store) Connections() ConnectionsService { return s.connections } + func (s *store) Shares() SharesService { return s.shares } @@ -88,19 +84,11 @@ func (c *store) Rely() RelyService { func (c *store) System() SystemService { return c.system } + func (c *store) Notify() NotifyServer { - return c.notify } -func (c *store) App() AppService { - return c.app -} - -func (c *store) Docker() DockerService { - return c.docker -} - func (c *store) Casa() CasaService { return c.casa }