import argparse import ast import json import os import re import subprocess import tempfile import time # Default flavor json directory FLAVOR_DIR = './flavor_dir' CLI_PATH = '../ormcli/orm' FID = None FILE_NAME = None FLAVOR_NAME = None REGION_NAME = None def get_flavor_type(path): # The last directory name is the flavor type (e.g., 'medium') return path.split('/')[-2] def get_region_list(regions): global REGION_NAME result = [] for region in regions: REGION_NAME = region res, output = sh('get_region') if not res: result_region = json.loads(output) result.append({'name': result_region['name'], 'designType': result_region['designType']}) else: print('Failed to get region %s, aborting...' % (region,)) exit(1) return result def create_command(cli_command): if cli_command == 'add_region': cmd = 'python %s fms add_region %s %s' % (CLI_PATH, FID, FILE_NAME,) elif cli_command == 'get_flavor': cmd = 'python %s fms get_flavor test %s' % (CLI_PATH, FLAVOR_NAME,) elif cli_command == 'get_region': cmd = 'python %s rms get_region %s' % (CLI_PATH, REGION_NAME,) else: raise ValueError('Received an unknown command: %s' % (cli_command,)) if ';' in cmd or '&&' in cmd: raise Exception("Violation of command injection, cmd is " + cmd) return cmd def read_jsonfile(file): return json.loads(open(file).read()) def calculate_name(flavor): flavor_name = "{0}.c{1}r{2}d{3}".format(flavor['series'], flavor['vcpus'], int(flavor['ram']) / 1024, flavor['disk']) if 'ephemeral' in flavor and int(flavor['ephemeral']) != 0: flavor_name += 'e{0}'.format(flavor['ephemeral']) return flavor_name def sh(cli_command): # run a shell command, echoing output, painting error lines red, # print runtime and status # return status and output cmd = create_command(cli_command) print('>> Starting: ' + cmd) start = time.time() output = '' errpat = re.compile('error', re.I) p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE) for line in iter(p.stdout.readline, b''): out = line.rstrip() print((">>> " + out)) output += out end = time.time() span = end - start retcode = p.wait() print('>> Ended: %s [%s, %d:%02d]' % (cmd, retcode, span / 60, span % 60)) return retcode, output parser = argparse.ArgumentParser(prog='regionator', description='batch add region to flavor') parser.add_argument('regions', type=str, default='', help='') parser.add_argument('series', type=str, default='', nargs='?', help='') args = parser.parse_args() regions = args.regions.split(',') series_list = args.series.split(',') if not regions: print("Must specify at least one region") exit(1) # Get all regions from RMS region_list = get_region_list(regions) any_update = False for file in [os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(FLAVOR_DIR)) for f in fn]: try: f = read_jsonfile(file) except ValueError: continue updated = False flavor_type = get_flavor_type(file) if not series_list or series_list == [''] or f['series'] in series_list: data = {'regions': []} for region in region_list: # Take only the regions whose design type matches the flavor's if flavor_type.lower() == region['designType'].lower(): data['regions'].append({'name': region['name']}) updated = True any_update = True if updated: # Create the json file fh, file_name = tempfile.mkstemp() FILE_NAME = file_name os.write(fh, json.dumps(data)) os.close(fh) FLAVOR_NAME = calculate_name(f) res, output = sh('get_flavor') if not res: flavor = ast.literal_eval(output) FID = flavor['flavor']['id'] print('fid: ' + FID) res, output = sh('add_region') os.unlink(FILE_NAME) if not any_update: if not args.series: exp = 'design type of any of the regions:[{}]'.format(args.regions) else: exp = 'combination of regions:[{}] and series:[{}]'.format( args.regions, args.series) print(('No flavor was updated, please make sure that the {} matches any ' 'flavor under the flavor directory'.format(exp)))