Skip to content

Instantly share code, notes, and snippets.

@jollyrojer
Created August 25, 2016 23:38
Show Gist options
  • Save jollyrojer/d523a6894463458181e2bca121513c2b to your computer and use it in GitHub Desktop.
Save jollyrojer/d523a6894463458181e2bca121513c2b to your computer and use it in GitHub Desktop.
import argparse
import logging
import os
import re
import time
from qubell.api.private.platform import QubellPlatform
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
class Tonomi:
"""
Get instance and prolongate it for 1 hour.
If no instance found it will create one with TTL = 1 hour.
Get new artifact url from files generated earlier by Jenkins.
Run instance reconfiguration (sets new urls (parameters) as new inputs).
Save instance endpoins to file (they will be used in tests).
"""
def __init__(self, user, password, tenant, organization_name, artifacts_urls_file):
self.user = user
self.password = password
self.tenant = tenant
self.org_name = organization_name
self.artifacts_urls_file = artifacts_urls_file
self.app_name = 'All Up'
self.env_name = 'Review'
self.ins_name_prefix = '[CI] Review test '
self.ins_name = self.ins_name_prefix + time.strftime("%H:%M:%S %d.%m.%Y")
self.tonomi_properties_path = 'tonomi_properties.txt'
self.new_ttl = '7200000' # 3600000 ms = 1 hour
self.max_ci_env_number = 2 # maximum amount of envs allowed for CI
self.organization = None
def get_new_inputs(self):
"""
Retrives params from property file, prepare and return input params in next format:
params = {'input.webapp-url': 'URL_TO_WEBAPP_ARTIFACT',
'input.worker-agent-url': 'URL_TO_WORKER_ARTIFACT'}
"""
if not os.path.isfile(self.artifacts_urls_file):
raise Exception('Artifacts urls files is not found: %s' % self.artifacts_urls_file)
with open(self.artifacts_urls_file) as p_file:
urls = p_file.readlines()
art_urls = dict(e.split('=') for e in urls)
params = dict(map(lambda (key, value): ('input.'+str(key), value), art_urls.items()))
logger.info("Generated input parameters: %s " % params)
return params
def connect(self):
""" Get existed or create a new instance. """
logger.info("Setting the connection.")
try:
self.platform = QubellPlatform.connect(user=self.user, password=self.password, tenant=self.tenant)
logger.info("Successfully connected to: %s" % self.tenant)
except:
raise Exception('Failed to connect to %s' % self.tenant)
logger.info("Getting the organization.")
try:
self.organization = self.platform.get_organization(name=self.org_name)
logger.info("Organization found: %s" % self.org_name)
except:
raise Exception('Organization %s not found' % self.org_name)
def get_instances(self):
""" Returns an operable existed instance. """
logger.info("Looking for the existed instances.")
ci_instances = [i for i in self.organization.instances if i.name.startswith(self.ins_name_prefix)]
logger.info("All CI instances: %s" % ci_instances)
return ci_instances
@staticmethod
def get_active_instance(instances):
""" Return first instance in Active or Running state. """
for instance in instances:
if instance.status in ['Active', 'Running']:
logger.info("Using 1st good instance %s" % instance.name)
return instance
logger.info("There is no instance in Active or Running state.")
return None
def prolongate_TTL(self, instance, new_ttl):
""" Set new TTL for instance """
if instance.destroyAt:
logger.info("Instance prolongate. New TTL: %s ms" % new_ttl)
instance.reschedule_workflow(workflow_name='destroy', timestamp=new_ttl)
else:
logger.info("Almost 'Immortal' instance! :)")
def instance_reconfiguration(self, instance, parameters):
""" Run instance reconfiguration. """
logger.info("Start `%s` instance reconfiguration." % instance.name)
instance.reconfigure(parameters=parameters)
instance.ready(timeout=30)
def create_instance(self, parameters=None):
""" Create and return a new instance. """
logger.info("Creating a new instance.")
application = self.organization.get_application(self.app_name)
environment = self.organization.get_environment(self.env_name)
instance = self.organization.create_instance(application=application,
environment=environment,
name=self.ins_name,
parameters=parameters,
destroyInterval=self.new_ttl)
instance.ready(timeout=600)
return instance
def save_instance_endpoints_to_file(self, instance):
""" Save endpoints to file. """
endpoint_urls = instance.return_values.get('endpoint.endpoint-URL', None)
if not endpoint_urls:
raise Exception('Failed to get endpoint_urls from instance')
get_group_version_pat = re.compile(r'https://(?P<host>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(?P<port>\d+)')
match = get_group_version_pat.search(endpoint_urls[0])
if not match:
raise Exception('Failed to retrieve endpoints params.')
tonomi_properties = dict()
tonomi_properties['host.name'] = match.group('host')
tonomi_properties['host.port'] = match.group('port')
tonomi_properties['app-hosts'] = ','.join(instance.return_values.get('endpoint.app-hosts', None))
tonomi_properties['worker-host'] = ','.join(instance.return_values.get('endpoint.worker-host', None))
logger.info("Saving tonomi properties %s info to %s" % (tonomi_properties, self.tonomi_properties_path))
with open(self.tonomi_properties_path, "w") as p_file:
for k, v in sorted(tonomi_properties.items()):
f = "{key}={value}\n"
line = f.format(key=k, value=v)
p_file.write(line)
def run_tonomi(self):
"""
Main method to run:
Retrives artifacts parameters.
Get and reconfigure instance or create a new one.
Save endpoints to file.
"""
new_instance_parameters = self.get_new_inputs()
self.connect()
ci_instances = self.get_instances()
instance = self.get_active_instance(ci_instances) if len(ci_instances) > 0 else None
if instance:
self.prolongate_TTL(instance, self.new_ttl)
self.instance_reconfiguration(instance, new_instance_parameters)
elif len(ci_instances) < self.max_ci_env_number:
instance = self.create_instance(parameters=new_instance_parameters)
else:
raise Exception('ATTN: CI env number limit has been reached! Please urgently check the existed env states!')
self.save_instance_endpoints_to_file(instance)
if __name__ == '__main__':
help_string = """
Set environment variables TONOMI_USER, TONOMI_PASSWORD, TONOMI_TENANT or use options to provide access to organization.
Example:
python run_tonomi.py -o myorg -u 'user@tonomi.com' -p 'MyPass' -t 'https://express.tonomi.com'
"""
parser = argparse.ArgumentParser(description=help_string, formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-u', '--user', help='Email of registered user on tonomi platform')
parser.add_argument('-p', '--password', help='Password for user')
parser.add_argument('-t', '--tenant', help='Url to platform')
parser.add_argument('-o', '--org', help='Organization name to use.')
parser.add_argument('--artifacts-urls-file', help='File with artifact urls')
args = parser.parse_args()
user = args.user or os.getenv('TONOMI_USER')
password = args.password or os.getenv('TONOMI_PASSWORD')
tenant = args.tenant or os.getenv('TONOMI_TENANT')
organization = args.org or os.getenv('TONOMI_ORGANIZATION')
artifacts_urls_file = args.artifacts_urls_file or os.getenv('ARTIFACTS_URLS_FILE')
tonomi = Tonomi(user, password, tenant, organization, artifacts_urls_file)
tonomi.run_tonomi()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment