docker.go 40 KB

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