migrate_schema.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package migrate
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/gravitl/netmaker/database"
  7. "github.com/gravitl/netmaker/db"
  8. "github.com/gravitl/netmaker/schema"
  9. "github.com/gravitl/netmaker/servercfg"
  10. "gorm.io/gorm"
  11. "os"
  12. "path/filepath"
  13. )
  14. // ToSQLSchema migrates the data from key-value
  15. // db to sql db.
  16. //
  17. // This function archives the old data and does not
  18. // delete it.
  19. //
  20. // Based on the db server, the archival is done in the
  21. // following way:
  22. //
  23. // 1. Sqlite: Moves the old data to a
  24. // netmaker_archive.db file.
  25. //
  26. // 2. Postgres: Moves the data to a netmaker_archive
  27. // schema within the same database.
  28. func ToSQLSchema() error {
  29. // initialize sql schema db.
  30. err := db.InitializeDB(schema.ListModels()...)
  31. if err != nil {
  32. return err
  33. }
  34. // migrate, if not done already.
  35. err = migrate()
  36. if err != nil {
  37. return err
  38. }
  39. // archive key-value schema db, if not done already.
  40. // ignore errors.
  41. _ = archive()
  42. return nil
  43. }
  44. func migrate() error {
  45. // begin a new transaction.
  46. dbctx := db.BeginTx(context.TODO())
  47. commit := false
  48. defer func() {
  49. if commit {
  50. db.FromContext(dbctx).Commit()
  51. } else {
  52. db.FromContext(dbctx).Rollback()
  53. }
  54. }()
  55. // check if migrated already.
  56. migrationJob := &schema.Job{
  57. ID: "migration-v1.0.0",
  58. }
  59. err := migrationJob.Get(dbctx)
  60. if err != nil {
  61. if !errors.Is(err, gorm.ErrRecordNotFound) {
  62. return err
  63. }
  64. // initialize key-value schema db.
  65. err := database.InitializeDatabase()
  66. if err != nil {
  67. return err
  68. }
  69. defer database.CloseDB()
  70. // migrate.
  71. // TODO: add migration code.
  72. // mark migration job completed.
  73. err = migrationJob.Create(dbctx)
  74. if err != nil {
  75. return err
  76. }
  77. commit = true
  78. }
  79. return nil
  80. }
  81. func archive() error {
  82. dbServer := servercfg.GetDB()
  83. if dbServer != "sqlite" && dbServer != "postgres" {
  84. return nil
  85. }
  86. // begin a new transaction.
  87. dbctx := db.BeginTx(context.TODO())
  88. commit := false
  89. defer func() {
  90. if commit {
  91. db.FromContext(dbctx).Commit()
  92. } else {
  93. db.FromContext(dbctx).Rollback()
  94. }
  95. }()
  96. // check if key-value schema db archived already.
  97. archivalJob := &schema.Job{
  98. ID: "archival-v1.0.0",
  99. }
  100. err := archivalJob.Get(dbctx)
  101. if err != nil {
  102. if !errors.Is(err, gorm.ErrRecordNotFound) {
  103. return err
  104. }
  105. // archive.
  106. switch dbServer {
  107. case "sqlite":
  108. err = sqliteArchiveOldData()
  109. default:
  110. err = pgArchiveOldData()
  111. }
  112. if err != nil {
  113. return err
  114. }
  115. // mark archival job completed.
  116. err = archivalJob.Create(dbctx)
  117. if err != nil {
  118. return err
  119. }
  120. commit = true
  121. } else {
  122. // remove the residual
  123. if dbServer == "sqlite" {
  124. _ = os.Remove(filepath.Join("data", "netmaker.db"))
  125. }
  126. }
  127. return nil
  128. }
  129. func sqliteArchiveOldData() error {
  130. oldDBFilePath := filepath.Join("data", "netmaker.db")
  131. archiveDBFilePath := filepath.Join("data", "netmaker_archive.db")
  132. // check if netmaker_archive.db exist.
  133. _, err := os.Stat(archiveDBFilePath)
  134. if err == nil {
  135. return nil
  136. } else if !os.IsNotExist(err) {
  137. return err
  138. }
  139. // rename old db file to netmaker_archive.db.
  140. return os.Rename(oldDBFilePath, archiveDBFilePath)
  141. }
  142. func pgArchiveOldData() error {
  143. _, err := database.PGDB.Exec("CREATE SCHEMA IF NOT EXISTS netmaker_archive")
  144. if err != nil {
  145. return err
  146. }
  147. for _, table := range database.Tables {
  148. _, err := database.PGDB.Exec(
  149. fmt.Sprintf(
  150. "ALTER TABLE public.%s SET SCHEMA netmaker_archive",
  151. table,
  152. ),
  153. )
  154. if err != nil {
  155. return err
  156. }
  157. }
  158. return nil
  159. }