Created
August 25, 2016 23:38
-
-
Save jollyrojer/d523a6894463458181e2bca121513c2b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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