def create(self, *args, **kwargs): varg = kwargs.get('pargs', None) if not varg: varg = kwargs group = None server = None type = varg.get('type', kwargs.get('type', None)) resource = varg.get('resource', kwargs.get('resource', None)) if type and type == 'delete': if not resource == 'service' or resource == 'server': servers = self._list_servers(kwargs, varg) for server in servers: if not server is None: group = Groups(self.config).find( ref=server['_links']['group']['href']) if not group is None: break elif resource == 'service': services = self._list_services(kwargs, varg) for service in services: if not service is None: group = Groups(self.config).find( ref=service['_links']['group']['href']) if not group is None: break if group is None: gid = varg.get('group', kwargs.get('group', None)) if not gid: raise IaaSError( 'Server or Group is required to start an order.') groups = Groups(self.config).list(detailed=True) key = None try: if str(int(gid)) == gid: key = 'id' except ValueError as e: if string.index(gid, '/') >= 0: key = '_links/self/href' matches = groups._filter([[key, gid]]) if isinstance(matches, list) and matches.__len__() > 0: group = matches[0] if not group is None: # This is NOT the else: for the previous statement ;) name = "Server order for {}".format(group._href) if not server is None: name = "Server order for {}".format(server._href) order_init = { "name": name, "group": group._href, "submit-now": "false" } resp = self.client().post('/api/v2/orders/', order_init, raw=True) if resp.status_code >= 400 or resp.status_code < 200: raise IaaSCloudboltAPIError(resp.text) else: mash = json.loads(resp.text) self.update(mash) return self else: raise IaaSError('Cannot determine/validate group')
def me(self): try: users = self.list() info = [user for user in users if string.lower(user['user.username']) == self.config.get('username')] if not isinstance(info, list): raise IaaSError('User info returned is incorrect type(%s): %s' % (info.__class__.__name__, info)) if len(info) < 1: return None me = User(self.config, href=info[0]['_links']['self']['href']) return me except Exception as e: raise IaaSError(str(e.message))
def submit(self, *args, **kwargs): def checkstatus(self): if not (self['status'] == 'PENDING' or self['status'] == 'CART'): resp = { 'status_code': 500, 'detail': 'Order status error', 'error': "Order {}: Only orders that are in 'PENDING' state can be approved. Current state of order is {}" .format(self._href, self['status']) } resp.update({'_links': self['_links']}) return resp return None def checkresponse(self, resp): if resp.status_code == 200: mash = json.loads(resp.text) self.update(mash) return mash raise IaaSCloudboltAPIError(resp.status_code, resp.text) mash = self._action('submit', checkstatus, checkresponse) if not mash is None: return mash raise IaaSError('Order {} cannot be cancelled'.format(self._href))
def _action(self, verb, checkstatus, checkresponse): if self['_links'].has_key('actions'): actions = [ action for action in self['_links']['actions'] if action.has_key(verb) ] if not len(actions) > 0: raise IaaSError('Order {} has no "{}" action'.format( self._href, verb)) action = actions[0] else: self.update(Order(self.config, href=self._href)) action = {verb: {'href': self._href + '/actions/{}'.format(verb)}} if self.get('status', None): resp = checkstatus(self) if not resp is None: return resp resp = self.client().post(action[verb]['href'], raw=True) if resp.status_code >= 400 or resp.status_code < 200: return checkresponse(self, resp) else: # return json.loads(resp.text) mash = json.loads(resp.text) self.update(mash) return self
def _evaluate(self, flt, against=None): if against is None: against = self if isinstance(flt, basestring): try: if isinstance(against, dict): idx = string.index(flt, '/') parts = string.split(flt, '/') return self._match_parts(parts, against) else: if isinstance(against, list): val = [o._evaluate(flt) for o in against] val = [o for o in val if o] return val else: if isinstance(against, basestring): return against else: raise IaaSError('What to do about a {}'.format( against.__class__.__name__)) except ValueError as e: return self._match_parts([flt], against) else: if isinstance(flt, basestring): return against.has_key(flt) return None
def list(self, *args, **kw): try: if not self.__len__() > 0: self.get('/{}'.format(string.lower(self.__class__.__name__)), *args, **kw) return self except Exception as e: raise IaaSError(str(e.message))
def _environment(self, kwargs, varg): envref = varg.get('environment', kwargs.get('environment', None)) if not envref: raise IaaSError('Environment is required to add to an order.') if not isinstance(envref, Environment): environment = Environment(self.config) environment.href(ref=envref) else: environment = envref return environment
def _list_servers(self, kwargs, varg): if not getattr(self, '_servers', None): entries = re.split(',\s*', varg.get('server', kwargs.get('server', None))) servers = [ self._server(kwargs, varg, ref=srvref) for srvref in entries ] servers = [server for server in servers if not server is None] if servers.__len__() <= 0: raise IaaSError( 'Unable to find servers that match {}'.format(entries)) self._servers = servers return self._servers
def _list_services(self, kwargs, varg): if not getattr(self, '_services', None): entries = re.split( ',\s*', varg.get('service', kwargs.get('service', None))) services = [ self._service(kwargs, varg, ref=svc) for svc in entries ] services = [service for service in services if not service is None] if services.__len__() <= 0: raise IaaSError( 'Unable to find services that match {}'.format(entries)) self._services = services return self._services
def info(self): groups = Groups(self.app.config.get_section_dict('cloudbolt')).list() info = [ group for group in groups if string.lower(group['group.groupname']) == self.app.config.get( 'cloudbolt', 'groupname') ] if not isinstance(info, list): raise IaaSError('Group info returned is incorrect type(%s): %s' % (info.__class__, info)) me = Group(self.app.config.get_section_dict('cloudbolt'), href=info[0]['_links']['self']['href']) self.render([me])
def api_client(self): try: config = self.config protocol = config.get('protocol') or 'https' port = config.get('port') or 443 domain = config.get('domain') username = config.get('username') + '@' + domain password = config.get('password') hostname = config.get('hostname') return CloudBoltAPIClient(username, password, host=hostname, port=port, protocol=protocol) except NoOptionError as e: raise IaaSError(str(e.message))
def _service(self, kwargs, varg, ref=None): if ref is None: ref = varg.get('service', kwargs.get('service', None)) if not ref: raise IaaSError('service is required to add to a delete order.') if not isinstance(ref, Server): if not getattr(self, '_collection', None): self._collection = Servers(self.config) service = Service(self.config, ref=ref) if not (service is None or service.href()): service = self._collection.find(ref=ref) # if not (service is None or service.href()): # raise IaaSError('Unable to find service {}'.format(srvref)) ref = service return ref
def post_a_object(self, href, parameters=None): if parameters is None: parameters = {} resp = self.client().post(href, self, headers=parameters.get('headers', None), raw=parameters.get('raw', None)) try: if resp.status_code == 403: raise IaaSCloudboltAPIError( resp.status_code, 'GET {}: {}'.format(href, resp.text)) if resp.status_code == 200: mash = json.loads(resp.text) return mash raise IaaSError('GET {}: {}'.format(href, resp.text)) except Exception as e: raise e
def show(self): def getid(rec): pass groups = Groups(self.app.config.get_section_dict('cloudbolt')).list() info = [ group for group in groups if string.lower(group['group.groupname']) == self.app.config.get( 'cloudbolt', 'groupname') ] if not isinstance(info, list): raise IaaSError('Group info returned is incorrect type(%s): %s' % (info.__class__, info)) me = [ Group(self.app.config.get_section_dict('cloudbolt'), href=info[0]['_links']['self']['href']) ] if len(me) > 0: attributes = [] if self.app.pargs.self: attributes.append('_links/self') if self.app.pargs.groups: # attributes.append('_links/groups/(href;title)') attributes.append('_links/groups') if self.app.pargs.id: attributes.append(getid) if len(attributes) > 0: if self.app.pargs.attributes: self.app.pargs.attributes += ','.join(attributes) else: self.app.pargs.attributes = ','.join(attributes) if self.app.pargs.attributes: nume = self._prune(me, 'attributes') if len(nume) > 0: me = nume else: me = [{ "message": 'No group attributes matched from "{}"'.format( self.app.pargs.attributes) }] else: me = [{"message": 'No groups found'}] self.render(me)
def __init__(self, *args, **kw): if self.__class__.__name__ != 'CloudboltPluginController': if not getattr(self.Meta, 'arguments_inherited', False): self.Meta.arguments = self.Meta.arguments + CloudboltPluginController.Meta.common_arguments self.Meta.arguments_inherited = True seen = {} for arg in self.Meta.arguments: if arg[0].__len__() >= 2: word = arg[0][1] else: word = arg[0][0] if not seen.get(word, False): seen[word] = True else: raise IaaSError("arg {} is duplicated in {}".format( arg, self.__class__.__name__)) else: pass super(CloudboltPluginController, self).__init__(*args, **kw) self._client = None
def _match_parts(self, parts, against): if against is None: against = self matches = re.match('^\((.*?)\)$', parts[0]) if matches: flds = string.split(matches.group(1), ';') if isinstance(against, dict): no = self.__class__(self.config, parameters=self.parameters) for k in flds: if against.has_key(k): no[k] = against[k] if len(no) <= 0: return None return no else: raise IaaSError('TODO {}'.format(against.__class__.__name__)) else: if not against.has_key(parts[0]): return None if len(parts) == 1: return against[parts[0]] return self._evaluate('/'.join(parts[1:]), against=against[parts[0]])
def cancel(self): def checkstatus(self): if not (self['status'] == 'PENDING' or self['status'] == 'CART'): resp = { 'status_code': 500, 'detail': 'Order status error', 'error': "Order {}: Only orders that are in 'PENDING' state can be approved. Current state of order is {}" .format(self._href, self['status']) } resp.update({'_links': self['_links']}) return resp return None def checkresponse(self, resp): if resp.status_code == 200 or (resp.status_code == 500 and verb == 'submit'): # A failed submit is ok when we 'cancel' mash = json.loads(resp.text) mash.update({'_links': self['_links']}) mash['detail'] = "Order {} was {}'ed".format(self._href, verb) mash['status_code'] = 200 # Fake it mash.pop('error') return mash if resp.status_code == 404: # Ok the first link does not work ... return None else: raise IaaSCloudboltAPIError(resp.text) for verb in ['cancel', 'submit']: mash = self._action(verb, checkstatus, checkresponse) if not mash is None: return mash raise IaaSError('Order {} cannot be cancelled'.format(self._href))
def check_recipe(self, recipe=None): if recipe is None: if not hasattr(self._meta, 'recipe'): msg = '{} does not have a recipe!'.format( self.__class__.__name__) self.app.log.fatal(msg) raise IaaSError(msg) recipe = self._meta.recipe msg = '' for ingredient in recipe: if not getattr(self.app.pargs, ingredient['parameter'], None): if not is_true(self.setting('batch')) and self.setting( 'prompt') and ingredient['ask']: self.app.log.info('Prompt here for {}'.format( ingredient['parameter'])) prompt = ArgPrompt() if ingredient.get('options', None): prompt._meta.numbered = True options = ingredient['options'] if options.get('values', None): prompt._meta.options = options['values'] elif options.get('class', None): columns = getattr(self, '_columns', None) ignored = getattr(self, '_ignored', None) try: if options['module'] not in sys.modules: try: __import__(options['module'], globals(), locals(), [], 0) except ImportError as e: raise IaaSError( 'Unable to import class needed to pull list of options for {} ({})' .format(ingredient, e.message)) klass = getattr(sys.modules[options['module']], options['class']) instance = klass( self.app.config.get_section_dict( options['section'])) print('Obtaining a {} of {} ...'.format( options['method'], options['class'])) if options['attribute'].get('filters', None): filters = getattr(self, '_filters', None) self._filters = options['attribute'][ 'filters'] self.app.log.info('Filter {}.{}.{}'.format( options['section'], options['class'], options['method'])) values = getattr(instance, options['method'])( _filter=self._weigh, _collection=instance) if filters: self._filters = filters else: values = getattr( instance, options['method'])(detailed=True) if not values.__len__() > 0: raise FrameworkError( 'There are no {}!'.format( options['class'])) if not isinstance(options['attribute']['show'], list): options['attribute']['show'] = [ options['attribute']['show'] ] self._columns = options['attribute']['show'] selection = self._prune(values) i = 0 while i < selection.__len__(): for show in options['attribute']['show']: if not selection[i].get(show, None): for attr in options['attribute'][ 'alternatives']: sub = values[i]._evaluate(attr) if sub: selection[i][ show] = '{}:{}'.format( attr, sub) break i += 1 prompt._meta.options = [ ','.join(dict(obj).values()) for obj in selection ] self._meta.values = instance except KeyError as e: # raise IaaSError('Ingredient {} options for recipe {}.{} requires an unknown class'.format(ingredient,self.__class__.__name__, self._meta.label)) # except ValueError as e: raise IaaSError( 'Ingredient {} for recipe {}.{} requires a "{}" attribute' .format(ingredient, self.__class__.__name__, self._meta.label, e.message)) except FrameworkError as e: self.app.log.fatal("'{}': '{}'".format( e.message, e.msg)) print('FATAL error: {}'.format(e.msg)) raise e except Exception as e: self.app.log.fatal(e.message) print('FATAL error: {}'.format(e.message)) raise e if not columns is None: self._columns = columns if not ignored is None: self._ignored = ignored else: raise IaaSError( 'Ingredient {} options for recipe {}.{} are not valid' .format(ingredient, self.__class__.__name__, self._meta.label)) prompt._meta.text = 'Choose {}:'.format( ingredient['description']) else: prompt._meta.numbered = False prompt._meta.options = None prompt._meta.text = 'Enter {}: '.format( ingredient['description']) # prompt._meta.selection_text = 'Enter the {}:'.format(ingredient['parameter']) try: answer = prompt.prompt() if ingredient.get('options', None): options = ingredient['options'] if options.get('values', None): setattr(self.app.pargs, ingredient['parameter'], prompt.input) elif options.get('class', None): index = prompt._meta.options.index(answer) values = [self._meta.values[index]] columns = getattr(self, '_columns', None) ignored = getattr(self, '_ignored', None) self._columns = [options['attribute']['use']] selection = self._prune(values) if not columns is None: self._columns = columns if not ignored is None: self._ignored = ignored setattr( self.app.pargs, ingredient['parameter'], '{}:{}'.format( options['attribute']['use'], selection[0].get( options['attribute']['use'], None))) print('{} value will be "{}"'.format( ingredient['parameter'], getattr(self.app.pargs, ingredient['parameter']))) # if string.index(options['attribute']['use'], '/') < 0: # pass # else: # setattr(self.app.pargs, ingredient['parameter'], selection[0].get(options['attribute']['use'], None)) else: setattr(self.app.pargs, ingredient['parameter'], prompt.input) except FrameworkError as e: self.app.log.fatal("'{}': '{}'".format( e.message, e.msg)) print('FATAL error: {}'.format(e.msg)) raise e if not getattr(self.app.pargs, ingredient['parameter'], None): msg += "'{}' is required. ({})\n".format( ingredient['parameter'], ingredient['description']) if msg.__len__() > 0: raise IaaSError(msg)
def list(self): try: respns = self.get('/users') return respns except Exception as e: raise IaaSError(str(e.message))
def show(self): if not self.app.pargs.order: raise IaaSError('Order ref is required') self._show(Orders(self.app.config.get_section_dict('cloudbolt')), ref=self.app.pargs.order)
def add(self, *args, **kwargs): varg = kwargs.get('pargs', None) if not varg: varg = kwargs bpref = varg.get('blueprint', kwargs.get('blueprint', None)) if not bpref: raise IaaSError('blueprint is required to add to an order.') if not isinstance(bpref, Blueprint): blueprint = Blueprint(self.config, ref=bpref) if not blueprint: raise IaaSError('Unable to find blueprint {}'.format(bpref)) else: blueprint = bpref if not blueprint.get('is-orderable', False): raise IaaSError('Blueprint {} is not orderable'.format(bpref)) parameters = varg.get('parameters', kwargs.get('parameters', None)) sections = {} if parameters and len(string.lstrip(string.rstrip(parameters))) > 0: kv = lambda x: re.split('=\s*', x) # pm = lambda x: re.split(',\s*', x) sn = lambda x: re.split(':\s*', x) if string.find(parameters, ':') < 0: raise IaaSError( 'Invalid blueprint parameters: {} (Missing : so not able to identify build item)' .format(parameters)) if string.find(parameters, '=') < 0: raise IaaSError( 'Invalid blueprint parameters: {} (Missing = so not able to identify key/value pairs)' .format(parameters)) raw_sects = re.split(';\s*', parameters) raw_sects = dict(map(sn, raw_sects)) for sect, pars in raw_sects.items(): assigns = re.split(',\s*', pars) parameters = map(kv, assigns) parameters = dict(parameters) sections[sect] = parameters service_name = varg.get('service', kwargs.get('service', None)) if not service_name: raise IaaSError('Service name is required to add to an order.') environment = self._environment(kwargs, varg) password = varg.get('password', kwargs.get('password', None)) if not password: raise IaaSError('Password is required to add to a service order.') if password.__len__() < 8: raise IaaSError( 'Password must be 8 characters or more to add to a service order.' ) blueprint_items_arguments = {} for item in blueprint['build-items']: name = "build-item-{}".format(item['name']) parameters = sections.get(item['name'], {}) if item['type'] == 'provserver': parameters.update({"new-password": password}) build_item = { "environment": environment._href, "attributes": { "quantity": varg.get('quantity', kwargs.get('quantity', 1)) }, "parameters": parameters } else: build_item = { "parameters": parameters, } blueprint_items_arguments[name] = build_item order_service_item = { "blueprint": blueprint._href, "blueprint-items-arguments": blueprint_items_arguments, "service-name": service_name } resp = self.client().post(self.href() + '/deploy-items/', order_service_item, raw=True) if resp.status_code >= 400 or resp.status_code < 200: raise IaaSCloudboltAPIError(resp.text) else: mash = json.loads(resp.text) self.update(mash) return self
def delete(self, *args, **kwargs): varg = kwargs.get('pargs', None) if not varg: varg = kwargs environment = None servers = None services = None resource = varg.get('resource', kwargs.get('resource', None)) if not resource == 'service' or resource == 'server': servers = self._list_servers(kwargs, varg) for server in servers: if not server.get('status', None) in ['ACTIVE', 'PROV']: raise IaaSError('Server {} is not ACTIVE'.format( server._href)) if server: environment = Environments(self.config).find( ref=server['_links']['environment']['href']) if environment is None: if not kwargs['environment']: raise IaaSError( 'Server or Environment is required to start a delete order.' ) environment = self._environment(kwargs, varg) if not environment is None: break elif resource == 'service': services = self._list_services(kwargs, varg) for service in services: if not service.get('status', None) in ['Active']: raise IaaSError('Service {} is not Active'.format( service._href)) if service: server = None if service['_links']['servers'].__len__() > 0: server = Servers(self.config).find( ref=service['_links']['servers'][0]['href']) else: servers = Servers(self.config).list(detailed=True) if servers.__len__() > 0: server = servers[0] if server: environment = Environments(self.config).find( ref=server['_links']['environment']['href']) if environment is None: if not kwargs['environment']: raise IaaSError( 'Service or Environment is required to start a delete order.' ) environment = self._environment(kwargs, varg) if not environment is None: break if not environment is None: decom_item = {} decom_item['environment'] = environment._href if not resource == 'service' or resource == 'server': decom_item['servers'] = [server._href for server in servers] elif resource == 'service': decom_item['services'] = [ service._href for service in services ] resp = self.client().post(self.href() + '/decom-items/', decom_item, raw=True) if resp.status_code >= 400 or resp.status_code < 200: raise IaaSCloudboltAPIError(resp.text) else: mash = json.loads(resp.text) self.update(mash) return self else: raise IaaSError('Cannot determine/validate environment')
def get_all_records(self, object, *args, **kwargs): try: parameters = kwargs.get('parameters', {}) objs = [] seen = 0 try: pool = int(kwargs.get('pool', sys.maxint)) if parameters.has_key('pool') and parameters['pool']: pool = int(parameters['pool']) except ValueError as e: raise IaaSError("'limit' value is not an integer!?") try: total = int(kwargs.get( 'total', sys.maxint)) # Get all matches or the specified # if parameters.has_key('total') and parameters['total']: total = int(parameters['total']) except ValueError as e: raise IaaSError("'limit' value is not an integer!?") # dater = parameters[:date_range] || 'all' # Get all matches or the specified # try: offset = int(kwargs.get('offset', 0)) if parameters.has_key('offset') and parameters['offset']: offset = int(parameters['offset']) except ValueError as e: raise IaaSError("'limit' value is not an integer!?") try: limit = int(kwargs.get('limit', 0)) if parameters.has_key('limit') and parameters['limit']: limit = int(parameters['limit']) except ValueError as e: raise IaaSError("'limit' value is not an integer!?") pn = 1 try: if offset > 0: pn = int(kwargs.get('page', offset / limit)) if parameters.has_key('page') and parameters['page']: pn = int(parameters['page']) else: pn = int(kwargs.get('page', pn)) except ValueError as e: raise IaaSError("'page' value is not an integer!?") page = self.get_a_page(object, action=kwargs.get('action', ''), pool=pool, total=total, page=pn, offset=offset, limit=limit) while page and isinstance(page, dict): if kwargs.get('_filter', None): slice = [] for obj in page['_embedded']: nobj = kwargs['_filter'](obj, kwargs['_collection']) if not nobj is None: slice.append(nobj) objs.extend(slice) seen += len(slice) else: objs.extend(page['_embedded']) seen += len(page['_embedded']) if page.has_key( 'count' ): # Adjust limit (down or up) based on API feedback limit = page['count'] if page.has_key( 'total'): # Total is what API says or _everything_ if page['total'] < total: total = page['total'] if page['total'] < pool: pool = page['total'] # pgnos = total/limit # No of pages is obvious if total < len(objs): if isinstance(objs[0], list): raise StandardError("Should not slice array of arrays") objs = objs[0:total] next = False if page.has_key('_links'): if page['_links'].has_key('next'): next = True if next and len(objs) < total and seen < pool: # pn < pgnos && pn += 1 page = self.get_a_page(object, action=kwargs.get('action', ''), pool=pool, total=total, page=pn, offset=offset, limit=limit) else: page = None return objs except IaaSError as e: raise e except Exception as e: traceback.print_exc(file=sys.stdout)