Skip to content

Commit b531934

Browse files
authored
[db migrator] Introduce the DB migration infrastructure (sonic-net#519)
* [db migrator] Introduce the DB migration infrastructure - Add infrastructure to migrate DB contents from a lower version schema to a higher version schema, eventually reach latest version. - if config load_minigraph is executed, the db schema version is always the latest. Signed-off-by: Ying Xie <[email protected]> * [db migrator] address issues found in test
1 parent 4303b19 commit b531934

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

config/main.py

+12
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,12 @@ def reload(filename, yes, load_sysinfo):
387387
command = "{} -j {} --write-to-db".format(SONIC_CFGGEN_PATH, filename)
388388
run_command(command, display_cmd=True)
389389
client.set(config_db.INIT_INDICATOR, 1)
390+
391+
# Migrate DB contents to latest version
392+
db_migrator='/usr/bin/db_migrator.py'
393+
if os.path.isfile(db_migrator) and os.access(db_migrator, os.X_OK):
394+
run_command(db_migrator + ' -o migrate')
395+
390396
_restart_services()
391397

392398
@config.command()
@@ -437,6 +443,12 @@ def load_minigraph():
437443
if os.path.isfile('/etc/sonic/acl.json'):
438444
run_command("acl-loader update full /etc/sonic/acl.json", display_cmd=True)
439445
run_command("config qos reload", display_cmd=True)
446+
447+
# Write latest db version string into db
448+
db_migrator='/usr/bin/db_migrator.py'
449+
if os.path.isfile(db_migrator) and os.access(db_migrator, os.X_OK):
450+
run_command(db_migrator + ' -o set_version')
451+
440452
#FIXME: After config DB daemon is implemented, we'll no longer need to restart every service.
441453
_restart_services()
442454
click.echo("Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.")

scripts/db_migrator.py

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python
2+
3+
import sys
4+
import argparse
5+
import syslog
6+
from swsssdk import ConfigDBConnector
7+
8+
9+
SYSLOG_IDENTIFIER = 'db_migrator'
10+
11+
12+
def log_info(msg):
13+
syslog.openlog(SYSLOG_IDENTIFIER)
14+
syslog.syslog(syslog.LOG_INFO, msg)
15+
syslog.closelog()
16+
17+
18+
def log_error(msg):
19+
syslog.openlog(SYSLOG_IDENTIFIER)
20+
syslog.syslog(syslog.LOG_ERR, msg)
21+
syslog.closelog()
22+
23+
24+
class DBMigrator():
25+
def __init__(self):
26+
"""
27+
Version string format:
28+
version_<major>_<minor>_<build>
29+
major: starting from 1, sequentially incrementing in master
30+
branch.
31+
minor: in github branches, minor version stays in 0. This minor
32+
version creates space for private branches derived from
33+
github public branches. These private branches shall use
34+
none-zero values.
35+
build: sequentially increase within a minor version domain.
36+
"""
37+
self.CURRENT_VERSION = 'version_1_0_1'
38+
39+
self.TABLE_NAME = 'VERSIONS'
40+
self.TABLE_KEY = 'DATABASE'
41+
self.TABLE_FIELD = 'VERSION'
42+
self.configDB = ConfigDBConnector()
43+
self.configDB.db_connect('CONFIG_DB')
44+
45+
46+
def migrate_pfc_wd_table(self):
47+
# Migrate all data entries from table PFC_WD_TABLE to PFC_WD
48+
data = self.configDB.get_table('PFC_WD_TABLE')
49+
for key in data.keys():
50+
self.configDB.set_entry('PFC_WD', key, data[key])
51+
self.configDB.delete_table('PFC_WD_TABLE')
52+
53+
54+
def version_unknown(self):
55+
"""
56+
version_unknown tracks all SONiC versions that doesn't have a version
57+
string defined in config_DB.
58+
Nothing can be assumped when migrating from this version to the next
59+
version.
60+
Any migration operation needs to test if the DB is in expected format
61+
before migrating date to the next version.
62+
"""
63+
64+
log_info('Handling version_unknown')
65+
66+
# NOTE: Uncomment next 3 lines of code when the migration code is in
67+
# place. Note that returning specific string is intentional,
68+
# here we only intended to migrade to DB version 1.0.1.
69+
# If new DB version is added in the future, the incremental
70+
# upgrade will take care of the subsequent migrations.
71+
# self.migrate_pfc_wd_table()
72+
# self.set_version('version_1_0_1')
73+
# return 'version_1_0_1'
74+
75+
76+
def version_1_0_1(self):
77+
"""
78+
Current latest version. Nothing to do here.
79+
"""
80+
log_info('Handling version_1_0_1')
81+
82+
return None
83+
84+
85+
def get_version(self):
86+
version = self.configDB.get_entry(self.TABLE_NAME, self.TABLE_KEY)
87+
if version and version[self.TABLE_FIELD]:
88+
return version[self.TABLE_FIELD]
89+
90+
return 'version_unknown'
91+
92+
93+
def set_version(self, version=None):
94+
if not version:
95+
version = self.CURRENT_VERSION
96+
log_info('Setting version to ' + version)
97+
entry = { self.TABLE_FIELD : version }
98+
self.configDB.set_entry(self.TABLE_NAME, self.TABLE_KEY, entry)
99+
100+
101+
def migrate(self):
102+
version = self.get_version()
103+
log_info('Upgrading from version ' + version)
104+
while version:
105+
next_version = getattr(self, version)()
106+
if next_version == version:
107+
raise Exception('Version migrate from %s stuck in same version' % version)
108+
version = next_version
109+
110+
111+
def main():
112+
try:
113+
parser = argparse.ArgumentParser()
114+
115+
parser.add_argument('-o',
116+
dest='operation',
117+
metavar='operation (migrate, set_version, get_version)',
118+
type = str,
119+
required = False,
120+
choices=['migrate', 'set_version', 'get_version'],
121+
help = 'operation to perform [default: get_version]',
122+
default='get_version')
123+
args = parser.parse_args()
124+
operation = args.operation
125+
126+
dbmgtr = DBMigrator()
127+
result = getattr(dbmgtr, operation)()
128+
if result:
129+
print(str(result))
130+
131+
except Exception as e:
132+
log_error('Caught excetion: ' + str(e))
133+
parser.print_help()
134+
sys.exit(1)
135+
136+
137+
if __name__ == "__main__":
138+
main()

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
'scripts/aclshow',
5555
'scripts/boot_part',
5656
'scripts/coredump-compress',
57+
'scripts/db_migrator.py',
5758
'scripts/decode-syseeprom',
5859
'scripts/dropcheck',
5960
'scripts/ecnconfig',

0 commit comments

Comments
 (0)