github.com/demisto/mattermost-server@v4.9.0-rc3+incompatible/store/sqlstore/upgrade.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"encoding/json"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	l4g "github.com/alecthomas/log4go"
    13  
    14  	"github.com/mattermost/mattermost-server/model"
    15  	"github.com/mattermost/mattermost-server/utils"
    16  )
    17  
    18  const (
    19  	VERSION_4_9_0            = "4.9.0"
    20  	VERSION_4_8_1            = "4.8.1"
    21  	VERSION_4_8_0            = "4.8.0"
    22  	VERSION_4_7_2            = "4.7.2"
    23  	VERSION_4_7_1            = "4.7.1"
    24  	VERSION_4_7_0            = "4.7.0"
    25  	VERSION_4_6_0            = "4.6.0"
    26  	VERSION_4_5_0            = "4.5.0"
    27  	VERSION_4_4_0            = "4.4.0"
    28  	VERSION_4_3_0            = "4.3.0"
    29  	VERSION_4_2_0            = "4.2.0"
    30  	VERSION_4_1_0            = "4.1.0"
    31  	VERSION_4_0_0            = "4.0.0"
    32  	VERSION_3_10_0           = "3.10.0"
    33  	VERSION_3_9_0            = "3.9.0"
    34  	VERSION_3_8_0            = "3.8.0"
    35  	VERSION_3_7_0            = "3.7.0"
    36  	VERSION_3_6_0            = "3.6.0"
    37  	VERSION_3_5_0            = "3.5.0"
    38  	VERSION_3_4_0            = "3.4.0"
    39  	VERSION_3_3_0            = "3.3.0"
    40  	VERSION_3_2_0            = "3.2.0"
    41  	VERSION_3_1_0            = "3.1.0"
    42  	VERSION_3_0_0            = "3.0.0"
    43  	OLDEST_SUPPORTED_VERSION = VERSION_3_0_0
    44  )
    45  
    46  const (
    47  	EXIT_VERSION_SAVE_MISSING = 1001
    48  	EXIT_TOO_OLD              = 1002
    49  	EXIT_VERSION_SAVE         = 1003
    50  	EXIT_THEME_MIGRATION      = 1004
    51  )
    52  
    53  func UpgradeDatabase(sqlStore SqlStore) {
    54  
    55  	UpgradeDatabaseToVersion31(sqlStore)
    56  	UpgradeDatabaseToVersion32(sqlStore)
    57  	UpgradeDatabaseToVersion33(sqlStore)
    58  	UpgradeDatabaseToVersion34(sqlStore)
    59  	UpgradeDatabaseToVersion35(sqlStore)
    60  	UpgradeDatabaseToVersion36(sqlStore)
    61  	UpgradeDatabaseToVersion37(sqlStore)
    62  	UpgradeDatabaseToVersion38(sqlStore)
    63  	UpgradeDatabaseToVersion39(sqlStore)
    64  	UpgradeDatabaseToVersion310(sqlStore)
    65  	UpgradeDatabaseToVersion40(sqlStore)
    66  	UpgradeDatabaseToVersion41(sqlStore)
    67  	UpgradeDatabaseToVersion42(sqlStore)
    68  	UpgradeDatabaseToVersion43(sqlStore)
    69  	UpgradeDatabaseToVersion44(sqlStore)
    70  	UpgradeDatabaseToVersion45(sqlStore)
    71  	UpgradeDatabaseToVersion46(sqlStore)
    72  	UpgradeDatabaseToVersion47(sqlStore)
    73  	UpgradeDatabaseToVersion471(sqlStore)
    74  	UpgradeDatabaseToVersion472(sqlStore)
    75  	UpgradeDatabaseToVersion48(sqlStore)
    76  	UpgradeDatabaseToVersion481(sqlStore)
    77  	UpgradeDatabaseToVersion49(sqlStore)
    78  
    79  	// If the SchemaVersion is empty this this is the first time it has ran
    80  	// so lets set it to the current version.
    81  	if sqlStore.GetCurrentSchemaVersion() == "" {
    82  		if result := <-sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil {
    83  			l4g.Critical(result.Err.Error())
    84  			time.Sleep(time.Second)
    85  			os.Exit(EXIT_VERSION_SAVE_MISSING)
    86  		}
    87  
    88  		l4g.Info(utils.T("store.sql.schema_set.info"), model.CurrentVersion)
    89  	}
    90  
    91  	// If we're not on the current version then it's too old to be upgraded
    92  	if sqlStore.GetCurrentSchemaVersion() != model.CurrentVersion {
    93  		l4g.Critical(utils.T("store.sql.schema_version.critical"), sqlStore.GetCurrentSchemaVersion(), OLDEST_SUPPORTED_VERSION, model.CurrentVersion, OLDEST_SUPPORTED_VERSION)
    94  		time.Sleep(time.Second)
    95  		os.Exit(EXIT_TOO_OLD)
    96  	}
    97  }
    98  
    99  func saveSchemaVersion(sqlStore SqlStore, version string) {
   100  	if result := <-sqlStore.System().Update(&model.System{Name: "Version", Value: version}); result.Err != nil {
   101  		l4g.Critical(result.Err.Error())
   102  		time.Sleep(time.Second)
   103  		os.Exit(EXIT_VERSION_SAVE)
   104  	}
   105  
   106  	l4g.Warn(utils.T("store.sql.upgraded.warn"), version)
   107  }
   108  
   109  func shouldPerformUpgrade(sqlStore SqlStore, currentSchemaVersion string, expectedSchemaVersion string) bool {
   110  	if sqlStore.GetCurrentSchemaVersion() == currentSchemaVersion {
   111  		l4g.Warn(utils.T("store.sql.schema_out_of_date.warn"), currentSchemaVersion)
   112  		l4g.Warn(utils.T("store.sql.schema_upgrade_attempt.warn"), expectedSchemaVersion)
   113  
   114  		return true
   115  	}
   116  
   117  	return false
   118  }
   119  
   120  func UpgradeDatabaseToVersion31(sqlStore SqlStore) {
   121  	if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) {
   122  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
   123  		saveSchemaVersion(sqlStore, VERSION_3_1_0)
   124  	}
   125  }
   126  
   127  func UpgradeDatabaseToVersion32(sqlStore SqlStore) {
   128  	if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) {
   129  		sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0")
   130  
   131  		saveSchemaVersion(sqlStore, VERSION_3_2_0)
   132  	}
   133  }
   134  
   135  func themeMigrationFailed(err error) {
   136  	l4g.Critical(utils.T("store.sql_user.migrate_theme.critical"), err)
   137  	time.Sleep(time.Second)
   138  	os.Exit(EXIT_THEME_MIGRATION)
   139  }
   140  
   141  func UpgradeDatabaseToVersion33(sqlStore SqlStore) {
   142  	if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) {
   143  		if sqlStore.DoesColumnExist("Users", "ThemeProps") {
   144  			params := map[string]interface{}{
   145  				"Category": model.PREFERENCE_CATEGORY_THEME,
   146  				"Name":     "",
   147  			}
   148  
   149  			transaction, err := sqlStore.GetMaster().Begin()
   150  			if err != nil {
   151  				themeMigrationFailed(err)
   152  			}
   153  
   154  			// increase size of Value column of Preferences table to match the size of the ThemeProps column
   155  			if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   156  				if _, err := transaction.Exec("ALTER TABLE Preferences ALTER COLUMN Value TYPE varchar(2000)"); err != nil {
   157  					themeMigrationFailed(err)
   158  				}
   159  			} else if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
   160  				if _, err := transaction.Exec("ALTER TABLE Preferences MODIFY Value text"); err != nil {
   161  					themeMigrationFailed(err)
   162  				}
   163  			}
   164  
   165  			// copy data across
   166  			if _, err := transaction.Exec(
   167  				`INSERT INTO
   168  					Preferences(UserId, Category, Name, Value)
   169  				SELECT
   170  					Id, '`+model.PREFERENCE_CATEGORY_THEME+`', '', ThemeProps
   171  				FROM
   172  					Users
   173  				WHERE
   174  					Users.ThemeProps != 'null'`, params); err != nil {
   175  				themeMigrationFailed(err)
   176  			}
   177  
   178  			// delete old data
   179  			if _, err := transaction.Exec("ALTER TABLE Users DROP COLUMN ThemeProps"); err != nil {
   180  				themeMigrationFailed(err)
   181  			}
   182  
   183  			if err := transaction.Commit(); err != nil {
   184  				themeMigrationFailed(err)
   185  			}
   186  
   187  			// rename solarized_* code themes to solarized-* to match client changes in 3.0
   188  			var data model.Preferences
   189  			if _, err := sqlStore.GetMaster().Select(&data, "SELECT * FROM Preferences WHERE Category = '"+model.PREFERENCE_CATEGORY_THEME+"' AND Value LIKE '%solarized_%'"); err == nil {
   190  				for i := range data {
   191  					data[i].Value = strings.Replace(data[i].Value, "solarized_", "solarized-", -1)
   192  				}
   193  
   194  				sqlStore.Preference().Save(&data)
   195  			}
   196  		}
   197  
   198  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IsTrusted", "tinyint(1)", "boolean", "0")
   199  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IconURL", "varchar(512)", "varchar(512)", "")
   200  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ClientId", "varchar(26)", "varchar(26)", "")
   201  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "UserId", "varchar(26)", "varchar(26)", "")
   202  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ExpiresAt", "bigint", "bigint", "0")
   203  
   204  		if sqlStore.DoesColumnExist("OAuthAccessData", "AuthCode") {
   205  			sqlStore.RemoveIndexIfExists("idx_oauthaccessdata_auth_code", "OAuthAccessData")
   206  			sqlStore.RemoveColumnIfExists("OAuthAccessData", "AuthCode")
   207  		}
   208  
   209  		sqlStore.RemoveColumnIfExists("Users", "LastActivityAt")
   210  		sqlStore.RemoveColumnIfExists("Users", "LastPingAt")
   211  
   212  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "integer", "0")
   213  
   214  		saveSchemaVersion(sqlStore, VERSION_3_3_0)
   215  	}
   216  }
   217  
   218  func UpgradeDatabaseToVersion34(sqlStore SqlStore) {
   219  	if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) {
   220  		sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0")
   221  		sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "")
   222  
   223  		saveSchemaVersion(sqlStore, VERSION_3_4_0)
   224  	}
   225  }
   226  
   227  func UpgradeDatabaseToVersion35(sqlStore SqlStore) {
   228  	if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) {
   229  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''")
   230  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'")
   231  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user' WHERE Roles = ''")
   232  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user team_admin' WHERE Roles = 'admin'")
   233  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user' WHERE Roles = ''")
   234  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user channel_admin' WHERE Roles = 'admin'")
   235  
   236  		// The rest of the migration from Filenames -> FileIds is done lazily in api.GetFileInfosForPost
   237  		sqlStore.CreateColumnIfNotExists("Posts", "FileIds", "varchar(150)", "varchar(150)", "[]")
   238  
   239  		// Increase maximum length of the Channel table Purpose column.
   240  		if sqlStore.GetMaxLengthOfColumnIfExists("Channels", "Purpose") != "250" {
   241  			sqlStore.AlterColumnTypeIfExists("Channels", "Purpose", "varchar(250)", "varchar(250)")
   242  		}
   243  
   244  		sqlStore.Session().RemoveAllSessions()
   245  
   246  		saveSchemaVersion(sqlStore, VERSION_3_5_0)
   247  	}
   248  }
   249  
   250  func UpgradeDatabaseToVersion36(sqlStore SqlStore) {
   251  	if shouldPerformUpgrade(sqlStore, VERSION_3_5_0, VERSION_3_6_0) {
   252  		sqlStore.CreateColumnIfNotExists("Posts", "HasReactions", "tinyint", "boolean", "0")
   253  
   254  		// Create Team Description column
   255  		sqlStore.CreateColumnIfNotExists("Teams", "Description", "varchar(255)", "varchar(255)", "")
   256  
   257  		// Add a Position column to users.
   258  		sqlStore.CreateColumnIfNotExists("Users", "Position", "varchar(64)", "varchar(64)", "")
   259  
   260  		// Remove ActiveChannel column from Status
   261  		sqlStore.RemoveColumnIfExists("Status", "ActiveChannel")
   262  
   263  		saveSchemaVersion(sqlStore, VERSION_3_6_0)
   264  	}
   265  }
   266  
   267  func UpgradeDatabaseToVersion37(sqlStore SqlStore) {
   268  	if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) {
   269  		// Add EditAt column to Posts
   270  		sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0")
   271  
   272  		saveSchemaVersion(sqlStore, VERSION_3_7_0)
   273  	}
   274  }
   275  
   276  func UpgradeDatabaseToVersion38(sqlStore SqlStore) {
   277  	if shouldPerformUpgrade(sqlStore, VERSION_3_7_0, VERSION_3_8_0) {
   278  		// Add the IsPinned column to posts.
   279  		sqlStore.CreateColumnIfNotExists("Posts", "IsPinned", "boolean", "boolean", "0")
   280  
   281  		saveSchemaVersion(sqlStore, VERSION_3_8_0)
   282  	}
   283  }
   284  
   285  func UpgradeDatabaseToVersion39(sqlStore SqlStore) {
   286  	if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) {
   287  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE)
   288  		sqlStore.RemoveTableIfExists("PasswordRecovery")
   289  
   290  		saveSchemaVersion(sqlStore, VERSION_3_9_0)
   291  	}
   292  }
   293  
   294  func UpgradeDatabaseToVersion310(sqlStore SqlStore) {
   295  	if shouldPerformUpgrade(sqlStore, VERSION_3_9_0, VERSION_3_10_0) {
   296  		saveSchemaVersion(sqlStore, VERSION_3_10_0)
   297  	}
   298  }
   299  
   300  func UpgradeDatabaseToVersion40(sqlStore SqlStore) {
   301  	if shouldPerformUpgrade(sqlStore, VERSION_3_10_0, VERSION_4_0_0) {
   302  		saveSchemaVersion(sqlStore, VERSION_4_0_0)
   303  	}
   304  }
   305  
   306  func UpgradeDatabaseToVersion41(sqlStore SqlStore) {
   307  	if shouldPerformUpgrade(sqlStore, VERSION_4_0_0, VERSION_4_1_0) {
   308  		// Increase maximum length of the Users table Roles column.
   309  		if sqlStore.GetMaxLengthOfColumnIfExists("Users", "Roles") != "256" {
   310  			sqlStore.AlterColumnTypeIfExists("Users", "Roles", "varchar(256)", "varchar(256)")
   311  		}
   312  
   313  		sqlStore.RemoveTableIfExists("JobStatuses")
   314  
   315  		saveSchemaVersion(sqlStore, VERSION_4_1_0)
   316  	}
   317  }
   318  
   319  func UpgradeDatabaseToVersion42(sqlStore SqlStore) {
   320  	if shouldPerformUpgrade(sqlStore, VERSION_4_1_0, VERSION_4_2_0) {
   321  		saveSchemaVersion(sqlStore, VERSION_4_2_0)
   322  	}
   323  }
   324  
   325  func UpgradeDatabaseToVersion43(sqlStore SqlStore) {
   326  	if shouldPerformUpgrade(sqlStore, VERSION_4_2_0, VERSION_4_3_0) {
   327  		saveSchemaVersion(sqlStore, VERSION_4_3_0)
   328  	}
   329  }
   330  
   331  func UpgradeDatabaseToVersion44(sqlStore SqlStore) {
   332  	if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) {
   333  		// Add the IsActive column to UserAccessToken.
   334  		sqlStore.CreateColumnIfNotExists("UserAccessTokens", "IsActive", "boolean", "boolean", "1")
   335  
   336  		saveSchemaVersion(sqlStore, VERSION_4_4_0)
   337  	}
   338  }
   339  
   340  func UpgradeDatabaseToVersion45(sqlStore SqlStore) {
   341  	if shouldPerformUpgrade(sqlStore, VERSION_4_4_0, VERSION_4_5_0) {
   342  		saveSchemaVersion(sqlStore, VERSION_4_5_0)
   343  	}
   344  }
   345  
   346  func UpgradeDatabaseToVersion46(sqlStore SqlStore) {
   347  	if shouldPerformUpgrade(sqlStore, VERSION_4_5_0, VERSION_4_6_0) {
   348  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
   349  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
   350  		saveSchemaVersion(sqlStore, VERSION_4_6_0)
   351  	}
   352  }
   353  
   354  func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
   355  	if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) {
   356  		sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)")
   357  		sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)")
   358  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   359  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Username")
   360  		saveSchemaVersion(sqlStore, VERSION_4_7_0)
   361  	}
   362  }
   363  
   364  // If any new instances started with 4.7, they would have the bad Email column on the
   365  // ChannelMemberHistory table. So for those cases we need to do an upgrade between
   366  // 4.7.0 and 4.7.1
   367  func UpgradeDatabaseToVersion471(sqlStore SqlStore) {
   368  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) {
   369  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   370  		saveSchemaVersion(sqlStore, VERSION_4_7_1)
   371  	}
   372  }
   373  
   374  func UpgradeDatabaseToVersion472(sqlStore SqlStore) {
   375  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_1, VERSION_4_7_2) {
   376  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   377  		saveSchemaVersion(sqlStore, VERSION_4_7_2)
   378  	}
   379  }
   380  
   381  func UpgradeDatabaseToVersion48(sqlStore SqlStore) {
   382  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_2, VERSION_4_8_0) {
   383  		saveSchemaVersion(sqlStore, VERSION_4_8_0)
   384  	}
   385  }
   386  
   387  func UpgradeDatabaseToVersion481(sqlStore SqlStore) {
   388  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_8_1) {
   389  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   390  		saveSchemaVersion(sqlStore, VERSION_4_8_1)
   391  	}
   392  }
   393  
   394  func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
   395  	// This version of Mattermost includes an App-Layer migration which migrates from hard-coded roles configured by
   396  	// a number of parameters in `config.json` to a `Roles` table in the database. The migration code can be seen
   397  	// in the file `app/app.go` in the function `DoAdvancedPermissionsMigration()`.
   398  
   399  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_1, VERSION_4_9_0) {
   400  		sqlStore.CreateColumnIfNotExists("Teams", "LastTeamIconUpdate", "bigint", "bigint", "0")
   401  		defaultTimezone := model.DefaultUserTimezone()
   402  		defaultTimezoneValue, err := json.Marshal(defaultTimezone)
   403  		if err != nil {
   404  			l4g.Critical(err)
   405  		}
   406  		sqlStore.CreateColumnIfNotExists("Users", "Timezone", "varchar(256)", "varchar(256)", string(defaultTimezoneValue))
   407  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   408  		saveSchemaVersion(sqlStore, VERSION_4_9_0)
   409  	}
   410  }