Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

migrate_storage.go 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package cmd
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/models/db"
  9. git_model "code.gitea.io/gitea/models/git"
  10. "code.gitea.io/gitea/models/migrations"
  11. packages_model "code.gitea.io/gitea/models/packages"
  12. repo_model "code.gitea.io/gitea/models/repo"
  13. user_model "code.gitea.io/gitea/models/user"
  14. "code.gitea.io/gitea/modules/log"
  15. packages_module "code.gitea.io/gitea/modules/packages"
  16. "code.gitea.io/gitea/modules/setting"
  17. "code.gitea.io/gitea/modules/storage"
  18. "github.com/urfave/cli"
  19. )
  20. // CmdMigrateStorage represents the available migrate storage sub-command.
  21. var CmdMigrateStorage = cli.Command{
  22. Name: "migrate-storage",
  23. Usage: "Migrate the storage",
  24. Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
  25. Action: runMigrateStorage,
  26. Flags: []cli.Flag{
  27. cli.StringFlag{
  28. Name: "type, t",
  29. Value: "",
  30. Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages'",
  31. },
  32. cli.StringFlag{
  33. Name: "storage, s",
  34. Value: "",
  35. Usage: "New storage type: local (default) or minio",
  36. },
  37. cli.StringFlag{
  38. Name: "path, p",
  39. Value: "",
  40. Usage: "New storage placement if store is local (leave blank for default)",
  41. },
  42. cli.StringFlag{
  43. Name: "minio-endpoint",
  44. Value: "",
  45. Usage: "Minio storage endpoint",
  46. },
  47. cli.StringFlag{
  48. Name: "minio-access-key-id",
  49. Value: "",
  50. Usage: "Minio storage accessKeyID",
  51. },
  52. cli.StringFlag{
  53. Name: "minio-secret-access-key",
  54. Value: "",
  55. Usage: "Minio storage secretAccessKey",
  56. },
  57. cli.StringFlag{
  58. Name: "minio-bucket",
  59. Value: "",
  60. Usage: "Minio storage bucket",
  61. },
  62. cli.StringFlag{
  63. Name: "minio-location",
  64. Value: "",
  65. Usage: "Minio storage location to create bucket",
  66. },
  67. cli.StringFlag{
  68. Name: "minio-base-path",
  69. Value: "",
  70. Usage: "Minio storage base path on the bucket",
  71. },
  72. cli.BoolFlag{
  73. Name: "minio-use-ssl",
  74. Usage: "Enable SSL for minio",
  75. },
  76. cli.BoolFlag{
  77. Name: "minio-insecure-skip-verify",
  78. Usage: "Skip SSL verification",
  79. },
  80. cli.StringFlag{
  81. Name: "minio-checksum-algorithm",
  82. Value: "",
  83. Usage: "Minio checksum algorithm (default/md5)",
  84. },
  85. },
  86. }
  87. func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
  88. return db.Iterate(ctx, nil, func(ctx context.Context, attach *repo_model.Attachment) error {
  89. _, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath())
  90. return err
  91. })
  92. }
  93. func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error {
  94. return db.Iterate(ctx, nil, func(ctx context.Context, mo *git_model.LFSMetaObject) error {
  95. _, err := storage.Copy(dstStorage, mo.RelativePath(), storage.LFS, mo.RelativePath())
  96. return err
  97. })
  98. }
  99. func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
  100. return db.Iterate(ctx, nil, func(ctx context.Context, user *user_model.User) error {
  101. _, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
  102. return err
  103. })
  104. }
  105. func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
  106. return db.Iterate(ctx, nil, func(ctx context.Context, repo *repo_model.Repository) error {
  107. _, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
  108. return err
  109. })
  110. }
  111. func migrateRepoArchivers(ctx context.Context, dstStorage storage.ObjectStorage) error {
  112. return db.Iterate(ctx, nil, func(ctx context.Context, archiver *repo_model.RepoArchiver) error {
  113. p := archiver.RelativePath()
  114. _, err := storage.Copy(dstStorage, p, storage.RepoArchives, p)
  115. return err
  116. })
  117. }
  118. func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) error {
  119. return db.Iterate(ctx, nil, func(ctx context.Context, pb *packages_model.PackageBlob) error {
  120. p := packages_module.KeyToRelativePath(packages_module.BlobHash256Key(pb.HashSHA256))
  121. _, err := storage.Copy(dstStorage, p, storage.Packages, p)
  122. return err
  123. })
  124. }
  125. func runMigrateStorage(ctx *cli.Context) error {
  126. stdCtx, cancel := installSignals()
  127. defer cancel()
  128. if err := initDB(stdCtx); err != nil {
  129. return err
  130. }
  131. log.Info("AppPath: %s", setting.AppPath)
  132. log.Info("AppWorkPath: %s", setting.AppWorkPath)
  133. log.Info("Custom path: %s", setting.CustomPath)
  134. log.Info("Log path: %s", setting.Log.RootPath)
  135. log.Info("Configuration file: %s", setting.CustomConf)
  136. if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
  137. log.Fatal("Failed to initialize ORM engine: %v", err)
  138. return err
  139. }
  140. if err := storage.Init(); err != nil {
  141. return err
  142. }
  143. var dstStorage storage.ObjectStorage
  144. var err error
  145. switch strings.ToLower(ctx.String("storage")) {
  146. case "":
  147. fallthrough
  148. case string(storage.LocalStorageType):
  149. p := ctx.String("path")
  150. if p == "" {
  151. log.Fatal("Path must be given when storage is loal")
  152. return nil
  153. }
  154. dstStorage, err = storage.NewLocalStorage(
  155. stdCtx,
  156. storage.LocalStorageConfig{
  157. Path: p,
  158. })
  159. case string(storage.MinioStorageType):
  160. dstStorage, err = storage.NewMinioStorage(
  161. stdCtx,
  162. storage.MinioStorageConfig{
  163. Endpoint: ctx.String("minio-endpoint"),
  164. AccessKeyID: ctx.String("minio-access-key-id"),
  165. SecretAccessKey: ctx.String("minio-secret-access-key"),
  166. Bucket: ctx.String("minio-bucket"),
  167. Location: ctx.String("minio-location"),
  168. BasePath: ctx.String("minio-base-path"),
  169. UseSSL: ctx.Bool("minio-use-ssl"),
  170. InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
  171. ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
  172. })
  173. default:
  174. return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
  175. }
  176. if err != nil {
  177. return err
  178. }
  179. migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{
  180. "attachments": migrateAttachments,
  181. "lfs": migrateLFS,
  182. "avatars": migrateAvatars,
  183. "repo-avatars": migrateRepoAvatars,
  184. "repo-archivers": migrateRepoArchivers,
  185. "packages": migratePackages,
  186. }
  187. tp := strings.ToLower(ctx.String("type"))
  188. if m, ok := migratedMethods[tp]; ok {
  189. if err := m(stdCtx, dstStorage); err != nil {
  190. return err
  191. }
  192. log.Info("%s files have successfully been copied to the new storage.", tp)
  193. return nil
  194. }
  195. return fmt.Errorf("unsupported storage: %s", ctx.String("type"))
  196. }