docker.go 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  1. package v1
  2. import (
  3. "bytes"
  4. json2 "encoding/json"
  5. "net/http"
  6. "reflect"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/IceWhaleTech/CasaOS/model"
  11. "github.com/IceWhaleTech/CasaOS/pkg/docker"
  12. upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
  13. "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
  14. ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
  15. oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
  16. port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
  17. "github.com/IceWhaleTech/CasaOS/pkg/utils/random"
  18. "github.com/IceWhaleTech/CasaOS/service"
  19. "github.com/IceWhaleTech/CasaOS/service/docker_base"
  20. model2 "github.com/IceWhaleTech/CasaOS/service/model"
  21. "github.com/IceWhaleTech/CasaOS/types"
  22. "github.com/gin-gonic/gin"
  23. "github.com/gorilla/websocket"
  24. "github.com/jinzhu/copier"
  25. uuid "github.com/satori/go.uuid"
  26. "golang.org/x/crypto/ssh"
  27. )
  28. var upgrader = websocket.Upgrader{
  29. ReadBufferSize: 1024,
  30. WriteBufferSize: 1024,
  31. CheckOrigin: func(r *http.Request) bool { return true },
  32. HandshakeTimeout: time.Duration(time.Second * 5),
  33. }
  34. //打开docker的terminal
  35. func DockerTerminal(c *gin.Context) {
  36. col := c.DefaultQuery("cols", "100")
  37. row := c.DefaultQuery("rows", "30")
  38. conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
  39. if err != nil {
  40. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
  41. return
  42. }
  43. defer conn.Close()
  44. container := c.Param("id")
  45. hr, err := service.Exec(container, row, col)
  46. if err != nil {
  47. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
  48. return
  49. }
  50. // 关闭I/O流
  51. defer hr.Close()
  52. // 退出进程
  53. defer func() {
  54. hr.Conn.Write([]byte("exit\r"))
  55. }()
  56. go func() {
  57. docker.WsWriterCopy(hr.Conn, conn)
  58. }()
  59. docker.WsReaderCopy(conn, hr.Conn)
  60. }
  61. //打开本机的ssh接口
  62. func WsSsh(c *gin.Context) {
  63. wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
  64. var logBuff = new(bytes.Buffer)
  65. quitChan := make(chan bool, 3)
  66. user := ""
  67. password := ""
  68. var login int = 1
  69. cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
  70. rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
  71. var client *ssh.Client
  72. for login != 0 {
  73. var err error
  74. wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
  75. user = docker.ReceiveWsMsgUser(wsConn, logBuff)
  76. wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
  77. wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
  78. password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
  79. wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
  80. client, err = docker.NewSshClient(user, password)
  81. if err != nil && client == nil {
  82. wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
  83. wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
  84. } else {
  85. login = 0
  86. }
  87. }
  88. if client != nil {
  89. defer client.Close()
  90. }
  91. ssConn, _ := docker.NewSshConn(cols, rows, client)
  92. defer ssConn.Close()
  93. go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
  94. go ssConn.SendComboOutput(wsConn, quitChan)
  95. go ssConn.SessionWait(quitChan)
  96. <-quitChan
  97. }
  98. //安装进度推送
  99. func SpeedPush(c *gin.Context) {
  100. //token := c.Query("token")
  101. //if len(token) == 0 || token != config.UserInfo.Token {
  102. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_AUTH_TOKEN, Message: oasis_err2.GetMsg(oasis_err2.ERROR_AUTH_TOKEN)})
  103. // return
  104. //}
  105. //ws, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
  106. //defer ws.Close()
  107. //
  108. //for {
  109. // select {
  110. // case msg := <-WSMSG:
  111. // ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintln(msg)))
  112. // }
  113. //}
  114. }
  115. // @Summary 安装app(该接口需要post json数据)
  116. // @Produce application/json
  117. // @Accept application/json
  118. // @Tags app
  119. // @Param id path int true "id"
  120. // @Param port formData int true "主端口"
  121. // @Param tcp formData string false "tcp端口"
  122. // @Param udp formData string false "udp端口"
  123. // @Param env formData string false "环境变量"
  124. // @Security ApiKeyAuth
  125. // @Success 200 {string} string "ok"
  126. // @Router /app/install/{id} [post]
  127. func InstallApp(c *gin.Context) {
  128. appId := c.Param("id")
  129. var appInfo model.ServerAppList
  130. m := model.CustomizationPostData{}
  131. c.BindJSON(&m)
  132. const CUSTOM = "custom"
  133. var dockerImage string
  134. var dockerImageVersion string
  135. //检查端口
  136. if len(m.PortMap) > 0 && m.PortMap != "0" {
  137. //c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
  138. portMap, _ := strconv.Atoi(m.PortMap)
  139. if !port2.IsPortAvailable(portMap, "tcp") {
  140. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
  141. return
  142. }
  143. }
  144. //if len(m.Port) == 0 || m.Port == "0" {
  145. // m.Port = m.PortMap
  146. //}
  147. imageArr := strings.Split(m.Image, ":")
  148. if len(imageArr) == 2 {
  149. dockerImage = imageArr[0]
  150. dockerImageVersion = imageArr[1]
  151. } else {
  152. dockerImage = m.Image
  153. dockerImageVersion = "latest"
  154. }
  155. if m.Origin != "custom" {
  156. appInfo = service.MyService.App().GetServerAppInfo(appId)
  157. } else {
  158. appInfo.Title = m.Label
  159. appInfo.Description = m.Description
  160. appInfo.Icon = m.Icon
  161. appInfo.ScreenshotLink = model.Strings{}
  162. appInfo.NetworkModel = m.NetworkModel
  163. appInfo.Tags = model.Strings{}
  164. appInfo.Tagline = ""
  165. appInfo.Index = m.Index
  166. }
  167. for _, u := range m.Ports {
  168. if u.Protocol == "udp" {
  169. t, _ := strconv.Atoi(u.CommendPort)
  170. if !port2.IsPortAvailable(t, "udp") {
  171. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  172. return
  173. }
  174. } else if u.Protocol == "tcp" {
  175. te, _ := strconv.Atoi(u.CommendPort)
  176. if !port2.IsPortAvailable(te, "tcp") {
  177. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  178. return
  179. }
  180. } else if u.Protocol == "both" {
  181. t, _ := strconv.Atoi(u.CommendPort)
  182. if !port2.IsPortAvailable(t, "udp") {
  183. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  184. return
  185. }
  186. te, _ := strconv.Atoi(u.CommendPort)
  187. if !port2.IsPortAvailable(te, "tcp") {
  188. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  189. return
  190. }
  191. }
  192. }
  193. for _, device := range m.Devices {
  194. if file.CheckNotExist(device.Path) {
  195. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
  196. return
  197. }
  198. }
  199. //restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
  200. //if len(restart) > 0 {
  201. //
  202. //}
  203. //
  204. //privileged := c.PostForm("privileged") //是否处于特权模式
  205. //if len(privileged) > 0 {
  206. //
  207. //}
  208. id := uuid.NewV4().String()
  209. var relyMap = make(map[string]string)
  210. go func() {
  211. installLog := model2.AppNotify{}
  212. installLog.CustomId = id
  213. installLog.State = 0
  214. installLog.Message = "installing rely"
  215. installLog.Speed = 10
  216. installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
  217. installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
  218. installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
  219. service.MyService.Notify().AddLog(installLog)
  220. if m.Origin != "custom" {
  221. for _, plugin := range appInfo.Plugins {
  222. if plugin == "mysql" {
  223. mid := uuid.NewV4().String()
  224. mc := docker_base.MysqlConfig{}
  225. mc.DataBasePassword = random.RandomString(6, false)
  226. mc.DataBaseDB = appInfo.Title
  227. mc.DataBaseUser = "root"
  228. mc.DataBasePort = "3306"
  229. mysqlContainerId, err := docker_base.MysqlCreate(mc, mid, m.CpuShares, m.Memory)
  230. if len(mysqlContainerId) > 0 && err == nil {
  231. mc.DataBaseHost = mid
  232. m.Envs = docker_base.MysqlFilter(mc, m.Envs)
  233. rely := model2.RelyDBModel{}
  234. rely.Type = types.RELY_TYPE_MYSQL
  235. rely.ContainerId = mysqlContainerId
  236. rely.CustomId = mid
  237. rely.ContainerCustomId = id
  238. var msqlConfig model2.MysqlConfigs
  239. //结构体转换
  240. copier.Copy(&msqlConfig, &mc)
  241. rely.Config = msqlConfig
  242. service.MyService.Rely().Create(rely)
  243. relyMap["mysql"] = mid
  244. } else {
  245. docker_base.MysqlDelete(mysqlContainerId)
  246. installLog.State = 0
  247. installLog.Speed = 30
  248. installLog.Message = err.Error()
  249. service.MyService.Notify().UpdateLog(installLog)
  250. }
  251. }
  252. }
  253. }
  254. installLog.Speed = 50
  255. installLog.Message = "pulling"
  256. service.MyService.Notify().UpdateLog(installLog)
  257. // step:下载镜像
  258. err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
  259. if err != nil {
  260. installLog.State = 0
  261. installLog.Speed = 70
  262. installLog.Message = err.Error()
  263. installLog.Type = types.NOTIFY_TYPE_ERROR
  264. service.MyService.Notify().UpdateLog(installLog)
  265. return
  266. }
  267. for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
  268. time.Sleep(time.Second)
  269. }
  270. //if {
  271. //}
  272. //step:创建容器
  273. // networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
  274. // if err != nil {
  275. // //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
  276. // installLog.State = 0
  277. // installLog.Speed = 75
  278. // installLog.Type = types.NOTIFY_TYPE_ERROR
  279. // installLog.Message = err.Error()
  280. // service.MyService.Notify().UpdateLog(installLog)
  281. // return
  282. // }
  283. containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
  284. installLog.ContainerId = containerId
  285. if err != nil {
  286. //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
  287. installLog.State = 0
  288. installLog.Speed = 80
  289. installLog.Type = types.NOTIFY_TYPE_ERROR
  290. installLog.Message = err.Error()
  291. service.MyService.Notify().UpdateLog(installLog)
  292. return
  293. } else {
  294. //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
  295. installLog.Speed = 80
  296. installLog.Message = "starting"
  297. service.MyService.Notify().UpdateLog(installLog)
  298. }
  299. //step:启动容器
  300. err = service.MyService.Docker().DockerContainerStart(id)
  301. if err != nil {
  302. //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
  303. installLog.State = 0
  304. installLog.Type = types.NOTIFY_TYPE_ERROR
  305. installLog.Speed = 90
  306. installLog.Message = err.Error()
  307. service.MyService.Notify().UpdateLog(installLog)
  308. return
  309. } else {
  310. //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
  311. installLog.Speed = 90
  312. if m.Origin != CUSTOM {
  313. installLog.Message = "setting upnp"
  314. } else {
  315. installLog.Message = "nearing completion"
  316. }
  317. service.MyService.Notify().UpdateLog(installLog)
  318. }
  319. if m.Origin != CUSTOM {
  320. //step:启动upnp
  321. if m.EnableUPNP {
  322. upnp, err := upnp2.Gateway()
  323. if err == nil {
  324. for _, p := range m.Ports {
  325. if p.Protocol == "udp" {
  326. upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  327. upnp.LocalHost = ip_helper2.GetLoclIp()
  328. tComment, _ := strconv.Atoi(p.CommendPort)
  329. upnp.AddPortMapping(tComment, tComment, "UDP")
  330. time.Sleep(time.Millisecond * 200)
  331. } else if p.Protocol == "tcp" {
  332. upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  333. upnp.LocalHost = ip_helper2.GetLoclIp()
  334. tComment, _ := strconv.Atoi(p.CommendPort)
  335. upnp.AddPortMapping(tComment, tComment, "TCP")
  336. time.Sleep(time.Millisecond * 200)
  337. } else if p.Protocol == "both" {
  338. upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  339. upnp.LocalHost = ip_helper2.GetLoclIp()
  340. tComment, _ := strconv.Atoi(p.CommendPort)
  341. upnp.AddPortMapping(tComment, tComment, "UDP")
  342. time.Sleep(time.Millisecond * 200)
  343. upnp.AddPortMapping(tComment, tComment, "TCP")
  344. time.Sleep(time.Millisecond * 200)
  345. }
  346. }
  347. }
  348. if err != nil {
  349. //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
  350. installLog.State = 0
  351. installLog.Speed = 95
  352. installLog.Type = types.NOTIFY_TYPE_ERROR
  353. installLog.Message = err.Error()
  354. service.MyService.Notify().UpdateLog(installLog)
  355. } else {
  356. //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
  357. installLog.Speed = 95
  358. installLog.Message = "checking"
  359. service.MyService.Notify().UpdateLog(installLog)
  360. }
  361. }
  362. }
  363. //step: 启动成功 检查容器状态确认启动成功
  364. container, err := service.MyService.Docker().DockerContainerInfo(id)
  365. if err != nil && container.ContainerJSONBase.State.Running {
  366. //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
  367. installLog.State = 0
  368. installLog.Speed = 100
  369. installLog.Type = types.NOTIFY_TYPE_ERROR
  370. installLog.Message = err.Error()
  371. service.MyService.Notify().UpdateLog(installLog)
  372. return
  373. } else {
  374. //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
  375. installLog.Speed = 100
  376. installLog.Message = "installed"
  377. service.MyService.Notify().UpdateLog(installLog)
  378. }
  379. rely := model.MapStrings{}
  380. copier.Copy(&rely, &relyMap)
  381. portsStr, _ := json2.Marshal(m.Ports)
  382. envsStr, _ := json2.Marshal(m.Envs)
  383. volumesStr, _ := json2.Marshal(m.Volumes)
  384. devicesStr, _ := json2.Marshal(m.Devices)
  385. //step: 保存数据到数据库
  386. md := model2.AppListDBModel{
  387. CustomId: id,
  388. Title: appInfo.Title,
  389. //ScreenshotLink: appInfo.ScreenshotLink,
  390. Slogan: appInfo.Tagline,
  391. Description: appInfo.Description,
  392. //Tags: appInfo.Tags,
  393. Icon: appInfo.Icon,
  394. Version: dockerImageVersion,
  395. ContainerId: containerId,
  396. Image: dockerImage,
  397. Index: appInfo.Index,
  398. //Port: m.Port,
  399. PortMap: m.PortMap,
  400. Label: m.Label,
  401. EnableUPNP: m.EnableUPNP,
  402. Ports: string(portsStr),
  403. Envs: string(envsStr),
  404. Volumes: string(volumesStr),
  405. Position: m.Position,
  406. NetModel: appInfo.NetworkModel,
  407. Restart: m.Restart,
  408. CpuShares: m.CpuShares,
  409. Memory: m.Memory,
  410. Devices: string(devicesStr),
  411. //Rely: rely,
  412. Origin: m.Origin,
  413. CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
  414. UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
  415. }
  416. //if appInfo.NetworkModel == "host" {
  417. // m.PortMap = m.Port
  418. //}
  419. service.MyService.App().SaveContainer(md)
  420. }()
  421. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
  422. }
  423. //// @Summary 自定义安装app(该接口需要post json数据)
  424. //// @Produce application/json
  425. //// @Accept application/json
  426. //// @Tags app
  427. //// @Param id path int true "id"
  428. //// @Param port formData int true "主端口"
  429. //// @Param tcp formData string false "tcp端口"
  430. //// @Param udp formData string false "udp端口"
  431. //// @Param env formData string false "环境变量"
  432. //// @Security ApiKeyAuth
  433. //// @Success 200 {string} string "ok"
  434. //// @Router /app/install/{id} [post]
  435. //func CustomInstallApp(c *gin.Context) {
  436. // //appId := c.Param("id")
  437. // // appInfo := service.MyService.App().GetServerAppInfo(appId)
  438. //
  439. // m := model.CustomizationPostData{}
  440. // c.BindJSON(&m)
  441. // //检查端口
  442. // if len(m.PortMap) == 0 || m.PortMap == "0" {
  443. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
  444. // return
  445. // }
  446. // if len(m.Port) == 0 || m.Port == "0" {
  447. // m.Port = m.PortMap
  448. // }
  449. //
  450. // portMap, _ := strconv.Atoi(m.PortMap)
  451. // if !port2.IsPortAvailable(portMap, "tcp") {
  452. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
  453. // return
  454. // }
  455. //
  456. // for _, u := range m.Udp {
  457. // t, _ := strconv.Atoi(u.CommendPort)
  458. // if !port2.IsPortAvailable(t, "udp") {
  459. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  460. // return
  461. // }
  462. // }
  463. //
  464. // for _, t := range m.Tcp {
  465. // te, _ := strconv.Atoi(t.CommendPort)
  466. // if !port2.IsPortAvailable(te, "tcp") {
  467. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + t.CommendPort})
  468. // return
  469. // }
  470. // }
  471. //
  472. // //restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
  473. // //if len(restart) > 0 {
  474. // //
  475. // //}
  476. // //
  477. // //privileged := c.PostForm("privileged") //是否处于特权模式
  478. // //if len(privileged) > 0 {
  479. // //
  480. // //}
  481. //
  482. // err := service.MyService.Docker().DockerPullImage(m.Image)
  483. // if err != nil {
  484. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PULL_IMAGE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PULL_IMAGE_ERROR)})
  485. // }
  486. //
  487. // id := uuid.NewV4().String()
  488. //
  489. // var relyMap = make(map[string]string)
  490. // go func() {
  491. // installLog := model2.AppNotify{}
  492. // installLog.CustomId = id
  493. // installLog.State = 0
  494. // installLog.Message = "installing rely"
  495. // installLog.Speed = 30
  496. // installLog.CreatedAt = time.Now()
  497. // installLog.UpdatedAt = time.Now()
  498. // service.MyService.Notify().AddLog(installLog)
  499. //
  500. // for !service.MyService.Docker().IsExistImage(m.Image) {
  501. // time.Sleep(time.Second)
  502. // }
  503. //
  504. // installLog.Speed = 50
  505. // installLog.Message = "pulling"
  506. // service.MyService.Notify().UpdateLog(installLog)
  507. // // step:下载镜像
  508. //
  509. // var cpd model.PostData
  510. // copier.Copy(&cpd, &m)
  511. // //step:创建容器
  512. // containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, id, cpd, m.NetworkModel, m.Image, "custom")
  513. // installLog.ContainerId = containerId
  514. // if err != nil {
  515. // //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
  516. // installLog.State = 0
  517. // installLog.Speed = 80
  518. // installLog.Message = err.Error()
  519. // service.MyService.Notify().UpdateLog(installLog)
  520. // return
  521. // } else {
  522. // //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
  523. // installLog.Speed = 80
  524. // installLog.Message = "starting"
  525. // service.MyService.Notify().UpdateLog(installLog)
  526. // }
  527. //
  528. // //step:启动容器
  529. // err = service.MyService.Docker().DockerContainerStart(id)
  530. // if err != nil {
  531. // //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
  532. // installLog.State = 0
  533. // installLog.Speed = 90
  534. // installLog.Message = err.Error()
  535. // service.MyService.Notify().UpdateLog(installLog)
  536. // return
  537. // } else {
  538. // //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
  539. // installLog.Speed = 90
  540. // installLog.Message = "setting upnp"
  541. // service.MyService.Notify().UpdateLog(installLog)
  542. // }
  543. //
  544. // //step: 启动成功 检查容器状态确认启动成功
  545. // containerStatus, err := service.MyService.Docker().DockerContainerInfo(id)
  546. // if err != nil && containerStatus.ContainerJSONBase.State.Running {
  547. // //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
  548. // installLog.State = 0
  549. // installLog.Speed = 100
  550. // installLog.Message = err.Error()
  551. // service.MyService.Notify().UpdateLog(installLog)
  552. // return
  553. // } else {
  554. // //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
  555. // installLog.Speed = 100
  556. // installLog.Message = "installed"
  557. // service.MyService.Notify().UpdateLog(installLog)
  558. // }
  559. //
  560. // rely := model.MapStrings{}
  561. //
  562. // copier.Copy(&rely, &relyMap)
  563. //
  564. // //step: 保存数据到数据库
  565. // md := model2.AppListDBModel{
  566. // CustomId: id,
  567. // Title: m.Label,
  568. // // ScreenshotLink: []string,
  569. // Slogan: "",
  570. // Description: m.Description,
  571. // // Tags: ,
  572. // Icon: m.Icon,
  573. // Version: m.Image,
  574. // ContainerId: containerId,
  575. // Image: m.Image,
  576. // Index: "",
  577. // Port: m.Port,
  578. // PortMap: m.PortMap,
  579. // Label: m.Label,
  580. // EnableUPNP: m.EnableUPNP,
  581. // UdpPorts: m.Udp,
  582. // TcpPorts: m.Tcp,
  583. // Envs: m.Envs,
  584. // Volumes: m.Volumes,
  585. // Position: m.Position,
  586. // NetModel: m.NetworkModel,
  587. // Restart: m.Restart,
  588. // CpuShares: m.CpuShares,
  589. // Memory: m.Memory,
  590. // Devices: m.Devices,
  591. // Rely: rely,
  592. // Origin: "custom",
  593. // }
  594. // if m.NetworkModel == "host" {
  595. // m.PortMap = m.Port
  596. // }
  597. // service.MyService.App().SaveContainer(md)
  598. //
  599. // }()
  600. //
  601. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
  602. //
  603. //}
  604. // @Summary 卸载app
  605. // @Produce application/json
  606. // @Accept multipart/form-data
  607. // @Tags app
  608. // @Param id path string true "容器id"
  609. // @Security ApiKeyAuth
  610. // @Success 200 {string} string "ok"
  611. // @Router /app/uninstall/{id} [delete]
  612. func UnInstallApp(c *gin.Context) {
  613. appId := c.Param("id")
  614. if len(appId) == 0 {
  615. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
  616. return
  617. }
  618. info := service.MyService.App().GetUninstallInfo(appId)
  619. //step:停止容器
  620. err := service.MyService.Docker().DockerContainerStop(appId)
  621. if err != nil {
  622. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
  623. return
  624. }
  625. //step:删除容器
  626. err = service.MyService.Docker().DockerContainerRemove(appId)
  627. if err != nil {
  628. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
  629. return
  630. }
  631. //存在镜像正在使用的情况
  632. // step:删除镜像
  633. service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)
  634. //step: 删除本地数据
  635. service.MyService.App().RemoveContainerById(appId)
  636. if info.Origin != "custom" {
  637. //step: 删除文件夹
  638. service.MyService.App().DelAppConfigDir(appId)
  639. //step: 删除install log
  640. service.MyService.Notify().DelLog(appId)
  641. // for k, v := range info.Rely {
  642. //
  643. // if k == "mysql" {
  644. // docker_base.MysqlDelete(v)
  645. // service.MyService.Rely().Delete(v)
  646. // }
  647. // }
  648. //if info.EnableUPNP {
  649. // upnp, err := upnp2.Gateway()
  650. // if err == nil {
  651. // for _, p := range info.Ports {
  652. // if p.Protocol == "udp" {
  653. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  654. // upnp.LocalHost = ip_helper2.GetLoclIp()
  655. // tComment, _ := strconv.Atoi(p.CommendPort)
  656. // upnp.DelPortMapping(tComment, "UDP")
  657. // time.Sleep(time.Millisecond * 200)
  658. // } else if p.Protocol == "tcp" {
  659. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  660. // upnp.LocalHost = ip_helper2.GetLoclIp()
  661. // tComment, _ := strconv.Atoi(p.CommendPort)
  662. // upnp.DelPortMapping(tComment, "TCP")
  663. // time.Sleep(time.Millisecond * 200)
  664. // } else if p.Protocol == "both" {
  665. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  666. // upnp.LocalHost = ip_helper2.GetLoclIp()
  667. // tComment, _ := strconv.Atoi(p.CommendPort)
  668. // upnp.DelPortMapping(tComment, "UDP")
  669. //
  670. // upnp.DelPortMapping(tComment, "TCP")
  671. // time.Sleep(time.Millisecond * 200)
  672. // }
  673. // }
  674. // }
  675. //}
  676. }
  677. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
  678. }
  679. // @Summary 修改app状态
  680. // @Produce application/json
  681. // @Accept multipart/form-data
  682. // @Tags app
  683. // @Param id path string true "appid"
  684. // @Param state query string false "是否停止 start stop restart"
  685. // @Security ApiKeyAuth
  686. // @Success 200 {string} string "ok"
  687. // @Router /app/state/{id} [put]
  688. func ChangAppState(c *gin.Context) {
  689. appId := c.Param("id")
  690. state := c.DefaultPostForm("state", "stop")
  691. var err error
  692. if state == "stop" {
  693. err = service.MyService.Docker().DockerContainerStop(appId)
  694. } else if state == "start" {
  695. err = service.MyService.Docker().DockerContainerStart(appId)
  696. } else if state == "restart" {
  697. err = service.MyService.Docker().DockerContainerStop(appId)
  698. err = service.MyService.Docker().DockerContainerStart(appId)
  699. }
  700. if err != nil {
  701. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
  702. return
  703. }
  704. info, err := service.MyService.App().GetContainerInfo(appId)
  705. if err != nil {
  706. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
  707. return
  708. }
  709. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info.State})
  710. }
  711. // @Summary 查看容器日志
  712. // @Produce application/json
  713. // @Accept application/json
  714. // @Tags app
  715. // @Param id path string true "appid"
  716. // @Security ApiKeyAuth
  717. // @Success 200 {string} string "ok"
  718. // @Router /app/logs/{id} [get]
  719. func ContainerLog(c *gin.Context) {
  720. appId := c.Param("id")
  721. log, _ := service.MyService.Docker().DockerContainerLog(appId)
  722. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
  723. }
  724. // @Summary 获取安装进度
  725. // @Produce application/json
  726. // @Accept application/json
  727. // @Tags app
  728. // @Param id path string true "容器id"
  729. // @Security ApiKeyAuth
  730. // @Success 200 {string} string "ok"
  731. // @Router /app/speed/{id} [get]
  732. func GetInstallSpeed(c *gin.Context) {
  733. id := c.Param("id")
  734. b := service.MyService.Notify().GetLog(id)
  735. b.Id = b.CustomId
  736. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
  737. }
  738. // @Summary 获取容器状态
  739. // @Produce application/json
  740. // @Accept application/json
  741. // @Tags app
  742. // @Param id path string true "容器id"
  743. // @Param type query string false "type=1"
  744. // @Security ApiKeyAuth
  745. // @Success 200 {string} string "ok"
  746. // @Router /app/state/{id} [get]
  747. func GetContainerState(c *gin.Context) {
  748. id := c.Param("id")
  749. t := c.DefaultQuery("type", "0")
  750. containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
  751. if e != nil {
  752. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: e.Error()})
  753. return
  754. }
  755. var data = make(map[string]interface{})
  756. data["state"] = containerInfo.State
  757. if t == "1" {
  758. appInfo := service.MyService.App().GetAppDBInfo(id)
  759. data["app"] = appInfo
  760. }
  761. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
  762. }
  763. // @Summary 更新设置
  764. // @Produce application/json
  765. // @Accept multipart/form-data
  766. // @Tags app
  767. // @Param id path string true "容器id"
  768. // @Param shares formData string false "cpu权重"
  769. // @Param mem formData string false "内存大小MB"
  770. // @Param restart formData string false "重启策略"
  771. // @Param label formData string false "应用名称"
  772. // @Param position formData bool true "是否放到首页"
  773. // @Security ApiKeyAuth
  774. // @Success 200 {string} string "ok"
  775. // @Router /app/update/{id}/setting [put]
  776. func UpdateSetting(c *gin.Context) {
  777. id := c.Param("id")
  778. const CUSTOM = "custom"
  779. m := model.CustomizationPostData{}
  780. c.BindJSON(&m)
  781. if len(id) == 0 {
  782. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
  783. return
  784. }
  785. var cpd model.CustomizationPostData
  786. copier.Copy(&cpd, &m)
  787. appInfo := service.MyService.App().GetAppDBInfo(id)
  788. var containerId string
  789. containerId = appInfo.ContainerId
  790. service.MyService.Docker().DockerContainerStop(id)
  791. portMap, _ := strconv.Atoi(m.PortMap)
  792. if !port2.IsPortAvailable(portMap, "tcp") {
  793. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
  794. return
  795. }
  796. for _, u := range m.Ports {
  797. if u.Protocol == "udp" {
  798. t, _ := strconv.Atoi(u.CommendPort)
  799. if !port2.IsPortAvailable(t, "udp") {
  800. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  801. return
  802. }
  803. } else if u.Protocol == "tcp" {
  804. te, _ := strconv.Atoi(u.CommendPort)
  805. if !port2.IsPortAvailable(te, "tcp") {
  806. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  807. return
  808. }
  809. } else if u.Protocol == "both" {
  810. t, _ := strconv.Atoi(u.CommendPort)
  811. if !port2.IsPortAvailable(t, "udp") {
  812. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  813. return
  814. }
  815. te, _ := strconv.Atoi(u.CommendPort)
  816. if !port2.IsPortAvailable(te, "tcp") {
  817. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
  818. return
  819. }
  820. }
  821. }
  822. //如果容器端口均未修改,这不进行处理
  823. portsStr, _ := json2.Marshal(m.Ports)
  824. envsStr, _ := json2.Marshal(m.Envs)
  825. volumesStr, _ := json2.Marshal(m.Volumes)
  826. devicesStr, _ := json2.Marshal(m.Devices)
  827. if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
  828. var newUUid = uuid.NewV4().String()
  829. var err error
  830. // networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetModel)
  831. // if err != nil {
  832. // c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
  833. // return
  834. // }
  835. containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)
  836. if err != nil {
  837. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
  838. return
  839. }
  840. err = service.MyService.Docker().DockerContainerRemove(id)
  841. if err != nil {
  842. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
  843. return
  844. }
  845. service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
  846. if err != nil {
  847. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
  848. return
  849. }
  850. } else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
  851. service.MyService.Docker().DockerContainerUpdate(cpd, id)
  852. }
  853. err := service.MyService.Docker().DockerContainerStart(id)
  854. if err != nil {
  855. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
  856. return
  857. }
  858. //更新upnp
  859. if m.Origin != CUSTOM {
  860. //if appInfo.EnableUPNP != appInfo.EnableUPNP {
  861. // if appInfo.EnableUPNP {
  862. // upnp, err := upnp2.Gateway()
  863. // if err == nil {
  864. //
  865. // for _, p := range appInfo.Ports {
  866. // if p.Protocol == "udp" {
  867. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  868. // upnp.LocalHost = ip_helper2.GetLoclIp()
  869. // tComment, _ := strconv.Atoi(p.CommendPort)
  870. // upnp.AddPortMapping(tComment, tComment, "UDP")
  871. // time.Sleep(time.Millisecond * 200)
  872. // } else if p.Protocol == "tcp" {
  873. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  874. // upnp.LocalHost = ip_helper2.GetLoclIp()
  875. // tComment, _ := strconv.Atoi(p.CommendPort)
  876. // upnp.AddPortMapping(tComment, tComment, "TCP")
  877. // time.Sleep(time.Millisecond * 200)
  878. // } else if p.Protocol == "both" {
  879. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  880. // upnp.LocalHost = ip_helper2.GetLoclIp()
  881. // tComment, _ := strconv.Atoi(p.CommendPort)
  882. // upnp.AddPortMapping(tComment, tComment, "UDP")
  883. // time.Sleep(time.Millisecond * 200)
  884. //
  885. // upnp.AddPortMapping(tComment, tComment, "TCP")
  886. // time.Sleep(time.Millisecond * 200)
  887. // }
  888. // }
  889. // }
  890. // } else {
  891. // upnp, err := upnp2.Gateway()
  892. // if err == nil {
  893. // for _, p := range appInfo.Ports {
  894. // if p.Protocol == "udp" {
  895. //
  896. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  897. // upnp.LocalHost = ip_helper2.GetLoclIp()
  898. // tComment, _ := strconv.Atoi(p.CommendPort)
  899. // upnp.DelPortMapping(tComment, "UDP")
  900. // time.Sleep(time.Millisecond * 200)
  901. // } else if p.Protocol == "tcp" {
  902. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  903. // upnp.LocalHost = ip_helper2.GetLoclIp()
  904. // tComment, _ := strconv.Atoi(p.CommendPort)
  905. // upnp.DelPortMapping(tComment, "TCP")
  906. // time.Sleep(time.Millisecond * 200)
  907. // } else if p.Protocol == "both" {
  908. // upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
  909. // upnp.LocalHost = ip_helper2.GetLoclIp()
  910. // tComment, _ := strconv.Atoi(p.CommendPort)
  911. // upnp.DelPortMapping(tComment, "UDP")
  912. // time.Sleep(time.Millisecond * 200)
  913. //
  914. // upnp.DelPortMapping(tComment, "TCP")
  915. // time.Sleep(time.Millisecond * 200)
  916. // }
  917. // }
  918. // }
  919. // }
  920. //}
  921. }
  922. appInfo.ContainerId = containerId
  923. appInfo.PortMap = m.PortMap
  924. appInfo.Label = m.Label
  925. appInfo.Index = m.Index
  926. appInfo.Ports = string(portsStr)
  927. appInfo.Envs = string(envsStr)
  928. appInfo.Icon = m.Icon
  929. appInfo.Volumes = string(volumesStr)
  930. appInfo.Devices = string(devicesStr)
  931. appInfo.NetModel = m.NetworkModel
  932. appInfo.Position = m.Position
  933. appInfo.EnableUPNP = m.EnableUPNP
  934. appInfo.Restart = m.Restart
  935. appInfo.Memory = m.Memory
  936. appInfo.CpuShares = m.CpuShares
  937. appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
  938. service.MyService.App().UpdateApp(appInfo)
  939. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
  940. }
  941. // @Summary 获取容器详情
  942. // @Produce application/json
  943. // @Accept application/json
  944. // @Tags app
  945. // @Param id path string true "appid"
  946. // @Security ApiKeyAuth
  947. // @Success 200 {string} string "ok"
  948. // @Router /app/info/{id} [get]
  949. func ContainerInfo(c *gin.Context) {
  950. appId := c.Param("id")
  951. appInfo := service.MyService.App().GetAppDBInfo(appId)
  952. containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
  953. var cpuModel = "arm"
  954. if cpu := service.MyService.ZiMa().GetCpuInfo(); len(cpu) > 0 {
  955. if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
  956. cpuModel = "intel"
  957. } else if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "amd") > 0 {
  958. cpuModel = "amd"
  959. }
  960. }
  961. info, err := service.MyService.Docker().DockerContainerInfo(appId)
  962. if err != nil {
  963. //todo 需要自定义错误
  964. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
  965. return
  966. }
  967. con := struct {
  968. Status string `json:"status"`
  969. StartedAt string `json:"started_at"`
  970. CPUShares int64 `json:"cpu_shares"`
  971. Memory int64 `json:"memory"`
  972. Restart string `json:"restart"`
  973. }{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
  974. data := make(map[string]interface{}, 5)
  975. data["app"] = appInfo
  976. data["cpu"] = cpuModel
  977. data["memory"] = service.MyService.ZiMa().GetMemInfo().Total
  978. data["container"] = json2.RawMessage(containerInfo)
  979. data["info"] = con
  980. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
  981. }
  982. // @Summary 获取安装所需要的数据
  983. // @Produce application/json
  984. // @Accept application/json
  985. // @Tags app
  986. // @Security ApiKeyAuth
  987. // @Success 200 {string} string "ok"
  988. // @Router /app/install/config [get]
  989. func GetDockerInstallConfig(c *gin.Context) {
  990. networks := service.MyService.Docker().DockerNetworkModelList()
  991. data := make(map[string]interface{}, 2)
  992. list := []map[string]string{}
  993. for _, network := range networks {
  994. if network.Driver != "null" {
  995. list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
  996. }
  997. }
  998. data["networks"] = list
  999. data["memory"] = service.MyService.ZiMa().GetMemInfo()
  1000. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
  1001. }
  1002. // @Summary 获取依赖数据
  1003. // @Produce application/json
  1004. // @Accept application/json
  1005. // @Tags app
  1006. // @Param id path string true "rely id"
  1007. // @Security ApiKeyAuth
  1008. // @Success 200 {string} string "ok"
  1009. // @Router /app/rely/{id}/info [get]
  1010. func ContainerRelyInfo(c *gin.Context) {
  1011. id := c.Param("id")
  1012. appInfo := service.MyService.Rely().GetInfo(id)
  1013. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: appInfo})
  1014. }
  1015. // @Summary 获取可更新数据
  1016. // @Produce application/json
  1017. // @Accept application/json
  1018. // @Tags app
  1019. // @Param id path string true "appid"
  1020. // @Security ApiKeyAuth
  1021. // @Success 200 {string} string "ok"
  1022. // @Router /app/update/{id}/info [get]
  1023. func ContainerUpdateInfo(c *gin.Context) {
  1024. appId := c.Param("id")
  1025. appInfo := service.MyService.App().GetAppDBInfo(appId)
  1026. info, err := service.MyService.Docker().DockerContainerInfo(appId)
  1027. if err != nil {
  1028. //todo 需要自定义错误
  1029. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
  1030. return
  1031. }
  1032. var port model.PortArrey
  1033. json2.Unmarshal([]byte(appInfo.Ports), &port)
  1034. var envs model.EnvArrey
  1035. json2.Unmarshal([]byte(appInfo.Envs), &envs)
  1036. var vol model.PathArrey
  1037. json2.Unmarshal([]byte(appInfo.Volumes), &vol)
  1038. var dir model.PathArrey
  1039. json2.Unmarshal([]byte(appInfo.Devices), &dir)
  1040. //volumesStr, _ := json2.Marshal(m.Volumes)
  1041. //devicesStr, _ := json2.Marshal(m.Devices)
  1042. m := model.CustomizationPostData{}
  1043. m.Index = appInfo.Index
  1044. m.Icon = appInfo.Icon
  1045. m.Ports = port
  1046. m.Image = appInfo.Image + ":" + appInfo.Version
  1047. m.Origin = appInfo.Origin
  1048. m.NetworkModel = appInfo.NetModel
  1049. m.Description = appInfo.Description
  1050. m.Label = appInfo.Label
  1051. m.PortMap = appInfo.PortMap
  1052. m.Devices = dir //appInfo.Devices
  1053. m.Envs = envs
  1054. m.Memory = info.HostConfig.Memory >> 20
  1055. m.CpuShares = info.HostConfig.CPUShares
  1056. m.Volumes = vol //appInfo.Volumes
  1057. m.Restart = info.HostConfig.RestartPolicy.Name
  1058. m.EnableUPNP = appInfo.EnableUPNP
  1059. m.Position = appInfo.Position
  1060. c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
  1061. }
  1062. ////准备安装(暂时不需要)
  1063. //func ReadyInstall(c *gin.Context) {
  1064. // _, tcp, udp := service.MyService.GetManifestJsonByRepo()
  1065. // data := make(map[string]interface{}, 2)
  1066. // if t := gjson.Parse(tcp).Array(); len(t) > 0 {
  1067. // //tcpList := []model.TcpPorts{}
  1068. // //e := json2.Unmarshal([]byte(tcp), tcpList)
  1069. // //if e!=nil {
  1070. // // return
  1071. // //}
  1072. // //for _, port := range tcpList {
  1073. // // if port.ContainerPort>0&&port.ExtranetPort {
  1074. // //
  1075. // // }
  1076. // //}
  1077. // var inarr []interface{}
  1078. // for _, result := range t {
  1079. //
  1080. // var p int
  1081. // ok := true
  1082. // for ok {
  1083. // p, _ = port.GetAvailablePort()
  1084. // ok = !port.IsPortAvailable(p)
  1085. // }
  1086. // pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
  1087. // inarr = append(inarr, pm)
  1088. // }
  1089. // data["tcp"] = inarr
  1090. // }
  1091. // if u := gjson.Parse(udp).Array(); len(u) > 0 {
  1092. // //udpList := []model.UdpPorts{}
  1093. // //e := json2.Unmarshal([]byte(udp), udpList)
  1094. // //if e != nil {
  1095. // // return
  1096. // //}
  1097. // var inarr []model.PortMap
  1098. // for _, result := range u {
  1099. // var p int
  1100. // ok := true
  1101. // for ok {
  1102. // p, _ = port.GetAvailablePort()
  1103. // ok = !port.IsPortAvailable(p)
  1104. // }
  1105. // pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
  1106. // inarr = append(inarr, pm)
  1107. // }
  1108. // data["udp"] = inarr
  1109. // }
  1110. // c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
  1111. //}