bilihub.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "go-common/app/admin/ep/merlin/model"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. )
  12. // AuthHub Auth Hub.
  13. func (s *Service) AuthHub(c context.Context, sessionID string) (err error) {
  14. return s.dao.AuthHub(c, sessionID)
  15. }
  16. // AccessAuthHub Access Auth Hub.
  17. func (s *Service) AccessAuthHub(c context.Context, username string) (accessHub bool, err error) {
  18. var (
  19. personProjectID int
  20. )
  21. if personProjectID, err = s.ProjectID(c, username); err != nil {
  22. return
  23. }
  24. if personProjectID > 0 {
  25. accessHub = true
  26. }
  27. return
  28. }
  29. // ProjectID Get Project ID.
  30. func (s *Service) ProjectID(c context.Context, projectName string) (projectID int, err error) {
  31. var hubProjects []*model.HubProject
  32. if hubProjects, err = s.dao.HubProjects(c, projectName); err != nil {
  33. return
  34. }
  35. for _, hubProject := range hubProjects {
  36. if projectName == hubProject.Name {
  37. projectID = hubProject.ProjectID
  38. return
  39. }
  40. }
  41. return
  42. }
  43. // ProjectRepositories Get Project Repositories.
  44. func (s *Service) ProjectRepositories(c context.Context, projectID, pn, ps int, keyWord string) (p *model.PaginateProjectRepoRecord, err error) {
  45. var (
  46. total int
  47. projectRepos []*model.ProjectRepository
  48. )
  49. if total, err = s.dao.ProjectRepoCount(c, projectID); err != nil {
  50. return
  51. }
  52. if projectRepos, err = s.dao.ProjectRepos(c, projectID, pn, ps, keyWord); err != nil {
  53. return
  54. }
  55. p = &model.PaginateProjectRepoRecord{
  56. PageNum: pn,
  57. PageSize: ps,
  58. Total: total,
  59. ProjectRepository: projectRepos,
  60. }
  61. return
  62. }
  63. // AccessPullProjects Access Pull Projects.
  64. func (s *Service) AccessPullProjects(c context.Context, username string) (projectsName []string, err error) {
  65. var accessToHub bool
  66. if accessToHub, err = s.AccessAuthHub(c, username); err != nil {
  67. return
  68. }
  69. if accessToHub {
  70. projectsName = append(projectsName, s.c.BiliHub.HostName+"/"+username)
  71. }
  72. projectsName = append(projectsName, s.c.BiliHub.HostName+"/"+s.c.BiliHub.SharePub)
  73. return
  74. }
  75. // Projects Get Projects.
  76. func (s *Service) Projects(c context.Context, username string) (projects map[string]int, err error) {
  77. var (
  78. personProjectID int
  79. merlinProjectID int
  80. publicProjectID int
  81. )
  82. projects = make(map[string]int)
  83. if personProjectID, err = s.ProjectID(c, username); err != nil {
  84. return
  85. }
  86. projects[username] = personProjectID
  87. if merlinProjectID, err = s.ProjectID(c, s.c.BiliHub.MerlinPub); err != nil {
  88. return
  89. }
  90. projects[s.c.BiliHub.MerlinPub] = merlinProjectID
  91. if publicProjectID, err = s.ProjectID(c, s.c.BiliHub.SharePub); err != nil {
  92. return
  93. }
  94. projects[s.c.BiliHub.SharePub] = publicProjectID
  95. return
  96. }
  97. // RepositoryTags Get Repository Tags.
  98. func (s *Service) RepositoryTags(c context.Context, repoName string) (repoTags []*model.RepositoryTag, err error) {
  99. var (
  100. repoTagsRet []*model.RepositoryTagResponse
  101. imageFullNamePrefix = s.c.BiliHub.HostName + "/" + repoName + ":"
  102. )
  103. if repoTagsRet, err = s.dao.RepoTags(c, repoName); err != nil {
  104. return
  105. }
  106. for _, repoTagRet := range repoTagsRet {
  107. // ignore image that size is 0
  108. if repoTagRet.Size == 0 {
  109. continue
  110. }
  111. repoTag := &model.RepositoryTag{
  112. RepositoryTagResponse: *repoTagRet,
  113. ImageFullName: imageFullNamePrefix + repoTagRet.Name,
  114. }
  115. repoTags = append(repoTags, repoTag)
  116. }
  117. return
  118. }
  119. // DeleteRepositoryTag Delete Repository Tag.
  120. func (s *Service) DeleteRepositoryTag(c context.Context, username, repoName, tagName string) (status int, err error) {
  121. var hasRight bool
  122. if hasRight = s.hasOperateHubRight(username, repoName); !hasRight {
  123. status = -1
  124. err = ecode.MerlinHubNoRight
  125. return
  126. }
  127. if err = s.dao.DeleteRepoTag(c, repoName, tagName); err != nil {
  128. status = -1
  129. }
  130. return
  131. }
  132. // DeleteRepository Delete Repository.
  133. func (s *Service) DeleteRepository(c context.Context, username, repoName string) (status int, err error) {
  134. var hasRight bool
  135. if hasRight = s.hasOperateHubRight(username, repoName); !hasRight {
  136. status = -1
  137. err = ecode.MerlinHubNoRight
  138. return
  139. }
  140. if err = s.dao.DeleteRepo(c, repoName); err != nil {
  141. status = -1
  142. }
  143. return
  144. }
  145. // AddRepositoryTag Add Repository Tag.
  146. func (s *Service) AddRepositoryTag(c context.Context, username, repoName, tagName, newRepoName, newTagName string) (status int, err error) {
  147. //操作src image 权限认证
  148. var hasRight bool
  149. if hasRight = s.hasOperateHubRight(username, repoName); !hasRight {
  150. status = -1
  151. err = ecode.MerlinHubNoRight
  152. return
  153. }
  154. //上传的src image权限认证。如果上传的路径 只能为公共路径和个人路径
  155. if strings.Split(newRepoName, "/")[0] != s.c.BiliHub.SharePub {
  156. if hasRight = s.hasOperateHubRight(username, newRepoName); !hasRight {
  157. status = -1
  158. err = ecode.MerlinHubNoRight
  159. return
  160. }
  161. }
  162. imageSrcName := s.getFullRepoName(repoName, tagName)
  163. imageTagName := s.getFullRepoName(newRepoName, newTagName)
  164. // pull and push image
  165. s.dao.ImageTask(func() {
  166. s.PullAndPush(username, imageSrcName, imageTagName, 0)
  167. })
  168. return
  169. }
  170. // AddTagToMachine Add Tag To Machine.
  171. func (s *Service) AddTagToMachine(c context.Context, username, imageSrcName string, machineIDs []int64) (machineImageMap map[int64]string, err error) {
  172. machineImageMap = map[int64]string{}
  173. for _, machineID := range machineIDs {
  174. repoName := strings.Split(imageSrcName, ":")[0]
  175. absRepoName := strings.Replace(repoName, "/", "-", -1)
  176. newRepoName := s.c.BiliHub.MachineTagPri + "/" + absRepoName
  177. newTagName := strconv.FormatInt(machineID, 10) + "-" + time.Now().Format("20060102150405")
  178. imageTagName := s.getFullRepoName(newRepoName, newTagName)
  179. if _, err = s.PullAndPush(username, imageSrcName, imageTagName, machineID); err != nil {
  180. return
  181. }
  182. machineImageMap[machineID] = imageTagName
  183. }
  184. return
  185. }
  186. // GetAllImagesInDocker Get All Images In Docker.
  187. func (s *Service) GetAllImagesInDocker() (imageNames []string, err error) {
  188. return s.dao.ImageGetAll()
  189. }
  190. // hasOperateHubRight has Operate HubRight.
  191. func (s *Service) hasOperateHubRight(username, repoName string) (hasRight bool) {
  192. //判断是否又权限执行操作
  193. if username == strings.Split(repoName, "/")[0] {
  194. hasRight = true
  195. return
  196. }
  197. for _, super := range s.c.BiliHub.SuperOwner {
  198. if username == super {
  199. hasRight = true
  200. return
  201. }
  202. }
  203. return
  204. }
  205. // get Full RepoName getFullRepoName.
  206. func (s *Service) getFullRepoName(repoName, tagName string) string {
  207. return s.c.BiliHub.HostName + "/" + repoName + ":" + tagName
  208. }
  209. //Push Push.
  210. func (s *Service) Push(c context.Context, username, repoName, tagName string, machineID int64) (status int, err error) {
  211. imageSrcName := s.getFullRepoName(repoName, tagName)
  212. log.Info("start Push target %s", imageSrcName)
  213. if err = s.dao.ImagePush(imageSrcName); err != nil {
  214. status = model.ImagePushErr
  215. log.Error("ImagePush target %s,err (%+v)", imageSrcName, err)
  216. }
  217. hubImageLog := &model.HubImageLog{
  218. UserName: username,
  219. MachineID: machineID,
  220. ImageSrc: "",
  221. ImageTag: imageSrcName,
  222. Status: status,
  223. OperateType: model.ImagePush,
  224. }
  225. s.dao.InsertHubImageLog(hubImageLog)
  226. log.Info("end Push target %s", imageSrcName)
  227. return
  228. }
  229. // ReTag ReTag.
  230. func (s *Service) ReTag(c context.Context, username, repoName, tagName, newRepoName, newTagName string, machineID int64) (status int, err error) {
  231. imageSrcName := s.getFullRepoName(repoName, tagName)
  232. imageTagName := s.getFullRepoName(newRepoName, newTagName)
  233. log.Info("start ReTag source %s tag %s", imageSrcName, imageTagName)
  234. if err = s.dao.ImageTag(imageSrcName, imageTagName); err != nil {
  235. status = model.ImageReTagErr
  236. log.Error("ImageTag source %s, target %s,err (%+v)", imageSrcName, imageTagName, err)
  237. }
  238. hubImageLog := &model.HubImageLog{
  239. UserName: username,
  240. MachineID: machineID,
  241. ImageSrc: imageSrcName,
  242. ImageTag: imageTagName,
  243. Status: status,
  244. OperateType: model.ImageTag,
  245. }
  246. s.dao.InsertHubImageLog(hubImageLog)
  247. log.Info("end ReTag source %s, tag %s", imageSrcName, imageTagName)
  248. return
  249. }
  250. // Pull Pull.
  251. func (s *Service) Pull(c context.Context, username, repoName, tagName string, machineID int64) (status int, err error) {
  252. imageSrcName := s.getFullRepoName(repoName, tagName)
  253. log.Info("start Pull source %s", imageSrcName)
  254. if err = s.dao.ImagePull(imageSrcName); err != nil {
  255. status = model.ImagePullErr
  256. log.Error("ImagePull source %s,err (%+v)", imageSrcName, err)
  257. }
  258. hubImageLog := &model.HubImageLog{
  259. UserName: username,
  260. MachineID: machineID,
  261. ImageSrc: imageSrcName,
  262. ImageTag: "",
  263. Status: status,
  264. OperateType: model.ImagePull,
  265. }
  266. s.dao.InsertHubImageLog(hubImageLog)
  267. log.Info("end Pull source %s", imageSrcName)
  268. return
  269. }
  270. // CreateSnapShot CreateSnapShot.
  271. func (s *Service) CreateSnapShot(c context.Context, username string, machineID int64) (status int, err error) {
  272. status = -1
  273. //获取镜像名称
  274. var (
  275. machine *model.Machine
  276. passMachineDetail *model.PaasMachineDetail
  277. pqadmr *model.PaasQueryAndDelMachineRequest
  278. tmpSnapshotRecord *model.SnapshotRecord
  279. )
  280. if machine, err = s.dao.QueryMachine(machineID); err != nil {
  281. return
  282. }
  283. pqadmr = machine.ToPaasQueryAndDelMachineRequest()
  284. if passMachineDetail, err = s.dao.QueryPaasMachine(c, pqadmr); err != nil {
  285. return
  286. }
  287. snapshotRecord := &model.SnapshotRecord{
  288. MachineID: machineID,
  289. ImageName: passMachineDetail.Image,
  290. Username: username,
  291. Status: model.SnapshotInit,
  292. }
  293. if tmpSnapshotRecord, err = s.dao.FindSnapshotRecord(machineID); err != nil {
  294. return
  295. }
  296. if tmpSnapshotRecord.ID == 0 {
  297. //首次快照 插入
  298. if err = s.dao.InsertSnapshotRecord(snapshotRecord); err != nil {
  299. return
  300. }
  301. } else if tmpSnapshotRecord.Status == model.SnapshotDoing {
  302. //有快照记录,查看是否正在进行中
  303. err = ecode.MerlinSnapshotInDoingErr
  304. return
  305. } else if err = s.dao.UpdateSnapshotRecord(snapshotRecord); err != nil {
  306. return
  307. }
  308. //创建快照
  309. resultStatus := model.SnapshotDoing
  310. if _, err = s.dao.SnapshotPaasMachineStatus(c, pqadmr); err != nil {
  311. resultStatus = model.SnapShotFailed
  312. }
  313. if err = s.dao.UpdateSnapshotRecordStatus(machineID, resultStatus); err != nil {
  314. return
  315. }
  316. status = 0
  317. return
  318. }
  319. // QuerySnapShot Query SnapShot.
  320. func (s *Service) QuerySnapShot(c context.Context, machineID int64) (snapshotRecord *model.SnapshotRecord, err error) {
  321. return s.dao.FindSnapshotRecord(machineID)
  322. }
  323. // QueryMachine2ImageLog Query Machine to ImageLog.
  324. func (s *Service) QueryMachine2ImageLog(c context.Context, queryRequest *model.QueryMachine2ImageLogRequest) (p *model.PaginateHubImageLog, err error) {
  325. var (
  326. hubImageLogs []*model.HubImageLog
  327. total int64
  328. )
  329. if total, hubImageLogs, err = s.dao.FindHubMachine2ImageLog(queryRequest); err != nil {
  330. return
  331. }
  332. p = &model.PaginateHubImageLog{
  333. PageNum: queryRequest.PageNum,
  334. PageSize: queryRequest.PageSize,
  335. Total: total,
  336. HubImageLogs: hubImageLogs,
  337. }
  338. return
  339. }
  340. // CallBackSnapShot Call Back SnapShot.
  341. func (s *Service) CallBackSnapShot(c context.Context, machineName, imageName, msg string, resultStatus bool) (err error) {
  342. var (
  343. machine *model.Machine
  344. snapshotResultStatus string
  345. )
  346. if machine, err = s.dao.QueryOnlineMachineByName(machineName); err != nil {
  347. return
  348. }
  349. if resultStatus {
  350. snapshotResultStatus = model.SnapshotSuccess
  351. } else {
  352. snapshotResultStatus = model.SnapShotFailed
  353. }
  354. err = s.dao.UpdateSnapshotRecordStatus(machine.ID, snapshotResultStatus)
  355. return
  356. }
  357. // Machine2Image Machine to Image.
  358. func (s *Service) Machine2Image(c context.Context, username, imageName, newImageName string, machineID int64) (err error) {
  359. var (
  360. accessToHub bool
  361. hubImageLog *model.HubImageLog
  362. hubImageLogs []*model.HubImageLog
  363. machine *model.Machine
  364. passMachineDetail *model.PaasMachineDetail
  365. )
  366. //判断镜像和机器是否一致
  367. if machine, err = s.dao.QueryMachine(machineID); err != nil {
  368. return
  369. }
  370. if passMachineDetail, err = s.dao.QueryPaasMachine(c, machine.ToPaasQueryAndDelMachineRequest()); err != nil {
  371. return
  372. }
  373. if passMachineDetail.Image != imageName {
  374. err = ecode.MerlinMachineImageNotSameErr
  375. return
  376. }
  377. //判断有无授权hub
  378. if accessToHub, err = s.AccessAuthHub(c, username); err != nil {
  379. return
  380. }
  381. if !accessToHub {
  382. err = ecode.MerlinHubNoRight
  383. return
  384. }
  385. //判断new image name是否重名
  386. if hubImageLog, err = s.dao.FindHubImageLogByImageTag(newImageName); err != nil {
  387. return
  388. }
  389. if hubImageLog.ID > 0 {
  390. err = ecode.MerlinDuplicateImageNameErr
  391. return
  392. }
  393. //判断该机器是否有正在进行的机器转镜像任务
  394. if hubImageLogs, err = s.dao.FindHubImageLogByMachineID(machineID); err != nil {
  395. return
  396. }
  397. for _, hil := range hubImageLogs {
  398. if hil.OperateType == model.ImageMachine2Image && hil.Status == model.ImageInit {
  399. err = ecode.MerlinMachine2ImageInDoingErr
  400. return
  401. }
  402. }
  403. status := model.ImageInit
  404. newHubImageLog := &model.HubImageLog{
  405. UserName: username,
  406. MachineID: machineID,
  407. ImageSrc: imageName,
  408. ImageTag: newImageName,
  409. Status: status,
  410. OperateType: model.ImageMachine2Image,
  411. }
  412. if err = s.dao.InsertHubImageLog(newHubImageLog); err != nil {
  413. return
  414. }
  415. s.dao.ImageTask(func() {
  416. s.PullAndPushWithMachine2Image(username, imageName, newImageName, machineID, newHubImageLog.ID)
  417. })
  418. return
  419. }
  420. // PullAndPush pull And Push.
  421. func (s *Service) PullAndPush(username, imageSrcName, imageTagName string, machineID int64) (status int, err error) {
  422. log.Info("start pullAndPush source %s, target %s", imageSrcName, imageTagName)
  423. //pull image
  424. if err = s.dao.ImagePull(imageSrcName); err != nil {
  425. status = model.ImagePullErr
  426. log.Error("ImagePull source %s,err (%+v)", imageSrcName, err)
  427. } else if err = s.dao.ImageTag(imageSrcName, imageTagName); err != nil {
  428. status = model.ImageReTagErr
  429. log.Error("ImageTag source %s, target %s,err (%+v)", imageSrcName, imageTagName, err)
  430. } else if err = s.dao.ImagePush(imageTagName); err != nil {
  431. status = model.ImagePushErr
  432. log.Error("ImagePush target %s,err (%+v)", imageTagName, err)
  433. }
  434. hubImageLog := &model.HubImageLog{
  435. UserName: username,
  436. MachineID: machineID,
  437. ImageSrc: imageSrcName,
  438. ImageTag: imageTagName,
  439. Status: status,
  440. OperateType: model.ImagePullAndPush,
  441. }
  442. s.dao.InsertHubImageLog(hubImageLog)
  443. log.Info("end pullAndPush source %s, target %s", imageSrcName, imageTagName)
  444. return
  445. }
  446. // PullAndPushWithMachine2Image Pull And Push With Machine to Image.
  447. func (s *Service) PullAndPushWithMachine2Image(username, imageSrcName, imageTagName string, machineID, hubImageLogID int64) (status int, err error) {
  448. log.Info("start PullAndPushWithMachine2Image source %s, target %s", imageSrcName, imageTagName)
  449. status = model.ImageSuccess
  450. //pull image
  451. if err = s.dao.ImagePull(imageSrcName); err != nil {
  452. status = model.ImagePullErr
  453. log.Error("ImagePull source %s,err (%+v)", imageSrcName, err)
  454. } else if err = s.dao.ImageTag(imageSrcName, imageTagName); err != nil {
  455. status = model.ImageReTagErr
  456. log.Error("ImageTag source %s, target %s,err (%+v)", imageSrcName, imageTagName, err)
  457. } else if err = s.dao.ImagePush(imageTagName); err != nil {
  458. status = model.ImagePushErr
  459. log.Error("ImagePush target %s,err (%+v)", imageTagName, err)
  460. }
  461. err = s.dao.UpdateHubImageLogStatus(hubImageLogID, status)
  462. log.Info("end PullAndPushWithMachine2Image source %s, target %s", imageSrcName, imageTagName)
  463. return
  464. }
  465. // Machine2ImageForceFailed Machine to Image Force Failed.
  466. func (s *Service) Machine2ImageForceFailed(c context.Context, machineID int64) (status int, err error) {
  467. if err = s.dao.UpdateHubImageLogStatusInDoingStatus(machineID, model.ImagePullErr); err != nil {
  468. status = -1
  469. }
  470. return
  471. }
  472. // UpdateImageConf Update Image Conf.
  473. func (s *Service) UpdateImageConf(c context.Context, username string, ic *model.ImageConfiguration) (status int, err error) {
  474. var (
  475. hubImageConf *model.HubImageConf
  476. hasRight bool
  477. envsJson []byte
  478. hostsJson []byte
  479. )
  480. status = -1
  481. // 超级用户才能改MerlinPub 配置模板
  482. ret := strings.Split(ic.ImageFullName, "/")
  483. if len(ret) > 1 && ret[1] == s.c.BiliHub.MerlinPub {
  484. for _, super := range s.c.BiliHub.SuperOwner {
  485. if username == super {
  486. hasRight = true
  487. continue
  488. }
  489. }
  490. if !hasRight {
  491. err = ecode.MerlinHubNoRight
  492. return
  493. }
  494. }
  495. if envsJson, err = json.Marshal(ic.Envs); err != nil {
  496. return
  497. }
  498. if hostsJson, err = json.Marshal(ic.HostAlias); err != nil {
  499. return
  500. }
  501. if hubImageConf, err = s.dao.FindHubImageConfByImageName(ic.ImageFullName); err != nil {
  502. return
  503. }
  504. newHubImageConf := &model.HubImageConf{
  505. ImageName: ic.ImageFullName,
  506. UpdateBy: username,
  507. Command: strings.TrimSpace(ic.Command),
  508. Envs: string(envsJson),
  509. Hosts: string(hostsJson),
  510. }
  511. if hubImageConf.ID == 0 {
  512. if err = s.dao.InsertHubImageConf(newHubImageConf); err != nil {
  513. return
  514. }
  515. } else {
  516. if err = s.dao.UpdateHubImageConf(newHubImageConf); err != nil {
  517. return
  518. }
  519. }
  520. status = 0
  521. return
  522. }
  523. // QueryImageConf Query Image Conf.
  524. func (s *Service) QueryImageConf(c context.Context, imageName string) (ic *model.ImageConfiguration, err error) {
  525. var (
  526. hubImageConf *model.HubImageConf
  527. envs []*model.EnvVariable
  528. hostAlias []*model.Host
  529. )
  530. if hubImageConf, err = s.dao.FindHubImageConfByImageName(imageName); err != nil || hubImageConf.ID == 0 {
  531. return
  532. }
  533. if err = json.Unmarshal([]byte(hubImageConf.Envs), &envs); err != nil {
  534. return
  535. }
  536. if err = json.Unmarshal([]byte(hubImageConf.Hosts), &hostAlias); err != nil {
  537. return
  538. }
  539. ic = &model.ImageConfiguration{
  540. ImageFullName: imageName,
  541. PaasMachineSystem: model.PaasMachineSystem{
  542. Command: hubImageConf.Command,
  543. Envs: envs,
  544. HostAlias: hostAlias,
  545. },
  546. }
  547. if len(ic.Envs) == 0 && len(ic.HostAlias) == 0 && strings.TrimSpace(ic.Command) == "" {
  548. ic = nil
  549. }
  550. return
  551. }