def test_refresh_from_db_add_and_delete(self): zm = zone_manager.ZoneManager() zone_state = zone_manager.ZoneState() zone_state.update_credentials( FakeZone(id=1, api_url='http://foo.com', username='******', password='******')) zm.zone_states[1] = zone_state self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([ FakeZone(id=2, api_url='http://foo.com', username='******', password='******'), ]) self.assertEquals(len(zm.zone_states), 1) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertEquals(zm.zone_states[2].username, 'user2')
def test_refresh_from_db_replace_existing(self): zm = zone_manager.ZoneManager() zone_state = zone_manager.ZoneState() zone_state.update_credentials( FakeZone(id=1, api_url='http://foo.com', username='******', password='******', name='child', weight_offset=0.0, weight_scale=1.0)) zm.zone_states[1] = zone_state self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([ FakeZone(id=1, api_url='http://foo.com', username='******', password='******', name='child', weight_offset=0.0, weight_scale=1.0), ]) self.assertEquals(len(zm.zone_states), 1) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertEquals(zm.zone_states[1].username, 'user2')
def test_refresh_from_db_missing(self): zone_state = self._create_zone_state(zone_id=1, username='******') zm = self.zone_manager zm.zone_states[1] = zone_state self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([]) self.assertEquals(len(zm.zone_states), 1) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 0)
def test_refresh_from_db_new(self): zone = _create_zone(zone_id=1, username='******') self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([zone]) zm = self.zone_manager self.assertEquals(len(zm.zone_states), 0) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertIn(1, zm.zone_states) self.assertEquals(zm.zone_states[1].zone_info['username'], 'user1')
def test_refresh_from_db_add_and_delete(self): zone_state = self._create_zone_state(zone_id=1, username='******') zm = self.zone_manager zm.zone_states[1] = zone_state zone2 = _create_zone(zone_id=2, username='******') self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([zone2]) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertIn(2, zm.zone_states) self.assertEquals(zm.zone_states[2].zone_info['username'], 'user2')
def wrapped_f(*args, **kwargs): collection, context, item_id = \ self.get_collection_context_and_id(args, kwargs) try: # Call the original function ... return f(*args, **kwargs) except exception.InstanceNotFound, e: LOG.debug( _("Instance %(item_id)s not found " "locally: '%(e)s'" % locals())) if not FLAGS.enable_zone_routing: raise zones = db.zone_get_all(context) if not zones: raise # Ask the children to provide an answer ... LOG.debug(_("Asking child zones ...")) result = self._call_child_zones( zones, wrap_novaclient_function(_issue_novaclient_command, collection, self.method_name, item_id)) # Scrub the results and raise another exception # so the API layers can bail out gracefully ... raise RedirectResult(self.unmarshall_result(result))
def wrapped_f(*args, **kwargs): collection, context, item_id = \ self.get_collection_context_and_id(args, kwargs) try: # Call the original function ... return f(*args, **kwargs) except exception.InstanceNotFound, e: LOG.debug(_("Instance %(item_id)s not found " "locally: '%(e)s'" % locals())) if not FLAGS.enable_zone_routing: raise zones = db.zone_get_all(context) if not zones: raise # Ask the children to provide an answer ... LOG.debug(_("Asking child zones ...")) result = self._call_child_zones(zones, wrap_novaclient_function(_issue_novaclient_command, collection, self.method_name, item_id)) # Scrub the results and raise another exception # so the API layers can bail out gracefully ... raise RedirectResult(self.unmarshall_result(result))
def _schedule(self, context, topic, request_spec, *args, **kwargs): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ if topic != "compute": msg = _("Scheduler only understands Compute nodes (for now)") raise NotImplementedError(msg) # Get all available hosts. all_hosts = self.zone_manager.service_states.iteritems() unfiltered_hosts = [(host, services[topic]) for host, services in all_hosts if topic in services] # Filter local hosts based on requirements ... filtered_hosts = self.filter_hosts(topic, request_spec, unfiltered_hosts) # weigh the selected hosts. # weighted_hosts = [{weight=weight, hostname=hostname, # capabilities=capabs}, ...] weighted_hosts = self.weigh_hosts(topic, request_spec, filtered_hosts) # Next, tack on the host weights from the child zones json_spec = json.dumps(request_spec) all_zones = db.zone_get_all(context) child_results = self._call_zone_method(context, "select", specs=json_spec, zones=all_zones) self._adjust_child_weights(child_results, all_zones) for child_zone, result in child_results: for weighting in result: # Remember the child_zone so we can get back to # it later if needed. This implicitly builds a zone # path structure. host_dict = {"weight": weighting["weight"], "child_zone": child_zone, "child_blob": weighting["blob"]} weighted_hosts.append(host_dict) weighted_hosts.sort(key=operator.itemgetter("weight")) return weighted_hosts
def call_zone_method(context, method, errors_to_ignore=None, *args, **kwargs): """Returns a list of (zone, call_result) objects.""" if not isinstance(errors_to_ignore, (list, tuple)): # This will also handle the default None errors_to_ignore = [errors_to_ignore] pool = greenpool.GreenPool() results = [] for zone in db.zone_get_all(context): try: nova = novaclient.OpenStack(zone.username, zone.password, zone.api_url) nova.authenticate() except novaclient.exceptions.BadRequest, e: url = zone.api_url LOG.warn(_("Failed request to zone; URL=%(url)s: %(e)s") % locals()) #TODO (dabo) - add logic for failure counts per zone, # with escalation after a given number of failures. continue zone_method = getattr(nova.zones, method) def _error_trap(*args, **kwargs): try: return zone_method(*args, **kwargs) except Exception as e: if type(e) in errors_to_ignore: return None # TODO (dabo) - want to be able to re-raise here. # Returning a string now; raising was causing issues. # raise e return "ERROR", "%s" % e res = pool.spawn(_error_trap, *args, **kwargs) results.append((zone, res))
def test_refresh_from_db_new(self): zm = zone_manager.ZoneManager() self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([ FakeZone(id=1, api_url='http://foo.com', username='******', password='******'), ]) self.assertEquals(len(zm.zone_states), 0) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertEquals(zm.zone_states[1].username, 'user1')
def get_zone_list(context): """Return a list of zones associated with this zone.""" items = _call_scheduler('get_zone_list', context) for item in items: item['api_url'] = item['api_url'].replace('\\/', '/') if not items: items = db.zone_get_all(context.elevated()) return items
def _schedule(self, context, topic, request_spec, *args, **kwargs): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ if topic != "compute": raise NotImplemented(_("Zone Aware Scheduler only understands " "Compute nodes (for now)")) num_instances = request_spec.get('num_instances', 1) instance_type = request_spec['instance_type'] weighted = [] host_list = None for i in xrange(num_instances): # Filter local hosts based on requirements ... # # The first pass through here will pass 'None' as the # host_list.. which tells the filter to build the full # list of hosts. # On a 2nd pass, the filter can modify the host_list with # any updates it needs to make based on resources that # may have been consumed from a previous build.. host_list = self.filter_hosts(topic, request_spec, host_list) if not host_list: LOG.warn(_("Filter returned no hosts after processing " "%(i)d of %(num_instances)d instances") % locals()) break # then weigh the selected hosts. # weighted = [{weight=weight, hostname=hostname, # capabilities=capabs}, ...] weights = self.weigh_hosts(topic, request_spec, host_list) weights.sort(key=operator.itemgetter('weight')) best_weight = weights[0] weighted.append(best_weight) self.consume_resources(topic, best_weight['capabilities'], instance_type) # Next, tack on the best weights from the child zones ... json_spec = json.dumps(request_spec) all_zones = db.zone_get_all(context) child_results = self._call_zone_method(context, "select", specs=json_spec, zones=all_zones) self._adjust_child_weights(child_results, all_zones) for child_zone, result in child_results: for weighting in result: # Remember the child_zone so we can get back to # it later if needed. This implicitly builds a zone # path structure. host_dict = {"weight": weighting["weight"], "child_zone": child_zone, "child_blob": weighting["blob"]} weighted.append(host_dict) weighted.sort(key=operator.itemgetter('weight')) return weighted
def test_refresh_from_db_missing(self): zm = zone_manager.ZoneManager() zone_state = zone_manager.ZoneState() zone_state.update_credentials(FakeZone(id=1, api_url='http://foo.com', username='******', password='******', name='child', weight_offset=0.0, weight_scale=1.0)) zm.zone_states[1] = zone_state self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([]) self.assertEquals(len(zm.zone_states), 1) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 0)
def test_refresh_from_db_add_and_delete(self): zm = zone_manager.ZoneManager() zone_state = zone_manager.ZoneState() zone_state.update_credentials(FakeZone(id=1, api_url='http://foo.com', username='******', password='******')) zm.zone_states[1] = zone_state self.mox.StubOutWithMock(db, 'zone_get_all') db.zone_get_all(mox.IgnoreArg()).AndReturn([ FakeZone(id=2, api_url='http://foo.com', username='******', password='******'), ]) self.assertEquals(len(zm.zone_states), 1) self.mox.ReplayAll() zm._refresh_from_db(None) self.mox.VerifyAll() self.assertEquals(len(zm.zone_states), 1) self.assertEquals(zm.zone_states[2].username, 'user2')
def index(self, req): """Return all zones in brief""" # Ask the ZoneManager in the Scheduler for most recent data, # or fall-back to the database ... items = api.API().get_zone_list(req.environ['nova.context']) if not items: items = db.zone_get_all(req.environ['nova.context']) items = common.limited(items, req) items = [_exclude_keys(item, ['username', 'password']) for item in items] return dict(zones=items)
def call_zone_method(context, method_name, errors_to_ignore=None, novaclient_collection_name='zones', zones=None, *args, **kwargs): """Returns a list of (zone, call_result) objects.""" if not isinstance(errors_to_ignore, (list, tuple)): # This will also handle the default None errors_to_ignore = [errors_to_ignore] pool = greenpool.GreenPool() results = [] if zones is None: zones = db.zone_get_all(context.elevated()) for zone in zones: try: # Do this on behalf of the user ... nova = novaclient.Client(zone.username, zone.password, None, zone.api_url, region_name=zone.name, token=context.auth_token) nova.authenticate() except novaclient_exceptions.BadRequest, e: url = zone.api_url name = zone.name LOG.warn( _("Authentication failed to zone " "'%(name)s' URL=%(url)s: %(e)s") % locals()) #TODO (dabo) - add logic for failure counts per zone, # with escalation after a given number of failures. continue novaclient_collection = getattr(nova, novaclient_collection_name) collection_method = getattr(novaclient_collection, method_name) def _error_trap(*args, **kwargs): try: return collection_method(*args, **kwargs) except Exception as e: if type(e) in errors_to_ignore: return None raise res = pool.spawn(_error_trap, *args, **kwargs) results.append((zone, res))
def _route_to_child_zones(self, context, collection, item_uuid): if not FLAGS.enable_zone_routing: raise exception.InstanceNotFound(instance_id=item_uuid) zones = db.zone_get_all(context) if not zones: raise exception.InstanceNotFound(instance_id=item_uuid) # Ask the children to provide an answer ... LOG.debug(_("Asking child zones ...")) result = self._call_child_zones(zones, wrap_novaclient_function(_issue_novaclient_command, collection, self.method_name, item_uuid)) # Scrub the results and raise another exception # so the API layers can bail out gracefully ... raise RedirectResult(self.unmarshall_result(result))
def _refresh_from_db(self, context): """Make our zone state map match the db.""" # Add/update existing zones ... zones = db.zone_get_all(context) existing = self.zone_states.keys() db_keys = [] for zone in zones: db_keys.append(zone.id) if zone.id not in existing: self.zone_states[zone.id] = ZoneState() self.zone_states[zone.id].update_credentials(zone) # Cleanup zones removed from db ... keys = self.zone_states.keys() # since we're deleting for zone_id in keys: if zone_id not in db_keys: del self.zone_states[zone_id]
def _route_to_child_zones(self, context, collection, item_uuid): if not FLAGS.enable_zone_routing: raise exception.InstanceNotFound(instance_id=item_uuid) zones = db.zone_get_all(context) if not zones: raise exception.InstanceNotFound(instance_id=item_uuid) # Ask the children to provide an answer ... LOG.debug(_("Asking child zones ...")) result = self._call_child_zones( zones, wrap_novaclient_function(_issue_novaclient_command, collection, self.method_name, item_uuid)) # Scrub the results and raise another exception # so the API layers can bail out gracefully ... raise RedirectResult(self.unmarshall_result(result))
def _schedule(self, context, topic, request_spec, *args, **kwargs): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ if topic != "compute": msg = _("Scheduler only understands Compute nodes (for now)") raise NotImplementedError(msg) # Get all available hosts. all_hosts = self.zone_manager.service_states.iteritems() unfiltered_hosts = [(host, services[topic]) for host, services in all_hosts if topic in services] # Filter local hosts based on requirements ... filtered_hosts = self.filter_hosts(topic, request_spec, unfiltered_hosts) # weigh the selected hosts. # weighted_hosts = [{weight=weight, hostname=hostname, # capabilities=capabs}, ...] weighted_hosts = self.weigh_hosts(topic, request_spec, filtered_hosts) # Next, tack on the host weights from the child zones json_spec = json.dumps(request_spec) all_zones = db.zone_get_all(context) child_results = self._call_zone_method(context, "select", specs=json_spec, zones=all_zones) self._adjust_child_weights(child_results, all_zones) for child_zone, result in child_results: for weighting in result: # Remember the child_zone so we can get back to # it later if needed. This implicitly builds a zone # path structure. host_dict = { "weight": weighting["weight"], "child_zone": child_zone, "child_blob": weighting["blob"] } weighted_hosts.append(host_dict) weighted_hosts.sort(key=operator.itemgetter('weight')) return weighted_hosts
def call_zone_method(context, method_name, errors_to_ignore=None, novaclient_collection_name='zones', zones=None, *args, **kwargs): """Returns a list of (zone, call_result) objects.""" if not isinstance(errors_to_ignore, (list, tuple)): # This will also handle the default None errors_to_ignore = [errors_to_ignore] pool = greenpool.GreenPool() results = [] if zones is None: zones = db.zone_get_all(context.elevated()) for zone in zones: try: # Do this on behalf of the user ... nova = novaclient.Client(zone.username, zone.password, None, zone.api_url, region_name=zone.name, token=context.auth_token) nova.authenticate() except novaclient_exceptions.BadRequest, e: url = zone.api_url name = zone.name LOG.warn(_("Authentication failed to zone " "'%(name)s' URL=%(url)s: %(e)s") % locals()) #TODO (dabo) - add logic for failure counts per zone, # with escalation after a given number of failures. continue novaclient_collection = getattr(nova, novaclient_collection_name) collection_method = getattr(novaclient_collection, method_name) def _error_trap(*args, **kwargs): try: return collection_method(*args, **kwargs) except Exception as e: if type(e) in errors_to_ignore: return None raise res = pool.spawn(_error_trap, *args, **kwargs) results.append((zone, res))
def _zone_get_all(self, context): """Broken out for testing.""" return db.zone_get_all(context)
def index(self, req): """Return all zones in brief""" items = db.zone_get_all(req.environ['nova.context']) items = common.limited(items, req) items = [_scrub_zone(item) for item in items] return dict(zones=items)
def _schedule(self, context, topic, request_spec, *args, **kwargs): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ if topic != "compute": raise NotImplementedError( _("Zone Aware Scheduler only understands" " Compute nodes (for now)")) num_instances = request_spec.get('num_instances', 1) instance_type = request_spec['instance_type'] weighted = [] host_list = None for i in xrange(num_instances): # Filter local hosts based on requirements ... # # The first pass through here will pass 'None' as the # host_list.. which tells the filter to build the full # list of hosts. # On a 2nd pass, the filter can modify the host_list with # any updates it needs to make based on resources that # may have been consumed from a previous build.. host_list = self.filter_hosts(topic, request_spec, host_list) if not host_list: LOG.warn( _("Filter returned no hosts after processing " "%(i)d of %(num_instances)d instances") % locals()) break # then weigh the selected hosts. # weighted = [{weight=weight, hostname=hostname, # capabilities=capabs}, ...] weights = self.weigh_hosts(topic, request_spec, host_list) weights.sort(key=operator.itemgetter('weight')) best_weight = weights[0] weighted.append(best_weight) self.consume_resources(topic, best_weight['capabilities'], instance_type) # Next, tack on the best weights from the child zones ... json_spec = json.dumps(request_spec) all_zones = db.zone_get_all(context) child_results = self._call_zone_method(context, "select", specs=json_spec, zones=all_zones) self._adjust_child_weights(child_results, all_zones) for child_zone, result in child_results: for weighting in result: # Remember the child_zone so we can get back to # it later if needed. This implicitly builds a zone # path structure. host_dict = { "weight": weighting["weight"], "child_zone": child_zone, "child_blob": weighting["blob"] } weighted.append(host_dict) weighted.sort(key=operator.itemgetter('weight')) return weighted