44import re
55import sys
66import time
7+ import json
78import utils
89import yaml
910import argparse
1011import textwrap
1112import random
12-
13+ from mysql import connector
1314cwd = os .path .dirname (__file__ )
1415os .chdir (cwd )
1516
2930
3031def load_config_4_ctl (args , command ):
3132 # if we need to load all config
32- if command in ["svc" , "render_template" , "download" , "docker" ]:
33+ if command in ["svc" , "render_template" , "download" , "docker" , "db" ]:
3334 args .config = [ENV_CNF_YAML , STATUS_YAML ] if not args .config else args .config
3435 config = load_deploy_config (args )
3536 else :
@@ -253,6 +254,68 @@ def render_template_or_dir(config, args):
253254 utils .render_template (src , dst , config )
254255
255256
257+ def maintain_db (config , args ):
258+ """
259+ push/pull a table to/from DB
260+ """
261+ subcommand = args .nargs [0 ]
262+ assert subcommand in ["pull" , "push" , "connect" ], "invalid action."
263+ host = config ["mysql_node" ]
264+ user = config ["mysql_username" ]
265+ password = config ["mysql_password" ]
266+ if subcommand == "connect" :
267+ os .system ("mysql -h {} -u {} -p{}" .format (host , user , password ))
268+ else :
269+ database = "DLWSCluster-{}" .format (config ["clusterId" ])
270+ table_name = args .nargs [1 ]
271+ assert table_name in ["vc" , "acl" ], "invalid table."
272+
273+ if args .verbose :
274+ print ("connecting to {}@{}, DB {}" .format (user , host , database ))
275+ conn = connector .connect (user = user , password = password ,
276+ host = host , database = database )
277+ if subcommand == "pull" :
278+ sql = "SELECT * from {}" .format (table_name )
279+ cursor = conn .cursor ()
280+ cursor .execute (sql )
281+ col_names = [col [0 ] for col in cursor .description ]
282+ serialized_rows = []
283+ rows = cursor .fetchall ()
284+ for row in rows :
285+ serialized_row = {}
286+ for i , v in enumerate (row ):
287+ try :
288+ serialized_row [col_names [i ]] = json .loads (v )
289+ # JSONDecodeError
290+ except :
291+ serialized_row [col_names [i ]] = v
292+ serialized_rows .append (serialized_row )
293+ table_config = {"col_names" : col_names , "rows" : serialized_rows }
294+ output_file = args .output if args .output else "{}.yaml" .format (table_name )
295+ with open (output_file , "w" ) as wf :
296+ yaml .safe_dump (table_config , wf )
297+ elif subcommand == "push" :
298+ sql = "DELETE from {}" .format (table_name )
299+ cursor = conn .cursor ()
300+ cursor .execute (sql )
301+ input_file_list = args .input if args .input else ["{}.yaml" .format (table_name )]
302+ table_config = add_configs_in_order (input_file_list , {})
303+ col_names = table_config ["col_names" ]
304+ cols_2_ignore = table_config .get ("columns_to_ignore" , ["time" ])
305+ cols_filtered = [col for col in col_names if col not in cols_2_ignore ]
306+ cols_str = ", " .join (cols_filtered )
307+ for row in table_config ["rows" ]:
308+ vals = ", " .join (["'{}'" .format (json .dumps (row [col ])) for col in cols_filtered ])
309+ vals = vals .replace ("'null'" , "NULL" )
310+ sql = "INSERT INTO `{}` ({}) VALUES ({})" .format (table_name , cols_str , vals )
311+ if args .verbose :
312+ print (sql )
313+ cursor .execute (sql )
314+ conn .commit ()
315+
316+ cursor .close ()
317+
318+
256319def run_command (args , command ):
257320 config = load_config_4_ctl (args , command )
258321 if command == "restorefromdir" :
@@ -294,6 +357,8 @@ def run_command(args, command):
294357 if nargs [0 ] == "push" :
295358 check_buildable_images (args .nargs [1 ], config )
296359 push_docker_images (args , config )
360+ elif command == "db" :
361+ maintain_db (config , args )
297362 else :
298363 print ("invalid command, please read the doc" )
299364
@@ -316,9 +381,9 @@ def run_command(args, command):
316381 ''' ))
317382 parser .add_argument ('-cnf' , '--config' , action = 'append' , default = [], help = 'Specify the config files you want to load, later ones \
318383 would overwrite former ones, e.g., -cnf config.yaml -cnf status.yaml' )
319- parser .add_argument ('-i' , '--in ' , action = 'append' ,
384+ parser .add_argument ('-i' , '--input ' , action = 'append' ,
320385 default = [], help = 'Files to take as input' )
321- parser .add_argument ('-o' , '--out ' , help = 'File to dump to as output' )
386+ parser .add_argument ('-o' , '--output' , default = ' ' , help = 'File to dump to as output' )
322387 parser .add_argument ("-v" , "--verbose" ,
323388 help = "verbose print" , action = "store_true" )
324389 parser .add_argument ('-r' , '--roles_or_machine' , action = 'append' , default = [], help = 'Specify the roles of machines that you want to copy file \
0 commit comments