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…
x
Reference in New Issue
Block a user