Added orm_client codebase
Initial commit for orm_client by adding the codebase. Change-Id: I24f17561e6a426e6af9dbbe04e4a66599344d265
This commit is contained in:
parent
5de8154ed7
commit
2bc511c69f
0
orm/orm_client/db_clear/__init__.py
Normal file
0
orm/orm_client/db_clear/__init__.py
Normal file
49
orm/orm_client/db_clear/cli_comander.py
Normal file
49
orm/orm_client/db_clear/cli_comander.py
Normal file
@ -0,0 +1,49 @@
|
||||
import config as conf
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_regions(customer):
|
||||
regions = []
|
||||
try:
|
||||
customer_json = json.loads(customer)
|
||||
if 'regions' not in customer_json:
|
||||
raise Exception("got bad response from orm cli ")
|
||||
for region in customer_json['regions']:
|
||||
regions.append(region['name'])
|
||||
except Exception as exp:
|
||||
raise Exception("got bad response from orm cli {}".format(exp.message))
|
||||
message = "got no regions from orm cli"
|
||||
if regions:
|
||||
message = "got regions from orm cli --{}--".format(regions)
|
||||
log.debug(message)
|
||||
return regions
|
||||
|
||||
|
||||
def _build_get_customer_cli_command(resource_id):
|
||||
cli_command = """get_customer %s""" % resource_id
|
||||
log.debug('cli command {}'.format(cli_command))
|
||||
return cli_command
|
||||
|
||||
|
||||
def _get_customer_regions(cli_command, service):
|
||||
client_header = service.upper()
|
||||
log.debug("get customer with cli")
|
||||
os.chdir(conf.cli_dir)
|
||||
cwd = os.getcwd()
|
||||
customer = os.popen('./orm %s %s ' % (service.lower(), cli_command))
|
||||
log.debug("got cusmer with cli ... check if got regions")
|
||||
return _get_regions(customer.read())
|
||||
|
||||
|
||||
def get_resource_regions(resource_id, service):
|
||||
log.debug("---ORM CLI---")
|
||||
regions = None
|
||||
if service.upper() == 'CMS':
|
||||
regions = _get_customer_regions(
|
||||
_build_get_customer_cli_command(resource_id), service)
|
||||
return regions
|
102
orm/orm_client/db_clear/cms_cleaner.py
Normal file
102
orm/orm_client/db_clear/cms_cleaner.py
Normal file
@ -0,0 +1,102 @@
|
||||
"""clean cms mpdule."""
|
||||
import cli_comander as cli
|
||||
import db_comander as db
|
||||
import initializer
|
||||
import logging
|
||||
import sys
|
||||
import utils
|
||||
import yaml_handler as yh
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _validate_service(service):
|
||||
allowed_services = ['CMS', 'FMS']
|
||||
if service.upper() not in allowed_services:
|
||||
raise Exception("service should be one of {}".format(allowed_services))
|
||||
return service.upper()
|
||||
|
||||
|
||||
def _init():
|
||||
initializer.init_log()
|
||||
return
|
||||
|
||||
|
||||
def read_csv_file(file):
|
||||
log.debug("reading file {}".format(file))
|
||||
return utils.read_csv_file(file)
|
||||
|
||||
|
||||
def resource_db_clean(resource_id, service):
|
||||
log.debug("cleaning {} db for resource {}".format(service, resource_id))
|
||||
db.remove_resource_db(resource_id, service)
|
||||
return
|
||||
|
||||
|
||||
def check_yaml_file(resource_id):
|
||||
log.debug('checking yml file if exist for resource {}'.format(resource_id))
|
||||
files = yh.check_yaml_exist(resource_id)
|
||||
message = 'no yaml files found for this resource'
|
||||
if files:
|
||||
message = "found files please remove manualy {}".format(files)
|
||||
log.debug(message)
|
||||
return
|
||||
|
||||
|
||||
def get_resource_regions(resource_id, service_name):
|
||||
db_regions = db.get_cms_db_resource_regions(resource_id)
|
||||
orm_regions = cli.get_resource_regions(resource_id, service_name)
|
||||
return orm_regions, db_regions
|
||||
|
||||
|
||||
def clean_rds_resource_status(resource_id):
|
||||
log.debug("clean rds status db for resource {}".format(resource_id))
|
||||
db.remove_rds_resource_status(resource_id)
|
||||
return
|
||||
|
||||
|
||||
def _start_cleaning():
|
||||
log.info('start cleaning')
|
||||
file_path = sys.argv[1]
|
||||
service = _validate_service(sys.argv[2])
|
||||
resourses_to_clean = read_csv_file(file_path)
|
||||
for resource_id in resourses_to_clean:
|
||||
try:
|
||||
log.debug(
|
||||
'check if resource {} has any regions before clean'.format(
|
||||
resource_id))
|
||||
resource_regions, db_regions = get_resource_regions(resource_id,
|
||||
service)
|
||||
if resource_regions or db_regions:
|
||||
log.error(
|
||||
"got regions {} {} please clean regions from orm before"
|
||||
" removing the resource {}".format(resource_regions,
|
||||
db_regions,
|
||||
resource_id))
|
||||
raise Exception(
|
||||
"got regions {} {} please clean regions from orm before"
|
||||
" removing the resource {}".format(resource_regions,
|
||||
db_regions,
|
||||
resource_id))
|
||||
|
||||
log.debug('cleaning {}'.format(resource_id))
|
||||
resource_db_clean(resource_id, service)
|
||||
check_yaml_file(resource_id)
|
||||
clean_rds_resource_status(resource_id)
|
||||
|
||||
except Exception as exp:
|
||||
log.error("---------------{}---------------".format(exp.message))
|
||||
if 'not found' not in exp.message:
|
||||
log.exception(exp)
|
||||
continue
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
warning_message = raw_input(
|
||||
'IMPORTANT:- please note its your responsibility to backup the db'
|
||||
' before runing this script... click enter before continue'
|
||||
)
|
||||
_init()
|
||||
_start_cleaning()
|
25
orm/orm_client/db_clear/config.py
Normal file
25
orm/orm_client/db_clear/config.py
Normal file
@ -0,0 +1,25 @@
|
||||
"""config module."""
|
||||
|
||||
# db configs
|
||||
sql_user = 'root'
|
||||
sql_password = 'stack'
|
||||
sql_server = '127.0.0.1'
|
||||
sql_port = '3306'
|
||||
|
||||
# cms configs
|
||||
customer_table_name = "customer"
|
||||
customer_region_table_name = "customer_region"
|
||||
cms_db_name = "orm_cms_db"
|
||||
|
||||
|
||||
# cli configs
|
||||
cli_dir = '../ormcli'
|
||||
|
||||
# rds configs
|
||||
rds_db_name = 'orm_rds'
|
||||
resource_status_table_name = 'resource_status'
|
||||
|
||||
# sot configs
|
||||
local_repository_path = '/opt/app/orm/ORM'
|
||||
file_name_format = 's_{}.yml'
|
||||
relative_path_format = '/{}/hot/{}/{}'
|
130
orm/orm_client/db_clear/db_comander.py
Normal file
130
orm/orm_client/db_clear/db_comander.py
Normal file
@ -0,0 +1,130 @@
|
||||
import config as conf
|
||||
import logging
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
db_engines = {}
|
||||
|
||||
|
||||
def _db_create_engine(db_name):
|
||||
global db_engines
|
||||
if db_name not in db_engines:
|
||||
db_address = 'mysql://{}:{}@{}:{}/{}'.format(conf.sql_user,
|
||||
conf.sql_password,
|
||||
conf.sql_server,
|
||||
conf.sql_port,
|
||||
db_name)
|
||||
log.debug("DB:--- db address {}".format(db_address))
|
||||
db_engines[db_name] = sqlalchemy.create_engine(db_address)
|
||||
return db_engines
|
||||
|
||||
|
||||
def _run_query(query, db_name):
|
||||
db_engines = _db_create_engine(db_name)
|
||||
connection = db_engines[db_name].connect()
|
||||
try:
|
||||
sqlres = connection.execute(query)
|
||||
except Exception as exp:
|
||||
sqlres = None
|
||||
log.error("fail to delete resource {}".format(exp))
|
||||
finally:
|
||||
# close the connection
|
||||
connection.close()
|
||||
# db_engines[db_name].dispose()
|
||||
return sqlres
|
||||
|
||||
|
||||
def _build_delet_resource_status_query(resource_id, table_name):
|
||||
query = '''
|
||||
DELETE from %s
|
||||
WHERE resource_id = '%s'
|
||||
''' % (table_name, resource_id)
|
||||
return query
|
||||
|
||||
|
||||
def _build_delete_resource_query(resource_id, table_name):
|
||||
query = '''
|
||||
DELETE from %s
|
||||
WHERE %s.uuid = '%s'
|
||||
''' % (table_name, table_name, resource_id)
|
||||
return query
|
||||
|
||||
|
||||
def _build_get_resource_regions_query(resource_id, table_name):
|
||||
query = '''
|
||||
select region_id from %s
|
||||
WHERE customer_id = '%s' and region_id != '-1'
|
||||
''' % (table_name, resource_id)
|
||||
return query
|
||||
|
||||
|
||||
def _build_get_resource_id_query(resource_id, table_name):
|
||||
query = '''
|
||||
select * from %s
|
||||
WHERE %s.uuid = '%s'
|
||||
''' % (table_name, table_name, resource_id)
|
||||
return query
|
||||
|
||||
|
||||
def remove_cms_resource(resource_id):
|
||||
query = _build_delete_resource_query(resource_id, conf.customer_table_name)
|
||||
log.debug("DB---: deleting customer, query {}".format(query))
|
||||
_run_query(query, conf.cms_db_name)
|
||||
return
|
||||
|
||||
|
||||
def remove_rds_resource_status(resource_id):
|
||||
query = _build_delet_resource_status_query(resource_id,
|
||||
conf.resource_status_table_name)
|
||||
log.debug("DB---: deleting resource status, query {}".format(query))
|
||||
_run_query(query, conf.rds_db_name)
|
||||
return
|
||||
|
||||
|
||||
def remove_ims_resource(resource_id):
|
||||
return
|
||||
|
||||
|
||||
def remove_fms_resource(resource_id):
|
||||
return
|
||||
|
||||
|
||||
def get_cms_db_resource_regions(resource_id):
|
||||
regions = None
|
||||
query = _build_get_resource_id_query(resource_id, conf.customer_table_name)
|
||||
result = _run_query(query, conf.cms_db_name)
|
||||
if not result.rowcount > 0:
|
||||
raise Exception('resource {} not found'.format(resource_id))
|
||||
resource_internal_id = result.first().__getitem__('id')
|
||||
log.debug("got resource internal id {}".format(resource_internal_id))
|
||||
# from resource id get regions
|
||||
query = _build_get_resource_regions_query(resource_internal_id,
|
||||
conf.customer_region_table_name)
|
||||
log.debug(query)
|
||||
result = _run_query(query, conf.cms_db_name)
|
||||
if result.rowcount > 0:
|
||||
regions = result.fetchall()
|
||||
return regions
|
||||
|
||||
|
||||
def get_ims_db_resource_regions(resource_id):
|
||||
return
|
||||
|
||||
|
||||
def get_fms_db_resource_regions(resource_id):
|
||||
return
|
||||
|
||||
|
||||
def get_rds_db_resource_status(resource_id):
|
||||
return
|
||||
|
||||
|
||||
def remove_resource_db(resource_id, service):
|
||||
if service == 'CMS':
|
||||
log.debug(
|
||||
"cleaning {} db for resource {}".format(service, resource_id))
|
||||
remove_cms_resource(resource_id)
|
||||
return
|
10
orm/orm_client/db_clear/initializer.py
Normal file
10
orm/orm_client/db_clear/initializer.py
Normal file
@ -0,0 +1,10 @@
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def init_log():
|
||||
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',
|
||||
level=logging.DEBUG)
|
||||
logging.info("logger set")
|
23
orm/orm_client/db_clear/utils.py
Normal file
23
orm/orm_client/db_clear/utils.py
Normal file
@ -0,0 +1,23 @@
|
||||
import csv
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _validate_file(file):
|
||||
if str(file).split('.')[-1] != 'csv':
|
||||
log.error('please provide csv file')
|
||||
raise TypeError('please provide csv file')
|
||||
|
||||
|
||||
def read_csv_file(file):
|
||||
_validate_file(file)
|
||||
resources = []
|
||||
with open(file, 'rb') as csvfile:
|
||||
csv_dict = csv.DictReader(csvfile)
|
||||
for resource in csv_dict:
|
||||
resources.append(resource["uuids"])
|
||||
log.debug(
|
||||
'list of resources to clean ----{} -------'.format(resources))
|
||||
return resources
|
25
orm/orm_client/db_clear/yaml_handler.py
Normal file
25
orm/orm_client/db_clear/yaml_handler.py
Normal file
@ -0,0 +1,25 @@
|
||||
import config as conf
|
||||
import fnmatch
|
||||
import os
|
||||
|
||||
|
||||
def _get_resource_file_path():
|
||||
file_path = conf.local_repository_path
|
||||
return file_path
|
||||
|
||||
|
||||
def _find_file(resource_id):
|
||||
file_name = conf.file_name_format.format(resource_id)
|
||||
folder_to_search = _get_resource_file_path(resource_id)
|
||||
matches = []
|
||||
for root, dirnames, filenames in os.walk(folder_to_search):
|
||||
for filename in fnmatch.filter(filenames, file_name):
|
||||
matches.append(os.path.join(root, filename))
|
||||
return matches
|
||||
|
||||
|
||||
def check_yaml_exist(resource_id):
|
||||
files = _find_file(resource_id)
|
||||
if files:
|
||||
return files
|
||||
return None
|
41
orm/orm_client/flavorgen/README
Normal file
41
orm/orm_client/flavorgen/README
Normal file
@ -0,0 +1,41 @@
|
||||
Flavorgen Usage
|
||||
|
||||
To install:
|
||||
|
||||
1. Download attached file flavorgen.tgz
|
||||
2. Copy flavorgen.tgz to <orm_host>:/opt/app/orm/ormcli
|
||||
3. cd /opt/app/orm/ormcli
|
||||
4. tar xvzf flavorgen.tgz
|
||||
|
||||
All the predefined flavors are defined in flavor_dir. Edit if necessary.
|
||||
|
||||
To generate these flavors:
|
||||
|
||||
5. cd /opt/app/orm/ormcli/flavorgen
|
||||
6. ./flavorator.py
|
||||
|
||||
You should normally create the list of flavors once.
|
||||
|
||||
Then when you want to add regions to all the flavors, use:
|
||||
|
||||
7. ./regionator.py --regions region1,region2
|
||||
|
||||
The argument is a comma-separated list of regions with no internal whitespace.
|
||||
|
||||
|
||||
Use of -h will produce the following help:
|
||||
|
||||
./regionator.py -h
|
||||
usage: regionator [-h] [--flavor_dir FLAVOR_DIR] [--host HOST]
|
||||
[--cli_command CLI_COMMAND] [--regions REGIONS]
|
||||
|
||||
batch add region to flavor
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--flavor_dir FLAVOR_DIR
|
||||
<JSON flavor directory, default: ./flavor_dir>
|
||||
--host HOST <orm host ip>
|
||||
--cli_command CLI_COMMAND
|
||||
<path to cli command>
|
||||
--regions REGIONS <comma-separated regions to add, e.g. region1,region2>
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c12r64d400
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c12r64d400
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 12 VCPUs, 64 GB RAM, 400 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "65536",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "12",
|
||||
"swap": "0",
|
||||
"disk": "400"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c1r2d12e20
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c1r2d12e20
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 1 VCPU, 2 GB RAM, 12 GB Disk, 0 GB Swap and 20 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "2048",
|
||||
"ephemeral": "20",
|
||||
"visibility": "public",
|
||||
"vcpus": "1",
|
||||
"swap": "0",
|
||||
"disk": "12"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r2d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r2d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 2 VCPUs, 2 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "2048",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "2",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r4d12e40
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r4d12e40
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 2 VCPUs, 4 GB RAM, 12 GB Disk, 0 GB Swap and 40 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "4096",
|
||||
"ephemeral": "40",
|
||||
"visibility": "public",
|
||||
"vcpus": "2",
|
||||
"swap": "0",
|
||||
"disk": "12"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r4d20
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c2r4d20
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 2 VCPUs, 4 GB RAM, 20 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "4096",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "2",
|
||||
"swap": "0",
|
||||
"disk": "20"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r12d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r12d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 4 VCPUs, 12 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "12288",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r16d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r16d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 4 VCPUs, 16 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "16384",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r2d80e160
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r2d80e160
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 4 VCPUs, 2 GB RAM, 80 GB Disk, 0 GB Swap and 160 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "2048",
|
||||
"ephemeral": "160",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "80"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r32d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c4r32d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 4 VCPUs, 32 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "32768",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r16d40
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r16d40
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 8 VCPUs, 16 GB RAM, 40 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "16384",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "40"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r16d80e160
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r16d80e160
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 8 VCPUs, 16 GB RAM, 80 GB Disk, 0 GB Swap and 160 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "16384",
|
||||
"ephemeral": "160",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "80"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r32d80e320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r32d80e320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 8 VCPUs, 32 GB RAM, 80 GB Disk, 0 GB Swap and 320 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "32768",
|
||||
"ephemeral": "320",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "80"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r64d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/gv.c8r64d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard GV flavor with 8 VCPUs, 64 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "gv",
|
||||
"ram": "65536",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c12r64d400
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c12r64d400
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 12 VCPUs, 64 GB RAM, 400 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "65536",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "12",
|
||||
"swap": "0",
|
||||
"disk": "400"
|
||||
}
|
11
orm/orm_client/flavorgen/flavor_dir/Large/nv.c2r2d320
Normal file
11
orm/orm_client/flavorgen/flavor_dir/Large/nv.c2r2d320
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 2 VCPUs, 2 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "2048",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "2",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
||||
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c2r4d20
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c2r4d20
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 2 VCPUs, 4 GB RAM, 20 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "4096",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "2",
|
||||
"swap": "0",
|
||||
"disk": "20"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r12d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r12d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 4 VCPUs, 12 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "12288",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r16d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r16d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 4 VCPUs, 16 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "16384",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r32d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c4r32d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 4 VCPUs, 32 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "32768",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "4",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c8r16d40
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c8r16d40
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 8 VCPUs, 16 GB RAM, 40 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "16384",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "40"
|
||||
}
|
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c8r64d320
Normal file
10
orm/orm_client/flavorgen/flavor_dir/Large/nv.c8r64d320
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description":"A standard NV flavor with 8 VCPUs, 64 GB RAM, 320 GB Disk, 0 GB Swap and 0 GB Ephemeral",
|
||||
"series": "nv",
|
||||
"ram": "65536",
|
||||
"ephemeral": "0",
|
||||
"visibility": "public",
|
||||
"vcpus": "8",
|
||||
"swap": "0",
|
||||
"disk": "320"
|
||||
}
|
70
orm/orm_client/flavorgen/flavorator.py
Normal file
70
orm/orm_client/flavorgen/flavorator.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
# Default flavor json directory
|
||||
FLAVOR_DIR = './flavor_dir'
|
||||
|
||||
|
||||
def read_jsonfile(file):
|
||||
return json.loads(open(file).read())
|
||||
|
||||
|
||||
def calculate_name(flavor):
|
||||
return "{0}.c{1}r{2}d{3}".format(flavor['series'], flavor['vcpus'],
|
||||
int(flavor['ram']) / 1024, flavor['disk'])
|
||||
|
||||
|
||||
def sh(harg, file_name):
|
||||
# run a shell command, echoing output, painting error lines red,
|
||||
# print runtime and status
|
||||
# return status and output
|
||||
|
||||
cmd = create_command(harg, file_name)
|
||||
|
||||
print '>> Starting: ' + cmd
|
||||
start = time.time()
|
||||
output = ''
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
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
|
||||
|
||||
|
||||
def create_command(harg, file_name):
|
||||
cmd = 'python ../ormcli/orm fms %s create_flavor %s' % \
|
||||
(harg, file_name)
|
||||
if ';' in cmd or '&&' in cmd:
|
||||
raise Exception("Violation of command injection, cmd is " + cmd)
|
||||
return cmd
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(prog='flavorator',
|
||||
description='batch flavor creator')
|
||||
args = parser.parse_args()
|
||||
|
||||
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
|
||||
|
||||
print f
|
||||
flavor_name = calculate_name(f)
|
||||
fh, file_name = tempfile.mkstemp()
|
||||
os.write(fh, json.dumps({"flavor": f}))
|
||||
os.close(fh)
|
||||
res, output = sh('', file_name)
|
||||
os.unlink(file_name)
|
36
orm/orm_client/flavorgen/make_flav.py
Normal file
36
orm/orm_client/flavorgen/make_flav.py
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
import json
|
||||
import sys
|
||||
|
||||
if sys.argv[1].isdigit():
|
||||
vcpus = sys.argv[1]
|
||||
else:
|
||||
vcpus = "1"
|
||||
if sys.argv[1].isdigit():
|
||||
ram = sys.argv[1]
|
||||
else:
|
||||
ram = "1"
|
||||
if sys.argv[1].isdigit():
|
||||
disk = sys.argv[1]
|
||||
else:
|
||||
disk = "1"
|
||||
|
||||
|
||||
def calculate_name(flavor):
|
||||
return "{0}.c{1}r{2}d{3}".format(flavor['series'], flavor['vcpus'],
|
||||
flavor['ram'], flavor['disk'])
|
||||
|
||||
data = {
|
||||
"series": "gv",
|
||||
"vcpus": "10",
|
||||
"ram": "20",
|
||||
"disk": "30",
|
||||
"ephemeral": "0",
|
||||
"swap": "0",
|
||||
"visibility": "public"
|
||||
}
|
||||
|
||||
flavor_name = calculate_name(data)
|
||||
series = flavor_name.split('.')[0]
|
||||
|
||||
open(flavor_name, "w").write(json.dumps(data, indent=4) + '\n')
|
37
orm/orm_client/flavorgen/make_flavor.py
Normal file
37
orm/orm_client/flavorgen/make_flavor.py
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
data = {
|
||||
"swap": "0",
|
||||
"visibility": "public"
|
||||
}
|
||||
|
||||
flavor_name = sys.argv[1]
|
||||
series, geometry = flavor_name.split('.')
|
||||
try:
|
||||
# Try with ephemeral
|
||||
match = re.search('c(.+?)r(.+?)d(.+?)e(.*)', geometry)
|
||||
vcpus = match.group(1)
|
||||
ram = match.group(2)
|
||||
disk = match.group(3)
|
||||
ephemeral = match.group(4)
|
||||
except AttributeError:
|
||||
# Try without ephemeral. If this doesn't work, the input is invalid
|
||||
match = re.search('c(.+?)r(.+?)d(.*)', geometry)
|
||||
vcpus = match.group(1)
|
||||
ram = match.group(2)
|
||||
disk = match.group(3)
|
||||
ephemeral = 0
|
||||
|
||||
# Fill the Flavor data
|
||||
data['series'] = series
|
||||
data['vcpus'] = vcpus
|
||||
data['ram'] = str(int(ram) * 1024)
|
||||
data['disk'] = disk
|
||||
data['ephemeral'] = str(ephemeral)
|
||||
|
||||
# Write the Flavor JSON to the file
|
||||
open(flavor_name, "w").write(json.dumps(data, indent=4) + '\n')
|
161
orm/orm_client/flavorgen/regionator.py
Normal file
161
orm/orm_client/flavorgen/regionator.py
Normal file
@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python
|
||||
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 = ast.literal_eval(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 = '%s fms get_flavor test %s' % (CLI_PATH, FLAVOR_NAME,)
|
||||
elif cli_command == 'get_region':
|
||||
cmd = '%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, shell=True, 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='<comma-separated regions to add, e.g. region1,'
|
||||
'region2>')
|
||||
parser.add_argument('series',
|
||||
type=str,
|
||||
default='',
|
||||
nargs='?',
|
||||
help='<comma-separated flavor series to add, e.g. nd,gv>')
|
||||
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))
|
41
orm/orm_client/imagegen/README
Normal file
41
orm/orm_client/imagegen/README
Normal file
@ -0,0 +1,41 @@
|
||||
imagegen Usage
|
||||
|
||||
To install:
|
||||
|
||||
1. Download attached file imagegen.tgz
|
||||
2. Copy imagegen.tgz to <orm_host>:/opt/app/orm/ormcli
|
||||
3. cd /opt/app/orm/ormcli
|
||||
4. tar xvzf imagegen.tgz
|
||||
|
||||
All the predefined imagess are defined in image_dir. Edit if necessary.
|
||||
|
||||
To generate these images:
|
||||
|
||||
5. cd /opt/app/orm/ormcli/imagegen
|
||||
6. python imageator.py
|
||||
|
||||
You should normally create the list of images once.
|
||||
|
||||
Then when you want to add regions to all the images, use:
|
||||
|
||||
7. python regionator.py <region1>,<region2>
|
||||
|
||||
The argument is a comma-separated list of regions with no internal whitespace.
|
||||
|
||||
|
||||
Use of -h will produce the following help:
|
||||
|
||||
./regionator.py -h
|
||||
usage: regionator [-h] [--image_dir IMAGE_DIR] [--host HOST]
|
||||
[--cli_command CLI_COMMAND] [--regions REGIONS]
|
||||
|
||||
batch add region to image
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--image_dir IMAGE_DIR
|
||||
<JSON image directory, default: ./image_dir>
|
||||
--host HOST <orm host ip>
|
||||
--cli_command CLI_COMMAND
|
||||
<path to cli command>
|
||||
--regions REGIONS <comma-separated regions to add, e.g. region1,region2>
|
11
orm/orm_client/imagegen/image_dir/test_image
Normal file
11
orm/orm_client/imagegen/image_dir/test_image
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "test_image",
|
||||
"url": "https://mirrors.it.att.com/images/image-name",
|
||||
"visibility": "public",
|
||||
"disk-format": "raw",
|
||||
"container-format": "bare",
|
||||
"min-disk": 0,
|
||||
"owner": "ME",
|
||||
"enabled": true,
|
||||
"protected": false
|
||||
}
|
84
orm/orm_client/imagegen/imageator.py
Normal file
84
orm/orm_client/imagegen/imageator.py
Normal file
@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
from os.path import isfile, join
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
# from colorama import init, Fore, Back, Style
|
||||
|
||||
|
||||
# Default flavor json directory
|
||||
IMAGE_DIR = './image_dir'
|
||||
CLI_PATH = '../ormcli/orm'
|
||||
|
||||
|
||||
def read_jsonfile(file):
|
||||
return json.loads(open(file).read())
|
||||
|
||||
|
||||
def sh(cmd):
|
||||
# run a shell command, echoing output, painting error lines red,
|
||||
# print runtime and status
|
||||
# return status and output
|
||||
|
||||
print '>> Starting: ' + cmd
|
||||
start = time.time()
|
||||
output = ''
|
||||
errpat = re.compile('error', re.I)
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
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='imageator',
|
||||
description='batch image/region creator')
|
||||
# parser.add_argument('--image_dir',
|
||||
# type=str,
|
||||
# default='./image_dir',
|
||||
# help='<JSON image directory, default: ./image_dir>')
|
||||
# parser.add_argument('--host',
|
||||
# type=str,
|
||||
# help='<orm host ip>')
|
||||
# parser.add_argument('--cli_command',
|
||||
# type=str,
|
||||
# default='/opt/app/orm/ormcli/ormcli/orm',
|
||||
# help='<path to cli command>')
|
||||
args = parser.parse_args()
|
||||
|
||||
summary = []
|
||||
|
||||
for file in [f for f in os.listdir(IMAGE_DIR) if
|
||||
isfile(join(IMAGE_DIR, f))]:
|
||||
f = read_jsonfile(join(IMAGE_DIR, file))
|
||||
|
||||
print f
|
||||
image_name = f['name']
|
||||
fh, file_name = tempfile.mkstemp()
|
||||
os.write(fh, json.dumps({"image": f}))
|
||||
os.close(fh)
|
||||
# harg = '--orm-base-url %s' % args.host if args.host else ''
|
||||
res, output = sh('%s ims create_image test %s' % (
|
||||
CLI_PATH, file_name))
|
||||
os.unlink(file_name)
|
||||
|
||||
summary.append("File name: {}, Image name: {}, Create image status: {}\n".
|
||||
format(file,
|
||||
image_name,
|
||||
'Success' if res == 0 else 'Failed'))
|
||||
|
||||
print "\nImage creation summary:"
|
||||
print "-----------------------"
|
||||
for s in summary:
|
||||
print s
|
98
orm/orm_client/imagegen/regionator.py
Normal file
98
orm/orm_client/imagegen/regionator.py
Normal file
@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python
|
||||
from os.path import isfile, join
|
||||
import argparse
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
# from colorama import init, Fore, Back, Style
|
||||
|
||||
# Default flavor json directory
|
||||
IMAGE_DIR = './image_dir'
|
||||
CLI_PATH = '../ormcli/orm'
|
||||
|
||||
|
||||
def read_jsonfile(file):
|
||||
return json.loads(open(file).read())
|
||||
|
||||
|
||||
def sh(cmd):
|
||||
# run a shell command, echoing output, painting error lines red,
|
||||
# print runtime and status
|
||||
# return status and output
|
||||
|
||||
print '>> Starting: ' + cmd
|
||||
start = time.time()
|
||||
output = ''
|
||||
errpat = re.compile('error', re.I)
|
||||
p = subprocess.Popen(cmd, shell=True, 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 image')
|
||||
# parser.add_argument('--image_dir',
|
||||
# type=str,
|
||||
# default='./image_dir',
|
||||
# help='<JSON image directory, default: ./image_dir>')
|
||||
# parser.add_argument('--host',
|
||||
# type=str,
|
||||
# help='<orm host ip>')
|
||||
# parser.add_argument('--cli_command',
|
||||
# type=str,
|
||||
# default='/opt/app/orm/ormcli/ormcli/orm',
|
||||
# help='<path to cli command>')
|
||||
parser.add_argument('regions',
|
||||
type=str,
|
||||
default='',
|
||||
help='<comma-separated regions to add, e.g. region1,'
|
||||
'region2>')
|
||||
args = parser.parse_args()
|
||||
|
||||
regions = args.regions.split(',')
|
||||
if not regions:
|
||||
print "Must specify at least one region"
|
||||
exit(0)
|
||||
data = {'regions': [{'name': r} for r in regions]}
|
||||
fh, file_name = tempfile.mkstemp()
|
||||
os.write(fh, json.dumps(data))
|
||||
os.close(fh)
|
||||
|
||||
# Prepare images dict with pairs {image_name:image_id}
|
||||
img_dict = {}
|
||||
# harg = '--orm-base-url %s' % args.host if args.host else ''
|
||||
res, output = sh(
|
||||
'%s ims %s list_images test ' % (CLI_PATH, ''))
|
||||
if not res:
|
||||
images = ast.literal_eval(output)
|
||||
for img in images['images']:
|
||||
img_dict[img['name']] = img['id']
|
||||
print img_dict
|
||||
|
||||
for file in [f for f in os.listdir(IMAGE_DIR) if
|
||||
isfile(join(IMAGE_DIR, f))]:
|
||||
f = read_jsonfile(join(IMAGE_DIR, file))
|
||||
|
||||
print f
|
||||
image_name = f['name']
|
||||
if image_name in img_dict:
|
||||
image_id = img_dict[image_name]
|
||||
print 'image_id: ' + image_id
|
||||
res, output = sh('%s ims add_regions test %s %s' % (
|
||||
CLI_PATH, image_id, file_name))
|
||||
else:
|
||||
print 'image_name: {} does not exist. ignore.'.format(image_name)
|
||||
|
||||
os.unlink(file_name)
|
69
orm/orm_client/ormcli/README
Normal file
69
orm/orm_client/ormcli/README
Normal file
@ -0,0 +1,69 @@
|
||||
How to install orm cli
|
||||
======================
|
||||
|
||||
Ensure you have python and pip installed
|
||||
|
||||
> tar xvzf ormcli.tgz
|
||||
> cd ormcli
|
||||
> pip install -r requirements.txt
|
||||
|
||||
|
||||
How to run orm cli
|
||||
==================
|
||||
|
||||
cms, fms, and rms are all services that should be installed somewhere.
|
||||
To access these services, you'll need their IP addresses and port numbers,
|
||||
which should be supplied with the --host and --port arguments
|
||||
|
||||
For general help
|
||||
================
|
||||
|
||||
> orm -h
|
||||
usage: orm [-h] <service> ...
|
||||
|
||||
ORM REST CLI
|
||||
|
||||
positional arguments:
|
||||
<service>
|
||||
rms Endpoint Discovery Service
|
||||
cms Customer Management Service
|
||||
fms Flavor Management Service
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
To get help on the cms subsystem
|
||||
================================
|
||||
|
||||
> orm cms -h
|
||||
usage: orm cms [-h] [--version] [--requester REQUESTER]
|
||||
[--tracking_id TRACKING_ID] [--host HOST] [--port PORT]
|
||||
[--timeout TIMEOUT]
|
||||
auth_token auth_region client <subcommand> [-h] <args> ...
|
||||
|
||||
positional arguments:
|
||||
auth_token keystone user authorization token
|
||||
auth_region keystone region authorization id
|
||||
client client (application_id)
|
||||
<subcommand> [-h] <args>
|
||||
create_customer datafile
|
||||
update_customer custid datafile
|
||||
add_region custid datafile
|
||||
delete_region custid regionid
|
||||
add_user custid regionid datafile
|
||||
delete_default_user
|
||||
custid userid
|
||||
delete_user_from_region
|
||||
custid regionid userid
|
||||
get_customer custid
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--version show program's version number and exit
|
||||
--requester REQUESTER
|
||||
requester (user_id)
|
||||
--tracking_id TRACKING_ID
|
||||
tracking id
|
||||
--host HOST hostname or ip of CMS server
|
||||
--port PORT port number of CMS server
|
||||
--timeout TIMEOUT request timeout in ms (default: 10000)
|
0
orm/orm_client/ormcli/__init__.py
Normal file
0
orm/orm_client/ormcli/__init__.py
Normal file
53
orm/orm_client/ormcli/cli_common.py
Normal file
53
orm/orm_client/ormcli/cli_common.py
Normal file
@ -0,0 +1,53 @@
|
||||
import config
|
||||
import json
|
||||
import requests
|
||||
|
||||
OK_CODE = 200
|
||||
|
||||
ORM_CLIENT_KWARGS = {'type': str, 'help': 'client name', 'default': None,
|
||||
'nargs': '?'}
|
||||
|
||||
|
||||
class MissingArgumentError(Exception):
|
||||
"""Should be raised when an argument was found missing by CLI logic."""
|
||||
pass
|
||||
|
||||
|
||||
def get_keystone_ep(rms_url, region_name):
|
||||
"""Get the Keystone EP from RMS.
|
||||
|
||||
:param rms_url: RMS server URL
|
||||
:param region_name: The region name
|
||||
:return: Keystone EP (string), None if it was not found
|
||||
"""
|
||||
try:
|
||||
response = requests.get('%s/v2/orm/regions?regionname=%s' % (
|
||||
rms_url, region_name, ), verify=config.verify)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print('Could not connect to RMS, URL: {}'.format(rms_url))
|
||||
return None
|
||||
|
||||
if response.status_code != OK_CODE:
|
||||
print('RMS returned status: {}, content: {}'.format(
|
||||
response.status_code, response.content))
|
||||
return None
|
||||
|
||||
# RMS returned 200
|
||||
lcp = response.json()
|
||||
try:
|
||||
for endpoint in lcp['regions'][0]['endpoints']:
|
||||
if endpoint['type'] == 'identity':
|
||||
return endpoint['publicURL']
|
||||
except KeyError:
|
||||
print('Response from RMS came in an unsupported format. '
|
||||
'Make sure that you are using RMS 3.5')
|
||||
return None
|
||||
|
||||
# Keystone EP not found in the response
|
||||
print('No identity endpoint was found in the response from RMS')
|
||||
return None
|
||||
|
||||
|
||||
def pretty_print_json(json_to_print):
|
||||
"""Print a json without the u' prefix."""
|
||||
print(json.dumps(json_to_print))
|
449
orm/orm_client/ormcli/cmscli.py
Normal file
449
orm/orm_client/ormcli/cmscli.py
Normal file
@ -0,0 +1,449 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import cli_common
|
||||
import config
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
class ResponseError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def add_to_parser(service_sub):
|
||||
parser = \
|
||||
service_sub.add_parser('cms',
|
||||
help='Customer Management Service',
|
||||
formatter_class=lambda prog:
|
||||
argparse.HelpFormatter(prog,
|
||||
max_help_position=30,
|
||||
width=120))
|
||||
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
|
||||
parser.add_argument('--auth-region', type=str,
|
||||
help='Region used for authentication',
|
||||
default=get_environment_variable('auth-region'))
|
||||
parser.add_argument('--tenant-name', type=str,
|
||||
help='Keystone user tenant name',
|
||||
default=get_environment_variable('tenant-name'))
|
||||
parser.add_argument('--username', type=str, help='Keystone user name',
|
||||
default=get_environment_variable('username'))
|
||||
parser.add_argument('--password', type=str, help='Keystone user password',
|
||||
default=get_environment_variable('password'))
|
||||
parser.add_argument('--orm-base-url', type=str, help='ORM base URL',
|
||||
default=get_environment_variable('orm-base-url'))
|
||||
parser.add_argument('--tracking_id', type=str,
|
||||
help='"X-AIC-ORM-Tracking-Id" header')
|
||||
parser.add_argument('--port', type=int, help='port number of CMS server')
|
||||
parser.add_argument('--timeout', type=int,
|
||||
help='request timeout in seconds (default: 10)')
|
||||
parser.add_argument('-v', '--verbose', help='show details',
|
||||
action="store_true")
|
||||
parser.add_argument('-f', '--faceless',
|
||||
help='run without authentication',
|
||||
default=False,
|
||||
action="store_true")
|
||||
subparsers = parser.add_subparsers(dest='subcmd',
|
||||
metavar='<subcommand> [-h] <args>')
|
||||
|
||||
# customer
|
||||
parser_create_customer = subparsers.add_parser('create_customer',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <data file '
|
||||
'with new customer '
|
||||
'JSON>')
|
||||
parser_create_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_create_customer.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help='<data file with new customer '
|
||||
'JSON>')
|
||||
|
||||
parser_delete_customer = subparsers.add_parser('delete_customer',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer '
|
||||
'id>')
|
||||
parser_delete_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_customer.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
|
||||
parser_update_customer = subparsers.add_parser('update_customer',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer '
|
||||
'id> <data file with '
|
||||
'updated customer '
|
||||
'JSON>')
|
||||
parser_update_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_update_customer.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_update_customer.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help='<data file with updated '
|
||||
'customer JSON>')
|
||||
|
||||
# region
|
||||
parser_add_region = subparsers.add_parser('add_region',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer id> '
|
||||
'<data file with region('
|
||||
's) JSON>')
|
||||
parser_add_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_region.add_argument('custid', type=str, help='<customer id>')
|
||||
parser_add_region.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help='<data file with region(s) JSON>')
|
||||
|
||||
parser_replace_region = subparsers.add_parser('replace_region',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer '
|
||||
'id> <data file with '
|
||||
'region(s) JSON>')
|
||||
parser_replace_region.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_region.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_replace_region.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help='<data file with region(s) JSON>')
|
||||
|
||||
parser_delete_region = subparsers.add_parser('delete_region',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer id> '
|
||||
'<region id>')
|
||||
parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_region.add_argument('custid', type=str, help='<customer id>')
|
||||
parser_delete_region.add_argument('regionid', type=str, help='<region id>')
|
||||
|
||||
# add user
|
||||
parser_add_user = subparsers.add_parser('add_user',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer id> '
|
||||
'<region id> <data file '
|
||||
'with user(s) JSON>')
|
||||
parser_add_user.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_user.add_argument('custid', type=str, help='<customer id>')
|
||||
parser_add_user.add_argument('regionid', type=str, help='<region id>')
|
||||
parser_add_user.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help='<data file with user(s) JSON>')
|
||||
|
||||
# replace user
|
||||
parser_replace_user = subparsers.add_parser('replace_user',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer id> '
|
||||
'<region id> <data file '
|
||||
'with user(s) JSON>')
|
||||
parser_replace_user.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_user.add_argument('custid', type=str, help='<customer id>')
|
||||
parser_replace_user.add_argument('regionid', type=str, help='<region id>')
|
||||
parser_replace_user.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help='<data file with user(s) JSON>')
|
||||
|
||||
# delete user
|
||||
parser_delete_user = subparsers.add_parser(
|
||||
'delete_user',
|
||||
help='[<"X-AIC-ORM-Client" header>] '
|
||||
'<customer id> <region id> <user id>')
|
||||
parser_delete_user.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_user.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_delete_user.add_argument('regionid', type=str,
|
||||
help='<region id>')
|
||||
parser_delete_user.add_argument('userid', type=str,
|
||||
help='<user id>')
|
||||
|
||||
# add default user
|
||||
parser_add_default_user = \
|
||||
subparsers.add_parser('add_default_user',
|
||||
help='[<"X-AIC-ORM-Client" header>] '
|
||||
'<customer id> '
|
||||
'<data file with '
|
||||
'region(s) JSON>')
|
||||
parser_add_default_user.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_default_user.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_add_default_user.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help='<data file with user(s) JSON>')
|
||||
|
||||
# replace default user
|
||||
parser_replace_default_user = \
|
||||
subparsers.add_parser('replace_default_user',
|
||||
help='[<"X-AIC-ORM-Client" header>] '
|
||||
'<customer id> '
|
||||
'<data file '
|
||||
'with region(s) '
|
||||
'JSON>')
|
||||
parser_replace_default_user.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_default_user.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_replace_default_user.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help='<data file with user(s) '
|
||||
'JSON>')
|
||||
|
||||
# change enable
|
||||
parser_enable_customer = subparsers.add_parser('enabled',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] '
|
||||
'<customer id> '
|
||||
'<data file with '
|
||||
'true/false JSON>')
|
||||
parser_enable_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_enable_customer.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_enable_customer.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help='<data file with true/false '
|
||||
'JSON>')
|
||||
|
||||
# delete default user
|
||||
parser_delete_default_user = \
|
||||
subparsers.add_parser('delete_default_user',
|
||||
help='[<"X-AIC-ORM-Client" header>] <customer '
|
||||
'id> <user id>')
|
||||
parser_delete_default_user.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_default_user.add_argument('custid', type=str,
|
||||
help='<customer id>')
|
||||
parser_delete_default_user.add_argument('userid', type=str,
|
||||
help='<user id>')
|
||||
|
||||
# add metadata
|
||||
h1, h2, h3 = \
|
||||
'[<"X-AIC-ORM-Client" header>]', '<customer id>', '<data file ' \
|
||||
'with ' \
|
||||
'metadata(' \
|
||||
's) JSON>'
|
||||
parser_add_metadata = subparsers.add_parser('add_metadata',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_add_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_metadata.add_argument('custid', type=str,
|
||||
help=h2)
|
||||
parser_add_metadata.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
# replace metadata
|
||||
h1, h2, h3 = \
|
||||
'[<"X-AIC-ORM-Client" header>]', '<customer id>', '<data file ' \
|
||||
'with ' \
|
||||
'metadata(' \
|
||||
's) JSON>'
|
||||
parser_replace_metadata = subparsers.add_parser('replace_metadata',
|
||||
help='%s %s %s' % (
|
||||
h1, h2, h3))
|
||||
parser_replace_metadata.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_metadata.add_argument('custid', type=str,
|
||||
help=h2)
|
||||
parser_replace_metadata.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
# get customer
|
||||
parser_get_customer = subparsers.add_parser('get_customer',
|
||||
help='[<"X-AIC-ORM-Client" '
|
||||
'header>] <customer id>')
|
||||
parser_get_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_get_customer.add_argument('custid', type=str, help='<customer id>')
|
||||
|
||||
# list customers
|
||||
h1 = '[<"X-AIC-ORM-Client" header>]'
|
||||
h2 = '[--region <name>] [--user <name>] [--metadata <key:value>]' \
|
||||
' [starts_with <name>] [contains <name>]'
|
||||
parser_list_customer = subparsers.add_parser('list_customers',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_list_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_list_customer.add_argument('--region', type=str, help='region name')
|
||||
parser_list_customer.add_argument('--user', type=str, help='user name')
|
||||
parser_list_customer.add_argument('--starts_with', type=str,
|
||||
help='customer name')
|
||||
parser_list_customer.add_argument('--contains', type=str,
|
||||
help='* contains in customer name')
|
||||
parser_list_customer.add_argument('--metadata', action='append', nargs="+",
|
||||
type=str, help='<key:value>')
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def preparm(p):
|
||||
return ('' if len(p) else '?') + ('&' if len(p) else '')
|
||||
|
||||
|
||||
def cmd_details(args):
|
||||
if args.subcmd == 'create_customer':
|
||||
return requests.post, ''
|
||||
elif args.subcmd == 'delete_customer':
|
||||
return requests.delete, '/%s' % args.custid
|
||||
elif args.subcmd == 'update_customer':
|
||||
return requests.put, '/%s' % args.custid
|
||||
elif args.subcmd == 'add_region':
|
||||
return requests.post, '/%s/regions' % args.custid
|
||||
elif args.subcmd == 'replace_region':
|
||||
return requests.put, '/%s/regions' % args.custid
|
||||
elif args.subcmd == 'delete_region':
|
||||
return requests.delete, '/%s/regions/%s' % (args.custid, args.regionid)
|
||||
elif args.subcmd == 'add_user':
|
||||
return requests.post, '/%s/regions/%s/users' % (
|
||||
args.custid, args.regionid)
|
||||
elif args.subcmd == 'replace_user':
|
||||
return requests.put, '/%s/regions/%s/users' % (
|
||||
args.custid, args.regionid)
|
||||
elif args.subcmd == 'delete_user':
|
||||
return requests.delete, '/%s/regions/%s/users/%s' % (
|
||||
args.custid, args.regionid, args.userid)
|
||||
elif args.subcmd == 'add_default_user':
|
||||
return requests.post, '/%s/users' % args.custid
|
||||
elif args.subcmd == 'replace_default_user':
|
||||
return requests.put, '/%s/users' % args.custid
|
||||
elif args.subcmd == 'delete_default_user':
|
||||
return requests.delete, '/%s/users/%s' % (args.custid, args.userid)
|
||||
elif args.subcmd == 'add_metadata':
|
||||
return requests.post, '/%s/metadata' % args.custid
|
||||
elif args.subcmd == 'replace_metadata':
|
||||
return requests.put, '/%s/metadata' % args.custid
|
||||
elif args.subcmd == 'get_customer':
|
||||
return requests.get, '/%s' % args.custid
|
||||
elif args.subcmd == 'enabled':
|
||||
return requests.put, '/%s/enabled' % args.custid
|
||||
elif args.subcmd == 'list_customers':
|
||||
param = ''
|
||||
if args.region:
|
||||
param += '%sregion=%s' % (preparm(param), args.region)
|
||||
if args.user:
|
||||
param += '%suser=%s' % (preparm(param), args.user)
|
||||
if args.starts_with:
|
||||
param += '%sstarts_with=%s' % (preparm(param), args.starts_with)
|
||||
if args.contains:
|
||||
param += '%scontains=%s' % (preparm(param), args.contains)
|
||||
if args.metadata:
|
||||
for meta in args.metadata:
|
||||
param += '%smetadata=%s' % (preparm(param), meta[0])
|
||||
return requests.get, '/%s' % param
|
||||
|
||||
|
||||
def get_token(timeout, args, host):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
url = '%s/v2.0/tokens'
|
||||
data = '''
|
||||
{
|
||||
"auth": {
|
||||
"tenantName": "%s",
|
||||
"passwordCredentials": {
|
||||
"username": "%s",
|
||||
"password": "%s"
|
||||
}
|
||||
}
|
||||
}'''
|
||||
for argument in ('tenant_name', 'username', 'password', 'auth_region'):
|
||||
argument_value = getattr(args, argument, None)
|
||||
if argument_value is not None:
|
||||
globals()[argument] = argument_value
|
||||
else:
|
||||
configuration_value = getattr(config, argument)
|
||||
if configuration_value:
|
||||
globals()[argument] = configuration_value
|
||||
else:
|
||||
message = ('ERROR: {} for token generation was not supplied. '
|
||||
'Please use its command-line '
|
||||
'argument or environment variable.'.format(argument))
|
||||
print message
|
||||
raise cli_common.MissingArgumentError(message)
|
||||
|
||||
keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host),
|
||||
auth_region)
|
||||
if keystone_ep is None:
|
||||
raise ConnectionError(
|
||||
'Failed in get_token, host: {}, region: {}'.format(host,
|
||||
auth_region))
|
||||
url = url % (keystone_ep,)
|
||||
data = data % (tenant_name, username, password,)
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Getting token:\ntimeout: %d\nheaders: %s\nurl: %s\n" % (
|
||||
timeout, headers, url))
|
||||
try:
|
||||
resp = requests.post(url, timeout=timeout, data=data, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
raise ResponseError(
|
||||
'Failed to get token (Reason: {})'.format(
|
||||
resp.status_code))
|
||||
return resp.json()['access']['token']['id']
|
||||
|
||||
except Exception as e:
|
||||
print e.message
|
||||
raise ConnectionError(e.message)
|
||||
|
||||
|
||||
def get_environment_variable(argument):
|
||||
# The rules are: all caps, underscores instead of dashes and prefixed
|
||||
environment_variable = 'AIC_ORM_{}'.format(
|
||||
argument.replace('-', '_').upper())
|
||||
|
||||
return os.environ.get(environment_variable)
|
||||
|
||||
|
||||
def run(args):
|
||||
host = args.orm_base_url if args.orm_base_url else config.orm_base_url
|
||||
port = args.port if args.port else 7080
|
||||
data = args.datafile.read() if 'datafile' in args else '{}'
|
||||
timeout = args.timeout if args.timeout else 10
|
||||
|
||||
rest_cmd, cmd_url = cmd_details(args)
|
||||
url = '%s:%d/v1/orm/customers' % (host, port,) + cmd_url
|
||||
if args.faceless:
|
||||
auth_token = auth_region = requester = client = ''
|
||||
else:
|
||||
try:
|
||||
auth_token = get_token(timeout, args, host)
|
||||
except Exception:
|
||||
exit(1)
|
||||
auth_region = globals()['auth_region']
|
||||
requester = globals()['username']
|
||||
client = requester
|
||||
|
||||
tracking_id = args.tracking_id if args.tracking_id else None
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'X-Auth-Token': auth_token,
|
||||
'X-Auth-Region': auth_region,
|
||||
'X-AIC-ORM-Requester': requester,
|
||||
'X-AIC-ORM-Client': client,
|
||||
'X-AIC-ORM-Tracking-Id': tracking_id
|
||||
}
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Sending API:\ntimeout: %d\ndata: %s\nheaders: %s\ncmd: %s\nurl: "
|
||||
"%s\n" % (
|
||||
timeout, data, headers, rest_cmd.__name__, url))
|
||||
|
||||
try:
|
||||
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
|
||||
verify=config.verify)
|
||||
except Exception as e:
|
||||
print e
|
||||
exit(1)
|
||||
|
||||
if not 200 <= resp.status_code < 300:
|
||||
content = resp.json() if resp.status_code == 500 else ''
|
||||
print 'API error: %s %s (Reason: %d)\n%s' % (
|
||||
rest_cmd.func_name.upper(), url, resp.status_code, content)
|
||||
exit(1)
|
||||
|
||||
if resp.status_code == 204: # no content
|
||||
exit(0)
|
||||
|
||||
rj = resp.json()
|
||||
if rj == 'Not found':
|
||||
print 'No output was found'
|
||||
else:
|
||||
cli_common.pretty_print_json(rj)
|
8
orm/orm_client/ormcli/config.py
Normal file
8
orm/orm_client/ormcli/config.py
Normal file
@ -0,0 +1,8 @@
|
||||
# these values are used by ormcli to retrieve auth_token which is sent,
|
||||
# along with region, with each cms and fms api request
|
||||
tenant_name = ''
|
||||
username = ''
|
||||
password = False
|
||||
auth_region = ''
|
||||
orm_base_url = 'http://127.0.0.1'
|
||||
verify = False
|
395
orm/orm_client/ormcli/fmscli.py
Normal file
395
orm/orm_client/ormcli/fmscli.py
Normal file
@ -0,0 +1,395 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import cli_common
|
||||
import config
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
class ResponseError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def add_to_parser(service_sub):
|
||||
parser = \
|
||||
service_sub.add_parser('fms', help='Flavor Management Service',
|
||||
formatter_class=lambda prog:
|
||||
argparse.HelpFormatter(prog,
|
||||
max_help_position=30,
|
||||
width=120))
|
||||
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
|
||||
parser.add_argument('--auth-region', type=str,
|
||||
help='Region used for authentication',
|
||||
default=get_environment_variable('auth-region'))
|
||||
parser.add_argument('--orm-base-url', type=str, help='ORM base URL',
|
||||
default=get_environment_variable('orm-base-url'))
|
||||
parser.add_argument('--tracking_id', type=str, help='tracking id')
|
||||
parser.add_argument('--tenant-name', type=str,
|
||||
help='Keystone user tenant name',
|
||||
default=get_environment_variable('tenant-name'))
|
||||
parser.add_argument('--username', type=str, help='Keystone user name',
|
||||
default=get_environment_variable('username'))
|
||||
parser.add_argument('--password', type=str, help='Keystone user password',
|
||||
default=get_environment_variable('password'))
|
||||
parser.add_argument('--port', type=int, help='port number of FMS server')
|
||||
parser.add_argument('--timeout', type=int,
|
||||
help='request timeout in seconds (default: 10)')
|
||||
parser.add_argument('-v', '--verbose', help='show details',
|
||||
action="store_true")
|
||||
parser.add_argument('-f', '--faceless',
|
||||
help='run without authentication',
|
||||
default=False,
|
||||
action="store_true")
|
||||
subparsers = parser.add_subparsers(dest='subcmd',
|
||||
metavar='<subcommand> [-h] <args>')
|
||||
|
||||
# flavor
|
||||
h1, h2 = ('[<"X-AIC-ORM-Client" header>]',
|
||||
'<data file with new flavor JSON>')
|
||||
parser_create_flavor = subparsers.add_parser('create_flavor',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_create_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_create_flavor.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<data file with tag(s) JSON>',)
|
||||
parser_add_tags = subparsers.add_parser('add_tags',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_add_tags.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_tags.add_argument('flavorid', type=str, help=h2)
|
||||
parser_add_tags.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<data file with tag(s) JSON>',)
|
||||
parser_replace_tags = subparsers.add_parser('replace_tags',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_replace_tags.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_tags.add_argument('flavorid', type=str, help=h2)
|
||||
parser_replace_tags.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>', '<tag name>'
|
||||
parser_delete_tag = subparsers.add_parser('delete_tag',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_delete_tag.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_tag.add_argument('flavorid', type=str, help=h2)
|
||||
parser_delete_tag.add_argument('tagname', type=str, help=h3)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>'
|
||||
parser_delete_all_tags = subparsers.add_parser('delete_all_tags',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_delete_all_tags.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_all_tags.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>'
|
||||
parser_get_tags = subparsers.add_parser('get_tags',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_get_tags.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_get_tags.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
# extra specs
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>'
|
||||
parser_get_extra_specs = subparsers.add_parser('get_extra_specs',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_get_extra_specs.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_get_extra_specs.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<datafile with extra_specs json>',)
|
||||
parser_replace_extra_specs = subparsers.add_parser('replace_extra_specs',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_replace_extra_specs.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_replace_extra_specs.add_argument('flavorid', type=str, help=h2)
|
||||
parser_replace_extra_specs.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>'
|
||||
parser_delete_all_extra_specs = subparsers.add_parser(
|
||||
'delete_all_extra_specs', help='%s %s' % (h1, h2))
|
||||
parser_delete_all_extra_specs.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_all_extra_specs.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<extra_spec key name>',)
|
||||
parser_delete_extra_spec = subparsers.add_parser('delete_extra_spec',
|
||||
help='%s%s%s' % (
|
||||
h1, h2, h3))
|
||||
parser_delete_extra_spec.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_extra_spec.add_argument('flavorid', type=str, help=h2)
|
||||
parser_delete_extra_spec.add_argument('eskeyname', type=str, help=h3)
|
||||
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<datafile with extra_specs json>',)
|
||||
parser_add_extra_specs = subparsers.add_parser('add_extra_specs',
|
||||
help='%s%s%s' % (
|
||||
h1, h2, h3))
|
||||
parser_add_extra_specs.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_extra_specs.add_argument('flavorid', type=str, help=h2)
|
||||
parser_add_extra_specs.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>'
|
||||
parser_delete_flavor = subparsers.add_parser('delete_flavor',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_delete_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_flavor.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<flavor id or flavor_name>'
|
||||
parser_get_flavor = subparsers.add_parser('get_flavor',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_get_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_get_flavor.add_argument('flavorid', type=str, help=h2)
|
||||
|
||||
h1, h2 = ('[<"X-AIC-ORM-Client" header>]',
|
||||
'[--visibility <public|private>] [--region <name>] [--tenant '
|
||||
'<id>] [--series {gv,nv,ns,nd,ss}] [--alias <alias>]')
|
||||
parser_list_flavor = subparsers.add_parser('list_flavors',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_list_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_list_flavor.add_argument('--visibility', type=str,
|
||||
choices=['public', 'private'])
|
||||
parser_list_flavor.add_argument('--region', type=str, help='region name')
|
||||
parser_list_flavor.add_argument('--tenant', type=str, help='tenant id')
|
||||
parser_list_flavor.add_argument('--starts_with', type=str,
|
||||
help='flavor name starts with *')
|
||||
parser_list_flavor.add_argument('--contains', type=str,
|
||||
help='* contains in flavor name')
|
||||
parser_list_flavor.add_argument('--series', type=str,
|
||||
choices=['gv', 'nv', 'ns', 'nd', 'ss'])
|
||||
parser_list_flavor.add_argument('--alias', type=str, help='flavor alias')
|
||||
|
||||
# region for flavor
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<data file with region(s) JSON>',)
|
||||
parser_add_region = subparsers.add_parser('add_region',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_add_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_region.add_argument('flavorid', type=str, help=h2)
|
||||
parser_add_region.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>', '<region id>'
|
||||
parser_delete_region = subparsers.add_parser('delete_region',
|
||||
help='%s %s %s' % (
|
||||
h1, h2, h3))
|
||||
parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_region.add_argument('flavorid', type=str, help=h2)
|
||||
parser_delete_region.add_argument('regionid', type=str, help=h3)
|
||||
|
||||
# tenant for flavor
|
||||
h1, h2, h3 = ('[<"X-AIC-ORM-Client" header>]', '<flavor id>',
|
||||
'<data file with tenant(s) JSON>',)
|
||||
parser_add_tenant = subparsers.add_parser('add_tenant',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_add_tenant.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_tenant.add_argument('flavorid', type=str, help=h2)
|
||||
parser_add_tenant.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<flavor id>', '<tenant id>'
|
||||
parser_delete_tenant = subparsers.add_parser('delete_tenant',
|
||||
help='%s %s %s' % (
|
||||
h1, h2, h3))
|
||||
parser_delete_tenant.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_tenant.add_argument('flavorid', type=str, help=h2)
|
||||
parser_delete_tenant.add_argument('tenantid', type=str, help=h3)
|
||||
|
||||
|
||||
def preparm(p):
|
||||
return ('' if len(p) else '?') + ('&' if len(p) else '')
|
||||
|
||||
|
||||
def cmd_details(args):
|
||||
if args.subcmd == 'create_flavor':
|
||||
return requests.post, ''
|
||||
elif args.subcmd == 'update_flavor':
|
||||
return requests.put, '/%s' % args.flavorid
|
||||
elif args.subcmd == 'delete_flavor':
|
||||
return requests.delete, '/%s' % args.flavorid
|
||||
elif args.subcmd == 'add_region':
|
||||
return requests.post, '/%s/regions' % args.flavorid
|
||||
elif args.subcmd == 'add_tags':
|
||||
return requests.post, '/%s/tags' % args.flavorid
|
||||
elif args.subcmd == 'replace_tags':
|
||||
return requests.put, '/%s/tags' % args.flavorid
|
||||
elif args.subcmd == 'delete_tag':
|
||||
return requests.delete, '/%s/tags/%s' % (args.flavorid, args.tagname)
|
||||
elif args.subcmd == 'delete_all_tags':
|
||||
return requests.delete, '/%s/tags' % args.flavorid
|
||||
elif args.subcmd == 'get_tags':
|
||||
return requests.get, '/%s/tags' % args.flavorid
|
||||
elif args.subcmd == 'delete_region':
|
||||
return requests.delete, '/%s/regions/%s' % (
|
||||
args.flavorid, args.regionid)
|
||||
elif args.subcmd == 'add_tenant':
|
||||
return requests.post, '/%s/tenants' % args.flavorid
|
||||
elif args.subcmd == 'delete_tenant':
|
||||
return requests.delete, '/%s/tenants/%s' % (
|
||||
args.flavorid, args.tenantid)
|
||||
elif args.subcmd == 'get_flavor':
|
||||
return requests.get, '/%s' % args.flavorid
|
||||
elif args.subcmd == 'get_extra_specs':
|
||||
return requests.get, '/%s/os_extra_specs' % args.flavorid
|
||||
elif args.subcmd == 'delete_all_extra_specs':
|
||||
return requests.delete, '/%s/os_extra_specs' % args.flavorid
|
||||
elif args.subcmd == 'delete_extra_spec':
|
||||
return requests.delete, '/%s/os_extra_specs/%s' % (
|
||||
args.flavorid, args.eskeyname)
|
||||
elif args.subcmd == 'add_extra_specs':
|
||||
return requests.post, '/%s/os_extra_specs' % args.flavorid
|
||||
elif args.subcmd == 'replace_extra_specs':
|
||||
return requests.put, '/%s/os_extra_specs' % args.flavorid
|
||||
elif args.subcmd == 'list_flavors':
|
||||
param = ''
|
||||
if args.visibility:
|
||||
param += '%svisibility=%s' % (preparm(param), args.visibility)
|
||||
if args.region:
|
||||
param += '%sregion=%s' % (preparm(param), args.region)
|
||||
if args.tenant:
|
||||
param += '%stenant=%s' % (preparm(param), args.tenant)
|
||||
if args.series:
|
||||
param += '%sseries=%s' % (preparm(param), args.series)
|
||||
if args.starts_with:
|
||||
param += '%sstarts_with=%s' % (preparm(param), args.starts_with)
|
||||
if args.contains:
|
||||
param += '%scontains=%s' % (preparm(param), args.contains)
|
||||
if args.alias:
|
||||
param += '%salias=%s' % (preparm(param), args.alias)
|
||||
return requests.get, '/%s' % param
|
||||
|
||||
|
||||
def get_token(timeout, args, host):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
url = '%s/v2.0/tokens'
|
||||
data = '''
|
||||
{
|
||||
"auth": {
|
||||
"tenantName": "%s",
|
||||
"passwordCredentials": {
|
||||
"username": "%s",
|
||||
"password": "%s"
|
||||
}
|
||||
}
|
||||
}'''
|
||||
for argument in ('tenant_name', 'username', 'password', 'auth_region'):
|
||||
argument_value = getattr(args, argument, None)
|
||||
if argument_value is not None:
|
||||
globals()[argument] = argument_value
|
||||
else:
|
||||
configuration_value = getattr(config, argument)
|
||||
if configuration_value:
|
||||
globals()[argument] = configuration_value
|
||||
else:
|
||||
message = ('ERROR: {} for token generation was not supplied. '
|
||||
'Please use its command-line '
|
||||
'argument or environment variable.'.format(argument))
|
||||
print message
|
||||
raise cli_common.MissingArgumentError(message)
|
||||
|
||||
keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host),
|
||||
auth_region)
|
||||
if keystone_ep is None:
|
||||
raise ConnectionError(
|
||||
'Failed in get_token, host: {}, region: {}'.format(host,
|
||||
auth_region))
|
||||
url = url % (keystone_ep,)
|
||||
data = data % (tenant_name, username, password,)
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Getting token:\ntimeout: %d\nheaders: %s\nurl: %s\n" % (
|
||||
timeout, headers, url))
|
||||
try:
|
||||
resp = requests.post(url, timeout=timeout, data=data, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
raise ResponseError(
|
||||
'Failed to get token (Reason: {})'.format(
|
||||
resp.status_code))
|
||||
return resp.json()['access']['token']['id']
|
||||
|
||||
except Exception as e:
|
||||
print e.message
|
||||
raise ConnectionError(e.message)
|
||||
|
||||
|
||||
def get_environment_variable(argument):
|
||||
# The rules are: all caps, underscores instead of dashes and prefixed
|
||||
environment_variable = 'AIC_ORM_{}'.format(
|
||||
argument.replace('-', '_').upper())
|
||||
|
||||
return os.environ.get(environment_variable)
|
||||
|
||||
|
||||
def run(args):
|
||||
host = args.orm_base_url if args.orm_base_url else config.orm_base_url
|
||||
port = args.port if args.port else 8082
|
||||
data = args.datafile.read() if 'datafile' in args else '{}'
|
||||
timeout = args.timeout if args.timeout else 10
|
||||
|
||||
rest_cmd, cmd_url = cmd_details(args)
|
||||
url = '%s:%d/v1/orm/flavors' % (host, port,) + cmd_url
|
||||
if args.faceless:
|
||||
auth_token = auth_region = requester = client = ''
|
||||
else:
|
||||
try:
|
||||
auth_token = get_token(timeout, args, host)
|
||||
except Exception:
|
||||
exit(1)
|
||||
auth_region = globals()['auth_region']
|
||||
requester = globals()['username']
|
||||
client = requester
|
||||
|
||||
tracking_id = args.tracking_id if args.tracking_id else None
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'X-Auth-Token': auth_token,
|
||||
'X-Auth-Region': auth_region,
|
||||
'X-AIC-ORM-Requester': requester,
|
||||
'X-AIC-ORM-Client': client,
|
||||
'X-AIC-ORM-Tracking-Id': tracking_id
|
||||
}
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Sending API:\ntimeout: %d\ndata: %s\nheaders: %s\ncmd: %s\nurl:"
|
||||
" %s\n" % (
|
||||
timeout, data, headers, rest_cmd.__name__, url))
|
||||
try:
|
||||
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
|
||||
verify=config.verify)
|
||||
except Exception as e:
|
||||
print e
|
||||
exit(1)
|
||||
|
||||
if not 200 <= resp.status_code < 300:
|
||||
content = resp.content
|
||||
print 'API error: %s %s (Reason: %d)\n%s' % (
|
||||
rest_cmd.func_name.upper(), url, resp.status_code, content)
|
||||
exit(1)
|
||||
|
||||
if resp.status_code == 204: # no content
|
||||
exit(0)
|
||||
|
||||
rj = resp.json()
|
||||
if rj == 'Not found':
|
||||
print 'No output was found'
|
||||
else:
|
||||
cli_common.pretty_print_json(rj)
|
366
orm/orm_client/ormcli/imscli.py
Normal file
366
orm/orm_client/ormcli/imscli.py
Normal file
@ -0,0 +1,366 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import cli_common
|
||||
import config
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
class ResponseError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def add_to_parser(service_sub):
|
||||
parser = service_sub.add_parser('ims',
|
||||
help='Image Management Service',
|
||||
formatter_class=lambda prog: argparse.
|
||||
HelpFormatter(prog,
|
||||
max_help_position=30,
|
||||
width=120))
|
||||
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
|
||||
parser.add_argument('--auth-region', type=str,
|
||||
help='Region used for authentication',
|
||||
default=get_environment_variable('auth-region'))
|
||||
parser.add_argument('--tenant-name', type=str,
|
||||
help='Keystone user tenant name',
|
||||
default=get_environment_variable('tenant-name'))
|
||||
parser.add_argument('--username', type=str, help='Keystone user name',
|
||||
default=get_environment_variable('username'))
|
||||
parser.add_argument('--password', type=str, help='Keystone user password',
|
||||
default=get_environment_variable('password'))
|
||||
parser.add_argument('--orm-base-url', type=str, help='ORM base URL',
|
||||
default=get_environment_variable('orm-base-url'))
|
||||
parser.add_argument('--tracking_id', type=str, help='tracking id')
|
||||
parser.add_argument('--port', type=int, help='port number of IMS server')
|
||||
parser.add_argument('--timeout', type=int,
|
||||
help='request timeout in seconds (default: 10)')
|
||||
parser.add_argument('-v', '--verbose', help='show details',
|
||||
action="store_true")
|
||||
parser.add_argument('-f', '--faceless',
|
||||
help='run without authentication',
|
||||
default=False,
|
||||
action="store_true")
|
||||
subparsers = parser.add_subparsers(dest='subcmd',
|
||||
metavar='<subcommand> [-h] <args>')
|
||||
|
||||
# image
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<data file with new image JSON>'
|
||||
parser_create_image = subparsers.add_parser('create_image',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_create_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_create_image.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<data file with updated image JSON>'
|
||||
parser_update_image = subparsers.add_parser('update_image',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_update_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_update_image.add_argument('imageid', type=str, help=h2)
|
||||
parser_update_image.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<image id>'
|
||||
parser_delete_image = subparsers.add_parser('delete_image',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_delete_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_image.add_argument('imageid', type=str, help=h2)
|
||||
|
||||
# get images
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<image id>'
|
||||
parser_get_image = subparsers.add_parser('get_image',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_get_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_get_image.add_argument('imageid', type=str, help=h2)
|
||||
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', \
|
||||
'[--visibility <public|private>] ' \
|
||||
'[--region <name>] [--customer <id>]'
|
||||
parser_list_images = subparsers.add_parser('list_images',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_list_images.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_list_images.add_argument('--visibility', type=str,
|
||||
choices=['public', 'private'])
|
||||
parser_list_images.add_argument('--region', type=str, help='region name')
|
||||
parser_list_images.add_argument('--customer', type=str, help='customer id')
|
||||
|
||||
# activate/deactivate image
|
||||
h1, h2 = '[<"X-AIC-ORM-Client" header>]', '<image id>'
|
||||
parser_enable = subparsers.add_parser('enable',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_enable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_enable.add_argument('imageid', type=str, help=h2)
|
||||
|
||||
parser_disable = subparsers.add_parser('disable',
|
||||
help='%s %s' % (h1, h2))
|
||||
|
||||
parser_disable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_disable.add_argument('imageid', type=str, help=h2)
|
||||
|
||||
# region for image
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<data file with region(s) JSON>'
|
||||
parser_add_regions = subparsers.add_parser('add_regions',
|
||||
help='%s %s %s' % (h1, h2, h3))
|
||||
parser_add_regions.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_regions.add_argument('imageid', type=str, help=h2)
|
||||
parser_add_regions.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<data file with region(s) JSON>'
|
||||
parser_update_regions = subparsers.add_parser('update_regions',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_update_regions.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_update_regions.add_argument('imageid', type=str, help=h2)
|
||||
parser_update_regions.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', '<region id>'
|
||||
parser_delete_region = subparsers.add_parser('delete_region',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_region.add_argument('imageid', type=str, help=h2)
|
||||
parser_delete_region.add_argument('regionid', type=str, help=h3)
|
||||
|
||||
# customer for image
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<data file with customer(s) JSON>'
|
||||
parser_add_customers = subparsers.add_parser('add_customers',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_add_customers.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_add_customers.add_argument('imageid', type=str, help=h2)
|
||||
parser_add_customers.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<data file with customer(s) JSON>'
|
||||
parser_update_customer = subparsers.add_parser('update_customers',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_update_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_update_customer.add_argument('imageid', type=str, help=h2)
|
||||
parser_update_customer.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h3)
|
||||
|
||||
h1, h2, h3 = '[<"X-AIC-ORM-Client" header>]', '<image id>', \
|
||||
'<customer id>'
|
||||
parser_delete_customer = subparsers.add_parser('delete_customer',
|
||||
help='%s %s %s' % (h1,
|
||||
h2,
|
||||
h3))
|
||||
parser_delete_customer.add_argument('client',
|
||||
**cli_common.ORM_CLIENT_KWARGS)
|
||||
parser_delete_customer.add_argument('imageid', type=str, help=h2)
|
||||
parser_delete_customer.add_argument('customerid', type=str, help=h3)
|
||||
|
||||
|
||||
def get_token(timeout, args, host):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
url = '%s/v2.0/tokens'
|
||||
data = '''
|
||||
{
|
||||
"auth": {
|
||||
"tenantName": "%s",
|
||||
"passwordCredentials": {
|
||||
"username": "%s",
|
||||
"password": "%s"
|
||||
}
|
||||
}
|
||||
}'''
|
||||
for argument in ('tenant_name', 'username', 'password', 'auth_region'):
|
||||
argument_value = getattr(args, argument, None)
|
||||
if argument_value is not None:
|
||||
globals()[argument] = argument_value
|
||||
else:
|
||||
configuration_value = getattr(config, argument)
|
||||
if configuration_value:
|
||||
globals()[argument] = configuration_value
|
||||
else:
|
||||
message = ('ERROR: {} for token generation was not supplied. '
|
||||
'Please use its command-line '
|
||||
'argument or environment variable.'.format(argument))
|
||||
print message
|
||||
raise cli_common.MissingArgumentError(message)
|
||||
|
||||
keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host),
|
||||
auth_region)
|
||||
if keystone_ep is None:
|
||||
raise ConnectionError(
|
||||
'Failed in get_token, host: {}, region: {}'.format(host,
|
||||
auth_region))
|
||||
url = url % (keystone_ep,)
|
||||
data = data % (tenant_name, username, password,)
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Getting token:\ntimeout: %d\nheaders: %s\nurl: %s\n" % (
|
||||
timeout, headers, url))
|
||||
try:
|
||||
resp = requests.post(url, timeout=timeout, data=data, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
raise ResponseError(
|
||||
'Failed to get token (Reason: {})'.format(
|
||||
resp.status_code))
|
||||
return resp.json()['access']['token']['id']
|
||||
|
||||
except Exception as e:
|
||||
print e.message
|
||||
raise ConnectionError(e.message)
|
||||
|
||||
|
||||
def preparm(p):
|
||||
return ('' if len(p) else '?') + ('&' if len(p) else '')
|
||||
|
||||
|
||||
def cmd_details(args):
|
||||
data = args.datafile.read() if 'datafile' in args else '{}'
|
||||
if args.subcmd == 'create_image':
|
||||
cmd, url = requests.post, ''
|
||||
elif args.subcmd == 'update_image':
|
||||
cmd, url = requests.put, '/%s' % args.imageid
|
||||
elif args.subcmd == 'delete_image':
|
||||
cmd, url = requests.delete, '/%s' % args.imageid
|
||||
|
||||
# activate/deactivate image
|
||||
elif args.subcmd in ('enable', 'disable'):
|
||||
cmd, url = requests.put, '/%s/enabled' % args.imageid
|
||||
data = '{"enabled": %s}' % ('true' if args.subcmd == 'enable' else
|
||||
'false')
|
||||
# image regions
|
||||
elif args.subcmd == 'add_regions':
|
||||
cmd, url = requests.post, '/%s/regions' % args.imageid
|
||||
elif args.subcmd == 'update_regions':
|
||||
cmd, url = requests.put, '/%s/regions' % args.imageid
|
||||
elif args.subcmd == 'delete_region':
|
||||
cmd, url = requests.delete, '/%s/regions/%s' % (args.imageid,
|
||||
args.regionid)
|
||||
|
||||
# image customers
|
||||
elif args.subcmd == 'add_customers':
|
||||
cmd, url = requests.post, '/%s/customers' % args.imageid
|
||||
elif args.subcmd == 'update_customers':
|
||||
cmd, url = requests.put, '/%s/customers' % args.imageid
|
||||
elif args.subcmd == 'delete_customer':
|
||||
cmd, url = requests.delete, '/%s/customers/%s' % (args.imageid,
|
||||
args.customerid)
|
||||
|
||||
# list images
|
||||
elif args.subcmd == 'get_image':
|
||||
cmd, url = requests.get, '/%s' % args.imageid
|
||||
elif args.subcmd == 'list_images':
|
||||
param = ''
|
||||
if args.visibility:
|
||||
param += '%svisibility=%s' % (preparm(param),
|
||||
args.visibility)
|
||||
if args.region:
|
||||
param += '%sregion=%s' % (preparm(param),
|
||||
args.region)
|
||||
if args.customer:
|
||||
param += '%scustomer=%s' % (preparm(param),
|
||||
args.customer)
|
||||
cmd, url = requests.get, '/%s' % param
|
||||
|
||||
return cmd, url, data
|
||||
|
||||
|
||||
def cmd_data(args):
|
||||
# This is a special case where api has a payload needed but the CLI is
|
||||
# seperated into 2 different commands. In this case we need to set the
|
||||
# payload.
|
||||
if args.subcmd == 'enable':
|
||||
return "{\n \"enabled\": true\n}"
|
||||
elif args.subcmd == 'disable':
|
||||
return "{\n \"enabled\": false\n}"
|
||||
else:
|
||||
return args.datafile.read() if 'datafile' in args else '{}'
|
||||
|
||||
|
||||
def get_environment_variable(argument):
|
||||
# The rules are: all caps, underscores instead of dashes and prefixed
|
||||
environment_variable = 'AIC_ORM_{}'.format(
|
||||
argument.replace('-', '_').upper())
|
||||
|
||||
return os.environ.get(environment_variable)
|
||||
|
||||
|
||||
def run(args):
|
||||
host = args.orm_base_url if args.orm_base_url else config.orm_base_url
|
||||
port = args.port if args.port else 8084
|
||||
timeout = args.timeout if args.timeout else 10
|
||||
|
||||
rest_cmd, cmd_url, data = cmd_details(args)
|
||||
url = '%s:%d/v1/orm/images' % (host, port,) + cmd_url
|
||||
if args.faceless:
|
||||
auth_token = auth_region = requester = client = ''
|
||||
else:
|
||||
try:
|
||||
auth_token = get_token(timeout, args, host)
|
||||
except Exception:
|
||||
exit(1)
|
||||
auth_region = globals()['auth_region']
|
||||
requester = globals()['username']
|
||||
client = requester
|
||||
|
||||
tracking_id = args.tracking_id if args.tracking_id else None
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'X-Auth-Token': auth_token,
|
||||
'X-Auth-Region': auth_region,
|
||||
'X-AIC-ORM-Requester': requester,
|
||||
'X-AIC-ORM-Client': client,
|
||||
'X-AIC-ORM-Tracking-Id': tracking_id
|
||||
}
|
||||
|
||||
if args.verbose:
|
||||
print("Sending API:\ntimeout: %d\ndata: %s\n"
|
||||
"headers: %s\ncmd: %s\nurl: %s\n" % (timeout,
|
||||
data,
|
||||
headers,
|
||||
rest_cmd.__name__,
|
||||
url))
|
||||
try:
|
||||
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
|
||||
verify=config.verify)
|
||||
except Exception as e:
|
||||
print e
|
||||
exit(1)
|
||||
|
||||
if not 200 <= resp.status_code < 300:
|
||||
content = resp.content
|
||||
print 'API error: %s %s (Reason: %d)\n%s' % (
|
||||
rest_cmd.func_name.upper(),
|
||||
url,
|
||||
resp.status_code,
|
||||
content)
|
||||
exit(1)
|
||||
|
||||
if resp.status_code == 204: # no content
|
||||
exit(0)
|
||||
|
||||
rj = resp.json()
|
||||
if rj == 'Not found':
|
||||
print 'No output was found'
|
||||
else:
|
||||
cli_common.pretty_print_json(rj)
|
7
orm/orm_client/ormcli/orm
Normal file
7
orm/orm_client/ormcli/orm
Normal file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import ormcli
|
||||
|
||||
if __name__ == "__main__":
|
||||
ormcli.main(sys.argv)
|
37
orm/orm_client/ormcli/ormcli.py
Normal file
37
orm/orm_client/ormcli/ormcli.py
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import cmscli
|
||||
import fmscli
|
||||
import imscli
|
||||
import rmscli
|
||||
import sys
|
||||
|
||||
|
||||
class Cli:
|
||||
def create_parser(self):
|
||||
self.parser = argparse.ArgumentParser(prog='orm',
|
||||
description='ORM REST CLI')
|
||||
service_sub = self.parser.add_subparsers(dest='service',
|
||||
metavar='<service>')
|
||||
self.submod = {'cms': cmscli, 'fms': fmscli, 'ims': imscli,
|
||||
'rms': rmscli}
|
||||
for s in self.submod.values():
|
||||
s.add_to_parser(service_sub)
|
||||
|
||||
def parse(self, argv=sys.argv):
|
||||
sys.argv = argv
|
||||
self.args = self.parser.parse_args()
|
||||
|
||||
def logic(self):
|
||||
self.submod[self.args.service].run(self.args)
|
||||
|
||||
|
||||
def main(argv):
|
||||
cli = Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(argv)
|
||||
cli.logic()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
2
orm/orm_client/ormcli/requirements.txt
Normal file
2
orm/orm_client/ormcli/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
requests
|
||||
argparse
|
385
orm/orm_client/ormcli/rmscli.py
Normal file
385
orm/orm_client/ormcli/rmscli.py
Normal file
@ -0,0 +1,385 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import cli_common
|
||||
import config
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
class ResponseError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def add_to_parser(service_sub):
|
||||
parser = service_sub.add_parser('rms', help='Resource Management Service',
|
||||
formatter_class=lambda prog: argparse.
|
||||
HelpFormatter(prog,
|
||||
max_help_position=30,
|
||||
width=120))
|
||||
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
|
||||
parser.add_argument('--auth-region', type=str,
|
||||
help='Region used for authentication',
|
||||
default=get_environment_variable('auth-region'))
|
||||
parser.add_argument('--tenant-name', type=str,
|
||||
help='Keystone user tenant name',
|
||||
default=get_environment_variable('tenant-name'))
|
||||
parser.add_argument('--username', type=str, help='Keystone user name',
|
||||
default=get_environment_variable('username'))
|
||||
parser.add_argument('--password', type=str, help='Keystone user password',
|
||||
default=get_environment_variable('password'))
|
||||
parser.add_argument('--orm-base-url', type=str, help='ORM base URL',
|
||||
default=get_environment_variable('orm-base-url'))
|
||||
parser.add_argument('--tracking_id', type=str, help='tracking id')
|
||||
parser.add_argument('--port', type=int, help='port number of IMS server')
|
||||
parser.add_argument('--timeout', type=int,
|
||||
help='request timeout in seconds (default: 10)')
|
||||
parser.add_argument('-v', '--verbose', help='show details',
|
||||
action="store_true")
|
||||
parser.add_argument('-f', '--faceless',
|
||||
help='run without authentication',
|
||||
default=False,
|
||||
action="store_true")
|
||||
subparsers = parser.add_subparsers(dest='subcmd',
|
||||
metavar='<subcommand> [-h] <args>')
|
||||
|
||||
# get group
|
||||
h1 = '<group_id>'
|
||||
parser_get_group = subparsers.add_parser('get_group', help=h1)
|
||||
parser_get_group.add_argument('group_id', help=h1)
|
||||
|
||||
# get all groups
|
||||
parser_list_groups = subparsers.add_parser('list_groups', help="")
|
||||
|
||||
# create group
|
||||
h1 = '<group json file>'
|
||||
parser_create_group = subparsers.add_parser('create_group', help=h1)
|
||||
parser_create_group.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h1)
|
||||
|
||||
# update group
|
||||
h1, h2 = '<group json file>', '<group_id>'
|
||||
parser_update_group = subparsers.add_parser('update_group',
|
||||
help="%s %s" % (h2, h1))
|
||||
parser_update_group.add_argument('group_id', help=h2)
|
||||
parser_update_group.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h1)
|
||||
|
||||
# delete group
|
||||
h1 = '<group id>'
|
||||
parser_delete_group = subparsers.add_parser('delete_group',
|
||||
help='%s' % (h1))
|
||||
parser_delete_group.add_argument('group_id', type=str, help=h1)
|
||||
|
||||
# get region
|
||||
h1, h2 = '<region_name_or_id>', '[--use_version <api version>]'
|
||||
parser_get_region = subparsers.add_parser('get_region',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_get_region.add_argument('--use_version', type=int,
|
||||
help='<api version to use (1 or 2)>')
|
||||
parser_get_region.add_argument('region_name_or_id', type=str, help=h1)
|
||||
|
||||
# update region
|
||||
h1, h2 = '<region_id>', '<full region json file>'
|
||||
parser_update_region = subparsers.add_parser('update_region',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_update_region.add_argument('region_id', type=str, help=h1)
|
||||
parser_update_region.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
|
||||
# create region
|
||||
h1 = '<full region json file>'
|
||||
parser_create_region = subparsers.add_parser('create_region',
|
||||
help='%s' % (h1))
|
||||
parser_create_region.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
|
||||
# delete region
|
||||
h1 = '<region id>'
|
||||
parser_delete_region = subparsers.add_parser('delete_region',
|
||||
help='%s' % (h1))
|
||||
parser_delete_region.add_argument('region_id', type=str, help=h1)
|
||||
|
||||
# list regions
|
||||
parser_list_region = subparsers.add_parser('list_regions',
|
||||
help='\
|
||||
[--use_version <api version>] [--type <type>] [--status <status>]\
|
||||
[--metadata <metadata>] [--aicversion <aicversion>][--clli <clli>]\
|
||||
[--regionname <regionname>] [--osversion <osversion>] [--valet <valet>]\
|
||||
[--state <state>] [--country <country>] [--city <city>] [--street <street>]\
|
||||
[--zip <zip>] [--vlcp_name <vlcp_name>]')
|
||||
parser_list_region.add_argument('--use_version', type=int,
|
||||
help='<api version to use>')
|
||||
parser_list_region.add_argument('--type', type=str, help='<type>')
|
||||
parser_list_region.add_argument('--status', type=str, help='<status>')
|
||||
parser_list_region.add_argument('--metadata', action='append', nargs="+",
|
||||
type=str, help='<metadata>')
|
||||
parser_list_region.add_argument('--aicversion', type=str,
|
||||
help='<aicversion>')
|
||||
parser_list_region.add_argument('--clli', type=str, help='<clli>')
|
||||
parser_list_region.add_argument('--regionname', type=str,
|
||||
help='<regionname>')
|
||||
parser_list_region.add_argument('--osversion', type=str,
|
||||
help='<osversion>')
|
||||
parser_list_region.add_argument('--valet', type=str, help='<valet>')
|
||||
parser_list_region.add_argument('--state', type=str, help='<state>')
|
||||
parser_list_region.add_argument('--country', type=str, help='<country>')
|
||||
parser_list_region.add_argument('--city', type=str, help='<city>')
|
||||
parser_list_region.add_argument('--street', type=str, help='<street>')
|
||||
parser_list_region.add_argument('--zip', type=str, help='<zip>')
|
||||
parser_list_region.add_argument('--vlcp_name', type=str,
|
||||
help='<vlcp_name>')
|
||||
|
||||
# add metadata to region
|
||||
h1, h2 = '<region_id>', '<metadata json file>'
|
||||
parser_add_metadata = subparsers.add_parser('add_metadata',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_add_metadata.add_argument('region_id', type=str, help=h1)
|
||||
parser_add_metadata.add_argument('datafile', type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
|
||||
# update region's metadata
|
||||
h1, h2 = '<region_id>', '<metadata json file>'
|
||||
parser_update_metadata = subparsers.add_parser('update_metadata',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_update_metadata.add_argument('region_id', type=str, help=h1)
|
||||
parser_update_metadata.add_argument('datafile',
|
||||
type=argparse.FileType('r'),
|
||||
help=h2)
|
||||
# delete metadata key from region
|
||||
h1, h2 = '<region id>', '<metadata key>'
|
||||
parser_delete_metadata = subparsers.add_parser('delete_metadata',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_delete_metadata.add_argument('region_id', type=str, help=h1)
|
||||
parser_delete_metadata.add_argument('metadata_key', type=str, help=h2)
|
||||
|
||||
# get region's metadata
|
||||
h1 = '<region id>'
|
||||
parser_get_metadata = subparsers.add_parser('get_metadata',
|
||||
help='%s' % (h1))
|
||||
parser_get_metadata.add_argument('region_id', type=str, help=h1)
|
||||
|
||||
# update region's status
|
||||
h1, h2 = '<region_id>', '<status>'
|
||||
parser_update_status = subparsers.add_parser('update_status',
|
||||
help='%s %s' % (h1, h2))
|
||||
parser_update_status.add_argument('region_id', type=str, help=h1)
|
||||
parser_update_status.add_argument('status', type=str, help=h2)
|
||||
|
||||
|
||||
def get_token(timeout, args, host):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
url = '%s/v2.0/tokens'
|
||||
data = '''
|
||||
{
|
||||
"auth": {
|
||||
"tenantName": "%s",
|
||||
"passwordCredentials": {
|
||||
"username": "%s",
|
||||
"password": "%s"
|
||||
}
|
||||
}
|
||||
}'''
|
||||
for argument in ('tenant_name', 'username', 'password', 'auth_region'):
|
||||
argument_value = getattr(args, argument, None)
|
||||
if argument_value is not None:
|
||||
globals()[argument] = argument_value
|
||||
else:
|
||||
# If it does not exist in the configuration, we would like the
|
||||
# exception to be raised
|
||||
configuration_value = getattr(config, argument)
|
||||
if configuration_value:
|
||||
globals()[argument] = configuration_value
|
||||
else:
|
||||
message = ('ERROR: {} for token generation was not supplied. '
|
||||
'Please use its command-line '
|
||||
'argument or environment variable.'.format(argument))
|
||||
print message
|
||||
raise cli_common.MissingArgumentError(message)
|
||||
|
||||
keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host),
|
||||
auth_region)
|
||||
if keystone_ep is None:
|
||||
raise ConnectionError(
|
||||
'Failed in get_token, host: {}, region: {}'.format(host,
|
||||
auth_region))
|
||||
url = url % (keystone_ep,)
|
||||
data = data % (tenant_name, username, password,)
|
||||
|
||||
if args.verbose:
|
||||
print(
|
||||
"Getting token:\ntimeout: %d\nheaders: %s\nurl: %s\n" % (
|
||||
timeout, headers, url))
|
||||
try:
|
||||
resp = requests.post(url, timeout=timeout, data=data, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
raise ResponseError(
|
||||
'Failed to get token (Reason: {})'.format(
|
||||
resp.status_code))
|
||||
return resp.json()['access']['token']['id']
|
||||
|
||||
except Exception as e:
|
||||
print e.message
|
||||
raise ConnectionError(e.message)
|
||||
|
||||
|
||||
def preparm(p):
|
||||
return ('' if len(p) else '?') + ('&' if len(p) else '')
|
||||
|
||||
|
||||
def cmd_details(args):
|
||||
if args.subcmd == 'get_region':
|
||||
return requests.get, '/%s' % args.region_name_or_id
|
||||
elif args.subcmd == 'create_region':
|
||||
return requests.post, ''
|
||||
elif args.subcmd == 'update_region':
|
||||
return requests.put, '/%s' % args.region_id
|
||||
elif args.subcmd == 'delete_region':
|
||||
return requests.delete, '/%s' % args.region_id
|
||||
elif args.subcmd == 'list_regions':
|
||||
param = ''
|
||||
if args.type:
|
||||
param += '%stype=%s' % (preparm(param), args.type)
|
||||
if args.status:
|
||||
param += '%sstatus=%s' % (preparm(param), args.status)
|
||||
if args.metadata:
|
||||
for meta in args.metadata:
|
||||
param += '%smetadata=%s' % (preparm(param), meta[0])
|
||||
if args.aicversion:
|
||||
param += '%saicversion=%s' % (preparm(param), args.aicversion)
|
||||
if args.clli:
|
||||
param += '%sclli=%s' % (preparm(param), args.clli)
|
||||
if args.regionname:
|
||||
param += '%sregionname=%s' % (preparm(param), args.regionname)
|
||||
if args.osversion:
|
||||
param += '%sosversion=%s' % (preparm(param), args.osversion)
|
||||
if args.valet:
|
||||
param += '%svalet=%s' % (preparm(param), args.valet)
|
||||
if args.state:
|
||||
param += '%sstate=%s' % (preparm(param), args.state)
|
||||
if args.country:
|
||||
param += '%scountry=%s' % (preparm(param), args.country)
|
||||
if args.city:
|
||||
param += '%scity=%s' % (preparm(param), args.city)
|
||||
if args.street:
|
||||
param += '%sstreet=%s' % (preparm(param), args.street)
|
||||
if args.zip:
|
||||
param += '%szip=%s' % (preparm(param), args.zip)
|
||||
if args.vlcp_name:
|
||||
param += '%svlcp_name=%s' % (preparm(param), args.vlcp_name)
|
||||
return requests.get, '/%s' % param
|
||||
elif args.subcmd == 'add_metadata':
|
||||
return requests.post, '/%s/metadata' % args.region_id
|
||||
elif args.subcmd == 'update_metadata':
|
||||
return requests.put, '/%s/metadata' % args.region_id
|
||||
elif args.subcmd == 'delete_metadata':
|
||||
return requests.delete, '/%s/metadata/%s' % (args.region_id,
|
||||
args.metadata_key)
|
||||
elif args.subcmd == 'get_metadata':
|
||||
return requests.get, '/%s/metadata' % args.region_id
|
||||
elif args.subcmd == 'update_status':
|
||||
return requests.put, '/%s/status' % args.region_id
|
||||
elif args.subcmd == 'get_group':
|
||||
return requests.get, '/%s' % args.group_id
|
||||
elif args.subcmd == 'list_groups':
|
||||
return requests.get, '/'
|
||||
elif args.subcmd == 'create_group':
|
||||
return requests.post, '/'
|
||||
elif args.subcmd == 'update_group':
|
||||
return requests.put, '/%s' % args.group_id
|
||||
elif args.subcmd == 'delete_group':
|
||||
return requests.delete, '/%s' % args.group_id
|
||||
|
||||
|
||||
def get_path(args):
|
||||
path = 'v2/orm/regions'
|
||||
if 'group' in args.subcmd:
|
||||
path = 'v2/orm/groups'
|
||||
return path
|
||||
|
||||
|
||||
def get_environment_variable(argument):
|
||||
# The rules are: all caps, underscores instead of dashes and prefixed
|
||||
environment_variable = 'AIC_ORM_{}'.format(
|
||||
argument.replace('-', '_').upper())
|
||||
|
||||
return os.environ.get(environment_variable)
|
||||
|
||||
|
||||
def run(args):
|
||||
url_path = get_path(args)
|
||||
host = args.orm_base_url if args.orm_base_url else config.orm_base_url
|
||||
port = args.port if args.port else 8080
|
||||
data = args.datafile.read() if 'datafile' in args else '{}'
|
||||
timeout = args.timeout if args.timeout else 10
|
||||
rest_cmd, cmd_url = cmd_details(args)
|
||||
url = '%s:%d/%s' % (host, port, url_path) + cmd_url
|
||||
if args.faceless:
|
||||
auth_token = auth_region = requester = client = ''
|
||||
else:
|
||||
try:
|
||||
auth_token = get_token(timeout, args, host)
|
||||
except Exception:
|
||||
exit(1)
|
||||
auth_region = globals()['auth_region']
|
||||
requester = globals()['username']
|
||||
client = requester
|
||||
|
||||
if (args.subcmd == 'get_region' or args.subcmd == 'list_regions') \
|
||||
and "use_version" in args:
|
||||
if args.use_version == 1:
|
||||
url = '%s:%d/lcp' % (host, port) + cmd_url
|
||||
elif args.use_version is not None and args.use_version != 2:
|
||||
print 'API error: use_version argument - invalid value, ' \
|
||||
'allowed values: 1 or 2'
|
||||
exit(1)
|
||||
|
||||
if args.subcmd == "update_status":
|
||||
data = '{"status": "%s"}' % args.status
|
||||
|
||||
tracking_id = args.tracking_id if args.tracking_id else None
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'X-Auth-Token': auth_token,
|
||||
'X-Auth-Region': auth_region,
|
||||
'X-AIC-ORM-Requester': requester,
|
||||
'X-AIC-ORM-Client': client,
|
||||
'X-AIC-ORM-Tracking-Id': tracking_id
|
||||
}
|
||||
if args.verbose:
|
||||
print("Sending API:\ntimeout: %d\ndata: %s\n"
|
||||
"headers: %s\ncmd: %s\nurl: %s\n" % (timeout,
|
||||
data,
|
||||
headers,
|
||||
rest_cmd.__name__,
|
||||
url))
|
||||
try:
|
||||
resp = rest_cmd(url, data=data, timeout=timeout, headers=headers,
|
||||
verify=config.verify)
|
||||
except Exception as e:
|
||||
print e
|
||||
exit(1)
|
||||
|
||||
if not 200 <= resp.status_code < 300:
|
||||
content = resp.content
|
||||
print 'API error: %s %s (Reason: %d)\n%s' % (
|
||||
rest_cmd.func_name.upper(),
|
||||
url,
|
||||
resp.status_code,
|
||||
content)
|
||||
exit(1)
|
||||
|
||||
if resp.status_code == 204: # no content
|
||||
exit(0)
|
||||
|
||||
rj = resp.json()
|
||||
|
||||
if rj == 'Not found':
|
||||
print 'No output was found'
|
||||
else:
|
||||
cli_common.pretty_print_json(rj)
|
0
orm/orm_client/ormcli/tests/__init__.py
Normal file
0
orm/orm_client/ormcli/tests/__init__.py
Normal file
119
orm/orm_client/ormcli/tests/data/cms-add-cust.json
Normal file
119
orm/orm_client/ormcli/tests/data/cms-add-cust.json
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"description": "Customer description",
|
||||
"enabled": true,
|
||||
"name": "myDomain",
|
||||
"metadata": {
|
||||
"my_server_name": "Apache1",
|
||||
"ocx_cust": "123456889"
|
||||
},
|
||||
"regions": [
|
||||
{
|
||||
"name": "SAN1",
|
||||
"type": "single",
|
||||
"quotas": [
|
||||
{
|
||||
"compute": [
|
||||
{
|
||||
"instances": "10",
|
||||
"injected-files": "10",
|
||||
"keypairs": "10",
|
||||
"ram": "10"
|
||||
}
|
||||
],
|
||||
"storage": [
|
||||
{
|
||||
"gigabytes": "10",
|
||||
"snapshots": "10",
|
||||
"volumes": "10"
|
||||
}
|
||||
],
|
||||
"network": [
|
||||
{
|
||||
"floatingip": "10",
|
||||
"network": "10",
|
||||
"port": "10",
|
||||
"router": "10",
|
||||
"subnet": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AIC_MEDIUM",
|
||||
"type": "group",
|
||||
"quotas": [
|
||||
{
|
||||
"compute": [
|
||||
{
|
||||
"instances": "10",
|
||||
"injected-files": "10",
|
||||
"keypairs": "10",
|
||||
"ram": "10"
|
||||
}
|
||||
],
|
||||
"storage": [
|
||||
{
|
||||
"gigabytes": "10",
|
||||
"snapshots": "10",
|
||||
"volumes": "10"
|
||||
}
|
||||
],
|
||||
"network": [
|
||||
{
|
||||
"floatingip": "10",
|
||||
"network": "10",
|
||||
"port": "10",
|
||||
"router": "10",
|
||||
"subnet": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"id": "userId1",
|
||||
"role": [
|
||||
"admin",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "userId2",
|
||||
"role": [
|
||||
"storage"
|
||||
]
|
||||
}
|
||||
],
|
||||
"defaultQuotas": [
|
||||
{
|
||||
"compute": [
|
||||
{
|
||||
"instances": "10",
|
||||
"injected-files": "10",
|
||||
"keypairs": "10",
|
||||
"ram": "10"
|
||||
}
|
||||
],
|
||||
"storage": [
|
||||
{
|
||||
"gigabytes": "10",
|
||||
"snapshots": "10",
|
||||
"volumes": "10"
|
||||
}
|
||||
],
|
||||
"network": [
|
||||
{
|
||||
"floatingip": "10",
|
||||
"network": "10",
|
||||
"port": "10",
|
||||
"router": "10",
|
||||
"subnet": "10"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
29
orm/orm_client/ormcli/tests/data/ims-create-image.json
Normal file
29
orm/orm_client/ormcli/tests/data/ims-create-image.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "abc1",
|
||||
"url": "https://mirrors.it.att.com/images/image-name",
|
||||
"visibility": "private",
|
||||
"disk-format": "raw",
|
||||
"container-format": "bare",
|
||||
"min-disk": 1,
|
||||
"min-ram": 1,
|
||||
"tags": ["tag1", "tag2", "tag3"],
|
||||
"properties": {
|
||||
"property1": "value1",
|
||||
"property2": "value2",
|
||||
"property3": "value3"
|
||||
},
|
||||
"regions": [
|
||||
{
|
||||
"name": "rdm1",
|
||||
"type": "single"
|
||||
},
|
||||
{
|
||||
"name": "rdm3",
|
||||
"type": "single"
|
||||
}
|
||||
],
|
||||
"customers": [
|
||||
"alef",
|
||||
"bet"
|
||||
]
|
||||
}
|
53
orm/orm_client/ormcli/tests/test_cli_common.py
Normal file
53
orm/orm_client/ormcli/tests/test_cli_common.py
Normal file
@ -0,0 +1,53 @@
|
||||
import mock
|
||||
from ormcli import cli_common
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class CmsTests(TestCase):
|
||||
@mock.patch.object(cli_common.requests, 'get')
|
||||
def test_get_keystone_ep_sanity(self, mock_get):
|
||||
my_response = mock.MagicMock()
|
||||
my_response.status_code = cli_common.OK_CODE
|
||||
my_response.json.return_value = {
|
||||
'regions': [{'endpoints': [{
|
||||
'type': 'identity', 'publicURL': 'test'}]}]}
|
||||
mock_get.return_value = my_response
|
||||
|
||||
self.assertEqual(cli_common.get_keystone_ep('a', 'b'), 'test')
|
||||
|
||||
@mock.patch.object(cli_common.requests, 'get',
|
||||
side_effect=cli_common.requests.exceptions
|
||||
.ConnectionError())
|
||||
def test_get_keystone_ep_connection_failed(self, mock_get):
|
||||
self.assertIsNone(cli_common.get_keystone_ep('a', 'b'))
|
||||
|
||||
|
||||
@mock.patch.object(cli_common.requests, 'get')
|
||||
def test_get_keystone_ep_bad_status_code(self, mock_get):
|
||||
my_response = mock.MagicMock()
|
||||
my_response.status_code = cli_common.OK_CODE + 1
|
||||
my_response.json.return_value = {
|
||||
'regions': [{'endpoints': [{
|
||||
'type': 'identity', 'publicURL': 'test'}]}]}
|
||||
mock_get.return_value = my_response
|
||||
|
||||
self.assertIsNone(cli_common.get_keystone_ep('a', 'b'))
|
||||
|
||||
|
||||
@mock.patch.object(cli_common.requests, 'get')
|
||||
def test_get_keystone_ep_bad_response(self, mock_get):
|
||||
my_response = mock.MagicMock()
|
||||
my_response.status_code = cli_common.OK_CODE
|
||||
my_response.json.return_value = {
|
||||
'regions': [{'endpoinqs': [{
|
||||
'type': 'identity', 'publicURL': 'test'}]}]}
|
||||
mock_get.return_value = my_response
|
||||
|
||||
self.assertIsNone(cli_common.get_keystone_ep('a', 'b'))
|
||||
|
||||
my_response.json.return_value = {
|
||||
'regions': [{'endpoints': [{
|
||||
'type': 'identiqy', 'publicURL': 'test'}]}]}
|
||||
mock_get.return_value = my_response
|
||||
|
||||
self.assertIsNone(cli_common.get_keystone_ep('a', 'b'))
|
229
orm/orm_client/ormcli/tests/test_cmscli.py
Normal file
229
orm/orm_client/ormcli/tests/test_cmscli.py
Normal file
@ -0,0 +1,229 @@
|
||||
from cStringIO import StringIO
|
||||
import json
|
||||
import mock
|
||||
from ormcli import cmscli
|
||||
from ormcli import ormcli
|
||||
import requests
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
TJ = {'access': {'token': {'id': 'test'}}}
|
||||
|
||||
|
||||
class CmsTests(TestCase):
|
||||
def setUp(self):
|
||||
out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO()
|
||||
self.mock_response = mock.Mock()
|
||||
|
||||
def respond(self, value, code, headers={}, oy=False):
|
||||
# Set the response according to the parameter
|
||||
if oy:
|
||||
response = mock.Mock()
|
||||
else:
|
||||
response = self.mock_response
|
||||
|
||||
response.json.return_value = value
|
||||
response.status_code = code
|
||||
response.headers = headers
|
||||
return response
|
||||
|
||||
def test_cmd_details(self):
|
||||
# Set up the args parameter
|
||||
args = mock.MagicMock()
|
||||
args.custid = 'test_custid'
|
||||
args.regionid = 'test_region'
|
||||
args.userid = 'test_userid'
|
||||
args.region = 'test_region'
|
||||
args.user = 'test_user'
|
||||
args.starts_with = 'test_startswith'
|
||||
args.contains = 'test_contains'
|
||||
|
||||
subcmd_to_result = {
|
||||
'create_customer': (requests.post, '',),
|
||||
'delete_customer': (requests.delete, '/%s' % args.custid,),
|
||||
'update_customer': (requests.put, '/%s' % args.custid,),
|
||||
'add_region': (requests.post, '/%s/regions' % args.custid,),
|
||||
'replace_region': (requests.put, '/%s/regions' % args.custid,),
|
||||
'delete_region': (
|
||||
requests.delete,
|
||||
'/%s/regions/%s' % (args.custid, args.regionid),),
|
||||
'add_user': (
|
||||
requests.post,
|
||||
'/%s/regions/%s/users' % (args.custid, args.regionid),),
|
||||
'replace_user': (
|
||||
requests.put,
|
||||
'/%s/regions/%s/users' % (args.custid, args.regionid),),
|
||||
'delete_user': (requests.delete, '/%s/regions/%s/users/%s' % (
|
||||
args.custid, args.regionid, args.userid),),
|
||||
'add_default_user': (requests.post, '/%s/users' % args.custid,),
|
||||
'replace_default_user': (requests.put, '/%s/users' % args.custid,),
|
||||
'delete_default_user': (
|
||||
requests.delete, '/%s/users/%s' % (args.custid, args.userid),),
|
||||
'add_metadata': (requests.post, '/%s/metadata' % args.custid,),
|
||||
'replace_metadata': (requests.put, '/%s/metadata' % args.custid,),
|
||||
'get_customer': (requests.get, '/%s' % args.custid,),
|
||||
'list_customers': (requests.get,
|
||||
'/?region=%s&user=%s&starts_with=%s'
|
||||
'&contains=%s' % (args.region,
|
||||
args.user, args.starts_with,
|
||||
args.contains))
|
||||
}
|
||||
|
||||
# Assert that each subcommand returns the expected details
|
||||
for subcmd in subcmd_to_result:
|
||||
args.subcmd = subcmd
|
||||
self.assertEqual(subcmd_to_result[subcmd],
|
||||
cmscli.cmd_details(args))
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep',
|
||||
return_value=None)
|
||||
def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep):
|
||||
args = mock.MagicMock()
|
||||
args.username = 'test'
|
||||
self.assertRaises(cmscli.ConnectionError, cmscli.get_token,
|
||||
'a', args, 'c')
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(cmscli.requests, 'post')
|
||||
def test_get_token_errors(self, mock_post, mock_get_keystone_ep):
|
||||
# Bad status code
|
||||
my_response = mock.MagicMock()
|
||||
my_response.status_code = 201
|
||||
mock_post.return_value = my_response
|
||||
self.assertRaises(cmscli.ConnectionError, cmscli.get_token,
|
||||
3, mock.MagicMock(), 'c')
|
||||
|
||||
# Post fails
|
||||
mock_post.side_effect = ValueError('test')
|
||||
self.assertRaises(cmscli.ConnectionError, cmscli.get_token,
|
||||
3, mock.MagicMock(), 'c')
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(cmscli.requests, 'post')
|
||||
@mock.patch.object(cmscli.requests, 'get')
|
||||
def test_list_customers(self, mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.mock_response
|
||||
args = ormcli.main('orm cms list_customers t'.split())
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn(json.dumps(TJ), output)
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(cmscli.requests, 'post')
|
||||
@mock.patch.object(cmscli.requests, 'get')
|
||||
@mock.patch.object(cmscli, 'get_token')
|
||||
def test_list_customers_a(self, mock_get_token,
|
||||
mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.mock_response
|
||||
mock_get.__name__ = 'a'
|
||||
args = ormcli.main('orm cms --verbose list_customers t'.split())
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn(json.dumps(TJ), output)
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(cmscli.requests, 'post')
|
||||
@mock.patch.object(cmscli.requests, 'get')
|
||||
def test_list_customers_e(self, mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.side_effect = Exception('e')
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm cms list_customers t'.split())
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('e', output)
|
||||
|
||||
@mock.patch.object(cmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(cmscli.requests, 'post')
|
||||
@mock.patch.object(cmscli.requests, 'get')
|
||||
@mock.patch.object(cmscli, 'get_token')
|
||||
@mock.patch.object(cmscli, 'globals')
|
||||
def test_list_customers_errors(self, mock_globals, mock_get_token,
|
||||
mock_get, mock_post,
|
||||
mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.respond(TJ, 204, oy=True)
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm cms list_customers t'.split())
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertEqual('', output)
|
||||
|
||||
def test_parsing(self):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 '
|
||||
'add_user '
|
||||
'client1 customer1 region1 '
|
||||
'ormcli/tests/data/cms-add-cust.json'.split())
|
||||
args = cli.args
|
||||
self.assertEqual(args.orm_base_url, '12.11.10.9')
|
||||
self.assertEqual(args.port, 8832)
|
||||
self.assertEqual(args.timeout, 150)
|
||||
|
||||
@mock.patch('requests.post')
|
||||
def test_timeout(self, mock_post):
|
||||
mock_post.side_effect = Exception("timeout boom")
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms --faceless add_user client1 customer1 region1 '
|
||||
'ormcli/tests/data/cms-add-cust.json'.split())
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('timeout boom', output)
|
||||
|
||||
@mock.patch('requests.post')
|
||||
@mock.patch.object(cmscli, 'get_token')
|
||||
def test_no_keystone(self, mock_get_token, mock_post):
|
||||
mock_post.side_effect = Exception("timeout boom")
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms add_user client1 customer1 region1 '
|
||||
'ormcli/tests/data/cms-add-cust.json'.split())
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
|
||||
@mock.patch('requests.post')
|
||||
@mock.patch.object(cmscli, 'get_token')
|
||||
def test_response_code(self, mock_get_token, mock_post):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms create_customer client1 '
|
||||
'ormcli/tests/data/cms-add-cust.json'.split())
|
||||
resp = self.respond({"access": {"token": {"id": 989}}}, 400)
|
||||
mock_post.return_value = resp
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
|
||||
@mock.patch('requests.post')
|
||||
def test_ok(self, mock_post):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms create_customer client1 '
|
||||
'ormcli/tests/data/cms-add-cust.json'.split())
|
||||
mock_post.return_value = self.respond(
|
||||
{"access": {"token": {"id": 989}}}, 200)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
@mock.patch('requests.post')
|
||||
def test_list_customers(self, mock_post, mock_get):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm cms list_customers --region 2 --user bob client1'.split())
|
||||
resp = self.respond('{"Hi, mom"}', 200, {'X-Subject-Token': 989})
|
||||
mock_post.return_value = self.respond(
|
||||
{"access": {"token": {"id": 989}}}, 200)
|
172
orm/orm_client/ormcli/tests/test_fmscli.py
Normal file
172
orm/orm_client/ormcli/tests/test_fmscli.py
Normal file
@ -0,0 +1,172 @@
|
||||
from cStringIO import StringIO
|
||||
import json
|
||||
import mock
|
||||
from ormcli import fmscli
|
||||
from ormcli import ormcli
|
||||
import requests
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
TJ = {'access': {'token': {'id': 'test'}}}
|
||||
|
||||
|
||||
class FmsTests(TestCase):
|
||||
def setUp(self):
|
||||
out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO()
|
||||
self.mock_response = mock.Mock()
|
||||
|
||||
def respond(self, value, code, headers={}, oy=False):
|
||||
# Set the response according to the parameter
|
||||
if oy:
|
||||
response = mock.Mock()
|
||||
else:
|
||||
response = self.mock_response
|
||||
|
||||
response.json.return_value = value
|
||||
response.status_code = code
|
||||
response.headers = headers
|
||||
return response
|
||||
|
||||
def test_cmd_details(self):
|
||||
# Set up the args parameter
|
||||
args = mock.MagicMock()
|
||||
args.flavorid = 'test_flavorid'
|
||||
args.regionid = 'test_region'
|
||||
args.region = 'test_region'
|
||||
args.tagname = 'test_tagname'
|
||||
args.eskeyname = 'test_eskeyname'
|
||||
args.visibility = 'test_visibility'
|
||||
args.tenant = 'test_tenant'
|
||||
args.series = 'test_series'
|
||||
args.starts_with = 'test_startswith'
|
||||
args.contains = 'test_contains'
|
||||
args.alias = 'test_alias'
|
||||
list_flavors_url = '/?visibility=%s®ion=%s&tenant=%s&series=%s' \
|
||||
'&starts_with=%s&contains=%s&alias=%s'
|
||||
subcmd_to_result = {
|
||||
'create_flavor': (requests.post, '',),
|
||||
'delete_flavor': (requests.delete, '/%s' % args.flavorid,),
|
||||
'add_region': (requests.post, '/%s/regions' % args.flavorid,),
|
||||
'add_tags': (requests.post, '/%s/tags' % args.flavorid,),
|
||||
'replace_tags': (requests.put, '/%s/tags' % args.flavorid,),
|
||||
'delete_tag': (
|
||||
requests.delete,
|
||||
'/%s/tags/%s' % (args.flavorid, args.tagname),),
|
||||
'delete_all_tags': (requests.delete, '/%s/tags' % args.flavorid,),
|
||||
'get_tags': (requests.get, '/%s/tags' % args.flavorid,),
|
||||
'delete_region': (requests.delete, '/%s/regions/%s' % (
|
||||
args.flavorid, args.regionid),),
|
||||
'add_tenant': (requests.post, '/%s/tenants' % args.flavorid,),
|
||||
'delete_tenant': (requests.delete, '/%s/tenants/%s' % (
|
||||
args.flavorid, args.tenantid),),
|
||||
'get_flavor': (requests.get, '/%s' % args.flavorid,),
|
||||
'get_extra_specs': (
|
||||
requests.get, '/%s/os_extra_specs' % args.flavorid,),
|
||||
'delete_all_extra_specs': (
|
||||
requests.delete, '/%s/os_extra_specs' % args.flavorid,),
|
||||
'delete_extra_spec': (requests.delete, '/%s/os_extra_specs/%s' % (
|
||||
args.flavorid, args.eskeyname),),
|
||||
'add_extra_specs': (
|
||||
requests.post, '/%s/os_extra_specs' % args.flavorid,),
|
||||
'list_flavors': (requests.get,
|
||||
list_flavors_url % (args.visibility, args.region,
|
||||
args.tenant, args.series,
|
||||
args.starts_with,
|
||||
args.contains, args.alias))
|
||||
}
|
||||
|
||||
# Assert that each subcommand returns the expected details
|
||||
for subcmd in subcmd_to_result:
|
||||
args.subcmd = subcmd
|
||||
self.assertEqual(subcmd_to_result[subcmd],
|
||||
fmscli.cmd_details(args))
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep',
|
||||
return_value=None)
|
||||
def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep):
|
||||
args = mock.MagicMock()
|
||||
args.username = 'test'
|
||||
self.assertRaises(fmscli.ConnectionError, fmscli.get_token,
|
||||
'a', args, 'c')
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(fmscli.requests, 'post')
|
||||
def test_get_token_errors(self, mock_post, mock_get_keystone_ep):
|
||||
# Bad status code
|
||||
my_response = mock.MagicMock()
|
||||
my_response.status_code = 201
|
||||
mock_post.return_value = my_response
|
||||
self.assertRaises(fmscli.ConnectionError, fmscli.get_token,
|
||||
3, mock.MagicMock(), 'c')
|
||||
|
||||
# Post fails
|
||||
mock_post.side_effect = ValueError('test')
|
||||
self.assertRaises(fmscli.ConnectionError, fmscli.get_token,
|
||||
3, mock.MagicMock(), 'c')
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(fmscli.requests, 'post')
|
||||
@mock.patch.object(fmscli.requests, 'get')
|
||||
@mock.patch.object(fmscli, 'get_token')
|
||||
@mock.patch.object(fmscli, 'globals')
|
||||
def test_list_flavors(self, mock_globals, mock_get_token,
|
||||
mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.mock_response
|
||||
args = ormcli.main('orm fms list_flavors t'.split())
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn(json.dumps(TJ), output)
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(fmscli.requests, 'post')
|
||||
@mock.patch.object(fmscli.requests, 'get')
|
||||
@mock.patch.object(fmscli, 'get_token')
|
||||
@mock.patch.object(fmscli, 'globals')
|
||||
def test_list_flavors_a(self, mock_globals, mock_get_token,
|
||||
mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.mock_response
|
||||
mock_get.__name__ = 'a'
|
||||
args = ormcli.main('orm fms --verbose list_flavors t'.split())
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn(json.dumps(TJ), output)
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(fmscli.requests, 'post')
|
||||
@mock.patch.object(fmscli.requests, 'get')
|
||||
def test_list_flavors_e(self, mock_get, mock_post, mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.side_effect = Exception('e')
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm fms list_flavors t'.split())
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('e', output)
|
||||
|
||||
@mock.patch.object(fmscli.cli_common, 'get_keystone_ep')
|
||||
@mock.patch.object(fmscli.requests, 'post')
|
||||
@mock.patch.object(fmscli.requests, 'get')
|
||||
@mock.patch.object(fmscli, 'get_token')
|
||||
@mock.patch.object(fmscli, 'globals')
|
||||
def test_list_flavors_errors(self, mock_globals, mock_get_token,
|
||||
mock_get, mock_post,
|
||||
mock_get_keystone_ep):
|
||||
mock_post.return_value = self.respond(TJ, 200)
|
||||
mock_get.return_value = self.respond(TJ, 204, oy=True)
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm fms list_flavors t'.split())
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertEqual('', output)
|
||||
|
||||
mock_get.return_value = self.respond(TJ, 404, oy=True)
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm fms --faceless list_flavors t'.split())
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('API error:', output)
|
199
orm/orm_client/ormcli/tests/test_imscli.py
Normal file
199
orm/orm_client/ormcli/tests/test_imscli.py
Normal file
@ -0,0 +1,199 @@
|
||||
from cStringIO import StringIO
|
||||
import mock
|
||||
from ormcli import imscli
|
||||
from ormcli.imscli import cmd_data
|
||||
from ormcli import ormcli
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class ImsTests(TestCase):
|
||||
def setUp(self):
|
||||
out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO()
|
||||
self.mock_response = mock.Mock()
|
||||
|
||||
def respond(self, value, code, headers={}):
|
||||
self.mock_response.json.return_value = value
|
||||
self.mock_response.status_code = code
|
||||
self.mock_response.headers = headers
|
||||
return self.mock_response
|
||||
|
||||
def test_error_with_empty_args(self):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main([])
|
||||
self.assertEqual(cm.exception.code, 2)
|
||||
sys.stderr.seek(0)
|
||||
output = sys.stderr.read()
|
||||
self.assertIn('too few arguments', output)
|
||||
|
||||
def test_help_command(self):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm --help'.split())
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('usage:', output)
|
||||
self.assertIn('optional arguments:', output)
|
||||
self.assertIn('<service>', output)
|
||||
self.assertIn('ims', output)
|
||||
self.assertIn('Image Management', output)
|
||||
|
||||
def test_ims_help_command(self):
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
args = ormcli.main('orm ims --help'.split())
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('usage:', output)
|
||||
self.assertIn('timeout', output)
|
||||
self.assertIn('optional arguments:', output)
|
||||
self.assertIn('orm ims', output)
|
||||
|
||||
@mock.patch.object(imscli, 'cli_common')
|
||||
@mock.patch('requests.put')
|
||||
@mock.patch('requests.post')
|
||||
@mock.patch.object(imscli, 'get_token')
|
||||
@mock.patch.object(imscli, 'globals')
|
||||
def test_timeout(self, mock_globals, mock_get_token,
|
||||
mock_post, mock_put, mock_common):
|
||||
mock_post.side_effect = Exception("timeout boom")
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm ims create_image client1 '
|
||||
'ormcli/tests/data/ims-create-image.json'.split())
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('timeout boom', output)
|
||||
|
||||
@mock.patch('requests.post')
|
||||
@mock.patch.object(imscli, 'get_token')
|
||||
@mock.patch.object(imscli, 'globals')
|
||||
def test_no_keystone(self, mock_globals, mock_get_token, mock_post):
|
||||
mock_post.side_effect = Exception("timeout boom")
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
globals()['auth_region'] = 'test'
|
||||
cli.parse(
|
||||
'orm ims create_image client1 '
|
||||
'ormcli/tests/data/ims-create-image.json'.split())
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
|
||||
# @mock.patch.object(imscli, 'cli_common')
|
||||
# @mock.patch('requests.post')
|
||||
# def test_response_code(self, mock_post, mock_common):
|
||||
# cli = ormcli.Cli()
|
||||
# cli.create_parser()
|
||||
# cli.parse(
|
||||
# 'orm ims create_image client1 '
|
||||
# 'ormcli/tests/data/ims-create-image.json'.split())
|
||||
# resp = self.respond({"access": {"token": {"id": 989}}}, 200)
|
||||
# mock_post.return_value = resp
|
||||
# cli.logic()
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# # The response json should be printed, but since we mock post() only
|
||||
# # once, the response would be the same response received
|
||||
# # from Keystone
|
||||
# self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output)
|
||||
|
||||
# @mock.patch.object(imscli, 'cli_common')
|
||||
# @mock.patch('requests.get')
|
||||
# @mock.patch('requests.post')
|
||||
# def test_get_image_sanity(self, mock_post, mock_get, mock_common):
|
||||
# mock_post.return_value = self.respond(
|
||||
# {"access": {"token": {"id": 989}}}, 201)
|
||||
# cli = ormcli.Cli()
|
||||
# cli.create_parser()
|
||||
# cli.parse('orm ims get_image client1 test'.split())
|
||||
# mock_get.return_value = self.respond(
|
||||
# {"access": {"token": {"id": 989}}}, 200)
|
||||
# cli.logic()
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output)
|
||||
|
||||
# @mock.patch.object(imscli, 'cli_common')
|
||||
# @mock.patch('requests.get')
|
||||
# @mock.patch('requests.post')
|
||||
# def test_list_images(self, mock_post, mock_get, mock_common):
|
||||
# mock_post.return_value = self.respond(
|
||||
# {"access": {"token": {"id": 989}}}, 201)
|
||||
# cli = ormcli.Cli()
|
||||
# cli.create_parser()
|
||||
# cli.parse(
|
||||
# 'orm ims list_images client1 --visibility public --region a '
|
||||
# '--tenant b'.split())
|
||||
# resp = self.respond({"access": {"token": {"id": 989}}}, 200)
|
||||
# mock_get.return_value = self.respond(
|
||||
# {"access": {"token": {"id": 989}}}, 200)
|
||||
# cli.logic()
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output)
|
||||
|
||||
@mock.patch.object(imscli, 'cli_common')
|
||||
@mock.patch('requests.get')
|
||||
@mock.patch('requests.post')
|
||||
@mock.patch.object(imscli, 'get_token')
|
||||
@mock.patch.object(imscli, 'globals')
|
||||
def test_list_images_bad_request(self, mock_get_token, mock_globals,
|
||||
mock_post, mock_get, mock_common):
|
||||
mock_post.return_value = self.respond(
|
||||
{"access": {"token": {"id": 989}}}, 201)
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm ims list_images client1 --visibility public --region a '
|
||||
'--customer b'.split())
|
||||
resp = self.respond({"access": {"token": {"id": 989}}}, 200)
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('API error', output)
|
||||
|
||||
def test_cmd_data_enable(self):
|
||||
my_args = mock.MagicMock()
|
||||
my_args.subcmd = 'enable'
|
||||
cm_data = cmd_data(my_args)
|
||||
self.assertEqual("{\n \"enabled\": true\n}", cm_data)
|
||||
|
||||
def test_cmd_data_disable(self):
|
||||
my_args = mock.MagicMock()
|
||||
my_args.subcmd = 'disable'
|
||||
cm_data = cmd_data(my_args)
|
||||
self.assertEqual("{\n \"enabled\": false\n}", cm_data)
|
||||
|
||||
def test_cmd_data_no_data_file(self):
|
||||
my_args = mock.MagicMock()
|
||||
my_args.subcmd = 'xyz'
|
||||
|
||||
my_args.datafile.read.return_value = "123"
|
||||
cm_data = cmd_data(my_args)
|
||||
self.assertEqual("{}", cm_data)
|
||||
|
||||
def test_cmd_data_from_data_file(self):
|
||||
my_args = MyDataFile()
|
||||
cm_data = cmd_data(my_args)
|
||||
|
||||
self.assertEqual("123", cm_data)
|
||||
|
||||
|
||||
class MyDataFile(object):
|
||||
def __init__(self):
|
||||
self.subcmd = '1'
|
||||
self.datafile = FakeDataFIle()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(['datafile'])
|
||||
|
||||
|
||||
class FakeDataFIle(object):
|
||||
def read(self):
|
||||
return '123'
|
188
orm/orm_client/ormcli/tests/test_rmscli.py
Normal file
188
orm/orm_client/ormcli/tests/test_rmscli.py
Normal file
@ -0,0 +1,188 @@
|
||||
from cStringIO import StringIO
|
||||
import mock
|
||||
from ormcli import ormcli
|
||||
from ormcli import rmscli
|
||||
import requests
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class RmsTests(TestCase):
|
||||
def setUp(self):
|
||||
out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO()
|
||||
self.mock_response = mock.Mock()
|
||||
|
||||
def respond(self, value, code, headers={}):
|
||||
self.mock_response.json.return_value = value
|
||||
self.mock_response.status_code = code
|
||||
self.mock_response.headers = headers
|
||||
return self.mock_response
|
||||
|
||||
def test_cmd_details(self):
|
||||
args = mock.MagicMock()
|
||||
args.get_group = 'test_get_group'
|
||||
args.list_groups = 'test_list_groups'
|
||||
args.create_group = 'test_create_group'
|
||||
args.update_group = 'test_update_group'
|
||||
args.region_name_or_id = 'test_region_name_or_id'
|
||||
args.type = '1'
|
||||
args.status = '2'
|
||||
args.metadata = '3'
|
||||
args.aicversion = '4'
|
||||
args.clli = '5'
|
||||
args.regionname = '6'
|
||||
args.osversion = '7'
|
||||
args.valet = '8'
|
||||
args.state = '9'
|
||||
args.country = '10'
|
||||
args.city = '11'
|
||||
args.street = '12'
|
||||
args.zip = '13'
|
||||
args.vlcp_name = '14'
|
||||
|
||||
AAAAAAA = '/?type=%s&status=%s&metadata=%s&aicversion=%s&clli=%s'\
|
||||
'®ionname=%s&osversion=%s&valet=%s&state=%s&country=%s'\
|
||||
'&city=%s&street=%s&zip=%s&vlcp_name=%s' % (args.type,
|
||||
args.status,
|
||||
args.metadata,
|
||||
args.aicversion,
|
||||
args.clli,
|
||||
args.regionname,
|
||||
args.osversion,
|
||||
args.valet,
|
||||
args.state,
|
||||
args.country,
|
||||
args.city,
|
||||
args.street,
|
||||
args.zip,
|
||||
args.vlcp_name,)
|
||||
|
||||
subcmd_to_result = {'get_region': (requests.get,
|
||||
'/%s' % args.region_name_or_id),
|
||||
'get_group': (requests.get, '/%s' % args.group_id),
|
||||
'list_groups': (requests.get, '/'),
|
||||
'create_group': (requests.post, '/'),
|
||||
'update_group': (
|
||||
requests.put, '/%s' % args.group_id),
|
||||
'list_regions': (requests.get, AAAAAAA)
|
||||
}
|
||||
|
||||
for subcmd in subcmd_to_result:
|
||||
args.subcmd = subcmd
|
||||
self.assertEqual(subcmd_to_result[subcmd],
|
||||
rmscli.cmd_details(args))
|
||||
|
||||
def test_parsing(self):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm rms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 '
|
||||
'list_regions --type big '.split())
|
||||
args = cli.args
|
||||
self.assertEqual(args.orm_base_url, '12.11.10.9')
|
||||
self.assertEqual(args.port, 8832)
|
||||
self.assertEqual(args.type, 'big')
|
||||
self.assertEqual(args.timeout, 150)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_timeout(self, mock_get):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm rms --faceless --orm-base-url 12.11.10.9 --port 8832'
|
||||
' --timeout 1 get_region x'.split())
|
||||
mock_get.side_effect = Exception("timeout boom")
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.logic()
|
||||
self.assertEqual(cm.exception.code, 1)
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('timeout boom', output)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_one_zone(self, mock_get):
|
||||
cli = ormcli.Cli()
|
||||
cli.create_parser()
|
||||
cli.parse(
|
||||
'orm rms --faceless --orm-base-url 12.11.10.9 --port 8832'
|
||||
' --timeout 150 get_region zoneone'.split())
|
||||
resp = self.respond(
|
||||
{
|
||||
"clli": "n/a",
|
||||
"name": "SNA 1",
|
||||
"enabled": 1,
|
||||
"state": "functional",
|
||||
"aic_version": "aic3.0",
|
||||
"endpoints": [
|
||||
{
|
||||
"type": "horizon",
|
||||
"publicurl": "http://horizon1.com"
|
||||
},
|
||||
{
|
||||
"type": "identity",
|
||||
"publicurl": "http://identity1.com"
|
||||
},
|
||||
{
|
||||
"type": "ord",
|
||||
"publicurl": "http://ord1.com"
|
||||
}
|
||||
],
|
||||
"id": "SNA1",
|
||||
"metadata": []
|
||||
}, 200,
|
||||
{'X-Subject-Token': 989})
|
||||
mock_get.return_value = resp
|
||||
cli.logic()
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn('"aic_version": "aic3.0"', output)
|
||||
|
||||
# def test_error_with_wrong_port(self):
|
||||
# args = self.parser.parse_args('--port 1111'.split())
|
||||
# with self.assertRaises(SystemExit) as cm:
|
||||
# rmscli.rmscli_logic(args)
|
||||
# self.assertEqual(cm.exception.code, 1)
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('Connection refused', output)
|
||||
|
||||
# def test_help_command(self):
|
||||
# with self.assertRaises(SystemExit) as cm:
|
||||
# args = self.parser.parse_args(['--help'])
|
||||
# self.assertEqual(cm.exception.code, 0)
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('usage:', output)
|
||||
# self.assertIn('timeout', output)
|
||||
# self.assertIn('optional arguments:', output)
|
||||
# self.assertIn('--host', output)
|
||||
|
||||
# @mock.patch('requests.get')
|
||||
# def test_timeout(self, mock_get):
|
||||
# args = self.parser.parse_args('--host 1.1.1.1 --timeout
|
||||
# 1000'.split())
|
||||
# mock_get.side_effect = Exception("HTTPConnectionPool(
|
||||
# host='1.1.1.1', port=8080): Max retries exceeded with url: /lcp (
|
||||
# Caused by ConnectTimeoutError(
|
||||
# <requests.packages.urllib3.connection.HTTPConnection object at
|
||||
# 0x7f9469c1a310>, 'Connection to 1.1.1.1 timed out. (connect
|
||||
# timeout=1.0)'))")
|
||||
# with self.assertRaises(SystemExit) as cm:
|
||||
# rmscli.rmscli_logic(args)
|
||||
# self.assertEqual(cm.exception.code, 1)
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('ConnectTimeoutError', output)
|
||||
|
||||
# learn how to mock 'real' request.get
|
||||
|
||||
# @mock.patch('rmscli.rmscli.rmscli.requests.get', autospec=True)
|
||||
# def test_bad_status(self, mock_get):
|
||||
# args = self.parser.parse_args([])
|
||||
# mock_get.return_value = Response({},500)
|
||||
# with self.assertRaises(SystemExit) as cm:
|
||||
# rmscli.rmscli_logic(args)
|
||||
# self.assertEqual(cm.exception.code, 1)
|
||||
# sys.stdout.seek(0)
|
||||
# output = sys.stdout.read()
|
||||
# self.assertIn('GET', output)
|
6
orm/orm_client/requirements.txt
Normal file
6
orm/orm_client/requirements.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pecan==1.0.2
|
||||
requests==2.2.1
|
6
orm/orm_client/setup.cfg
Normal file
6
orm/orm_client/setup.cfg
Normal file
@ -0,0 +1,6 @@
|
||||
[nosetests]
|
||||
match=^test
|
||||
where=ormcli
|
||||
nocapture=1
|
||||
cover-package=ormcli
|
||||
cover-erase=1
|
19
orm/orm_client/setup.py
Normal file
19
orm/orm_client/setup.py
Normal file
@ -0,0 +1,19 @@
|
||||
try:
|
||||
from setuptools import setup, find_packages
|
||||
except ImportError:
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='ormcli',
|
||||
version='0.1',
|
||||
description='',
|
||||
author='',
|
||||
author_email='',
|
||||
install_requires=[],
|
||||
test_suite='ormcli',
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
packages=find_packages(exclude=['ez_setup'])
|
||||
)
|
9
orm/orm_client/test-requirements.txt
Normal file
9
orm/orm_client/test-requirements.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
# Hacking already pins down pep8, pyflakes and flake8
|
||||
mock
|
||||
coverage
|
||||
testfixtures
|
||||
pytest-pep8
|
19
orm/orm_client/tox.ini
Normal file
19
orm/orm_client/tox.ini
Normal file
@ -0,0 +1,19 @@
|
||||
[tox]
|
||||
envlist=py27,cover
|
||||
|
||||
[testenv]
|
||||
deps= -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands=
|
||||
py.test --pep8 -m pep8
|
||||
|
||||
[testenv:cover]
|
||||
commands=
|
||||
coverage run setup.py test
|
||||
coverage report --omit=.tox/*,ormcli/tests/*,setup.py
|
||||
coverage html --omit=.tox/*,ormcli/tests/*,setup.py
|
||||
#commands={envpython} setup.py test -v {posargs}
|
||||
|
||||
[testenv:pep8]
|
||||
commands =
|
||||
py.test --pep8 -m pep8
|
Loading…
Reference in New Issue
Block a user