Merged with trunk
Fixed testing instrastructure: - stubbed out LoopingCall.start - unstubbed db.instance_create - now using fake context in spawn tests - moved fake xenstore ops into fake driver to avoid code duplication Fixed pep8 errors
This commit is contained in:
		| @@ -356,3 +356,7 @@ DEFINE_string('host', socket.gethostname(), | ||||
|  | ||||
| DEFINE_string('node_availability_zone', 'nova', | ||||
|               'availability zone of this node') | ||||
|  | ||||
| DEFINE_string('zone_name', 'nova', 'name of this zone') | ||||
| DEFINE_string('zone_capabilities', 'kypervisor:xenserver;os:linux', | ||||
|               'Key/Value tags which represent capabilities of this zone') | ||||
|   | ||||
							
								
								
									
										49
									
								
								nova/scheduler/api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								nova/scheduler/api.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| # Copyright (c) 2011 Openstack, LLC. | ||||
| # All Rights Reserved. | ||||
| # | ||||
| #    Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #    not use this file except in compliance with the License. You may obtain | ||||
| #    a copy of the License at | ||||
| # | ||||
| #         http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #    Unless required by applicable law or agreed to in writing, software | ||||
| #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| """ | ||||
| Handles all requests relating to schedulers. | ||||
| """ | ||||
|  | ||||
| from nova import flags | ||||
| from nova import log as logging | ||||
| from nova import rpc | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| LOG = logging.getLogger('nova.scheduler.api') | ||||
|  | ||||
|  | ||||
| class API(object): | ||||
|     """API for interacting with the scheduler.""" | ||||
|  | ||||
|     def _call_scheduler(self, method, context, params=None): | ||||
|         """Generic handler for RPC calls to the scheduler. | ||||
|  | ||||
|         :param params: Optional dictionary of arguments to be passed to the | ||||
|                        scheduler worker | ||||
|  | ||||
|         :retval: Result returned by scheduler worker | ||||
|         """ | ||||
|         if not params: | ||||
|             params = {} | ||||
|         queue = FLAGS.scheduler_topic | ||||
|         kwargs = {'method': method, 'args': params} | ||||
|         return rpc.call(context, queue, kwargs) | ||||
|  | ||||
|     def get_zone_list(self, context): | ||||
|         items = self._call_scheduler('get_zone_list', context) | ||||
|         for item in items: | ||||
|             item['api_url'] = item['api_url'].replace('\\/', '/') | ||||
|         return items | ||||
| @@ -29,6 +29,7 @@ from nova import log as logging | ||||
| from nova import manager | ||||
| from nova import rpc | ||||
| from nova import utils | ||||
| from nova.scheduler import zone_manager | ||||
|  | ||||
| LOG = logging.getLogger('nova.scheduler.manager') | ||||
| FLAGS = flags.FLAGS | ||||
| @@ -43,12 +44,21 @@ class SchedulerManager(manager.Manager): | ||||
|         if not scheduler_driver: | ||||
|             scheduler_driver = FLAGS.scheduler_driver | ||||
|         self.driver = utils.import_object(scheduler_driver) | ||||
|         self.zone_manager = zone_manager.ZoneManager() | ||||
|         super(SchedulerManager, self).__init__(*args, **kwargs) | ||||
|  | ||||
|     def __getattr__(self, key): | ||||
|         """Converts all method calls to use the schedule method""" | ||||
|         return functools.partial(self._schedule, key) | ||||
|  | ||||
|     def periodic_tasks(self, context=None): | ||||
|         """Poll child zones periodically to get status.""" | ||||
|         self.zone_manager.ping(context) | ||||
|  | ||||
|     def get_zone_list(self, context=None): | ||||
|         """Get a list of zones from the ZoneManager.""" | ||||
|         return self.zone_manager.get_zone_list() | ||||
|  | ||||
|     def _schedule(self, method, context, topic, *args, **kwargs): | ||||
|         """Tries to call schedule_* method on the driver to retrieve host. | ||||
|  | ||||
|   | ||||
							
								
								
									
										143
									
								
								nova/scheduler/zone_manager.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								nova/scheduler/zone_manager.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| # Copyright (c) 2011 Openstack, LLC. | ||||
| # All Rights Reserved. | ||||
| # | ||||
| #    Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #    not use this file except in compliance with the License. You may obtain | ||||
| #    a copy of the License at | ||||
| # | ||||
| #         http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #    Unless required by applicable law or agreed to in writing, software | ||||
| #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| """ | ||||
| ZoneManager oversees all communications with child Zones. | ||||
| """ | ||||
|  | ||||
| import novaclient | ||||
| import thread | ||||
| import traceback | ||||
|  | ||||
| from datetime import datetime | ||||
| from eventlet import greenpool | ||||
|  | ||||
| from nova import db | ||||
| from nova import flags | ||||
| from nova import log as logging | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| flags.DEFINE_integer('zone_db_check_interval', 60, | ||||
|                     'Seconds between getting fresh zone info from db.') | ||||
| flags.DEFINE_integer('zone_failures_to_offline', 3, | ||||
|              'Number of consecutive errors before marking zone offline') | ||||
|  | ||||
|  | ||||
| class ZoneState(object): | ||||
|     """Holds the state of all connected child zones.""" | ||||
|     def __init__(self): | ||||
|         self.is_active = True | ||||
|         self.name = None | ||||
|         self.capabilities = None | ||||
|         self.attempt = 0 | ||||
|         self.last_seen = datetime.min | ||||
|         self.last_exception = None | ||||
|         self.last_exception_time = None | ||||
|  | ||||
|     def update_credentials(self, zone): | ||||
|         """Update zone credentials from db""" | ||||
|         self.zone_id = zone.id | ||||
|         self.api_url = zone.api_url | ||||
|         self.username = zone.username | ||||
|         self.password = zone.password | ||||
|  | ||||
|     def update_metadata(self, zone_metadata): | ||||
|         """Update zone metadata after successful communications with | ||||
|            child zone.""" | ||||
|         self.last_seen = datetime.now() | ||||
|         self.attempt = 0 | ||||
|         self.name = zone_metadata["name"] | ||||
|         self.capabilities = zone_metadata["capabilities"] | ||||
|         self.is_active = True | ||||
|  | ||||
|     def to_dict(self): | ||||
|         return dict(name=self.name, capabilities=self.capabilities, | ||||
|                     is_active=self.is_active, api_url=self.api_url, | ||||
|                     id=self.zone_id) | ||||
|  | ||||
|     def log_error(self, exception): | ||||
|         """Something went wrong. Check to see if zone should be | ||||
|            marked as offline.""" | ||||
|         self.last_exception = exception | ||||
|         self.last_exception_time = datetime.now() | ||||
|         api_url = self.api_url | ||||
|         logging.warning(_("'%(exception)s' error talking to " | ||||
|                           "zone %(api_url)s") % locals()) | ||||
|  | ||||
|         max_errors = FLAGS.zone_failures_to_offline | ||||
|         self.attempt += 1 | ||||
|         if self.attempt >= max_errors: | ||||
|             self.is_active = False | ||||
|             logging.error(_("No answer from zone %(api_url)s " | ||||
|                             "after %(max_errors)d " | ||||
|                             "attempts. Marking inactive.") % locals()) | ||||
|  | ||||
|  | ||||
| def _call_novaclient(zone): | ||||
|     """Call novaclient. Broken out for testing purposes.""" | ||||
|     client = novaclient.OpenStack(zone.username, zone.password, zone.api_url) | ||||
|     return client.zones.info()._info | ||||
|  | ||||
|  | ||||
| def _poll_zone(zone): | ||||
|     """Eventlet worker to poll a zone.""" | ||||
|     logging.debug(_("Polling zone: %s") % zone.api_url) | ||||
|     try: | ||||
|         zone.update_metadata(_call_novaclient(zone)) | ||||
|     except Exception, e: | ||||
|         zone.log_error(traceback.format_exc()) | ||||
|  | ||||
|  | ||||
| class ZoneManager(object): | ||||
|     """Keeps the zone states updated.""" | ||||
|     def __init__(self): | ||||
|         self.last_zone_db_check = datetime.min | ||||
|         self.zone_states = {} | ||||
|         self.green_pool = greenpool.GreenPool() | ||||
|  | ||||
|     def get_zone_list(self): | ||||
|         """Return the list of zones we know about.""" | ||||
|         return [zone.to_dict() for zone in self.zone_states.values()] | ||||
|  | ||||
|     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 _poll_zones(self, context): | ||||
|         """Try to connect to each child zone and get update.""" | ||||
|         self.green_pool.imap(_poll_zone, self.zone_states.values()) | ||||
|  | ||||
|     def ping(self, context=None): | ||||
|         """Ping should be called periodically to update zone status.""" | ||||
|         diff = datetime.now() - self.last_zone_db_check | ||||
|         if diff.seconds >= FLAGS.zone_db_check_interval: | ||||
|             logging.debug(_("Updating zone cache from db.")) | ||||
|             self.last_zone_db_check = datetime.now() | ||||
|             self._refresh_from_db(context) | ||||
|         self._poll_zones(context) | ||||
| @@ -29,11 +29,153 @@ from nova import log as logging | ||||
| from nova import test | ||||
| from nova import utils | ||||
| from nova.auth import manager | ||||
| from nova.network import linux_net | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| LOG = logging.getLogger('nova.tests.network') | ||||
|  | ||||
|  | ||||
| class IptablesManagerTestCase(test.TestCase): | ||||
|     sample_filter = ['#Generated by iptables-save on Fri Feb 18 15:17:05 2011', | ||||
|                      '*filter', | ||||
|                      ':INPUT ACCEPT [2223527:305688874]', | ||||
|                      ':FORWARD ACCEPT [0:0]', | ||||
|                      ':OUTPUT ACCEPT [2172501:140856656]', | ||||
|                      ':nova-compute-FORWARD - [0:0]', | ||||
|                      ':nova-compute-INPUT - [0:0]', | ||||
|                      ':nova-compute-local - [0:0]', | ||||
|                      ':nova-compute-OUTPUT - [0:0]', | ||||
|                      ':nova-filter-top - [0:0]', | ||||
|                      '-A FORWARD -j nova-filter-top ', | ||||
|                      '-A OUTPUT -j nova-filter-top ', | ||||
|                      '-A nova-filter-top -j nova-compute-local ', | ||||
|                      '-A INPUT -j nova-compute-INPUT ', | ||||
|                      '-A OUTPUT -j nova-compute-OUTPUT ', | ||||
|                      '-A FORWARD -j nova-compute-FORWARD ', | ||||
|                      '-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT ', | ||||
|                      '-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT ', | ||||
|                      '-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT ', | ||||
|                      '-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ', | ||||
|                      '-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT ', | ||||
|                      '-A FORWARD -i virbr0 -o virbr0 -j ACCEPT ', | ||||
|                      '-A FORWARD -o virbr0 -j REJECT --reject-with ' | ||||
|                      'icmp-port-unreachable ', | ||||
|                      '-A FORWARD -i virbr0 -j REJECT --reject-with ' | ||||
|                      'icmp-port-unreachable ', | ||||
|                      'COMMIT', | ||||
|                      '# Completed on Fri Feb 18 15:17:05 2011'] | ||||
|  | ||||
|     sample_nat = ['# Generated by iptables-save on Fri Feb 18 15:17:05 2011', | ||||
|                   '*nat', | ||||
|                   ':PREROUTING ACCEPT [3936:762355]', | ||||
|                   ':INPUT ACCEPT [2447:225266]', | ||||
|                   ':OUTPUT ACCEPT [63491:4191863]', | ||||
|                   ':POSTROUTING ACCEPT [63112:4108641]', | ||||
|                   ':nova-compute-OUTPUT - [0:0]', | ||||
|                   ':nova-compute-floating-ip-snat - [0:0]', | ||||
|                   ':nova-compute-SNATTING - [0:0]', | ||||
|                   ':nova-compute-PREROUTING - [0:0]', | ||||
|                   ':nova-compute-POSTROUTING - [0:0]', | ||||
|                   ':nova-postrouting-bottom - [0:0]', | ||||
|                   '-A PREROUTING -j nova-compute-PREROUTING ', | ||||
|                   '-A OUTPUT -j nova-compute-OUTPUT ', | ||||
|                   '-A POSTROUTING -j nova-compute-POSTROUTING ', | ||||
|                   '-A POSTROUTING -j nova-postrouting-bottom ', | ||||
|                   '-A nova-postrouting-bottom -j nova-compute-SNATTING ', | ||||
|                   '-A nova-compute-SNATTING -j nova-compute-floating-ip-snat ', | ||||
|                   'COMMIT', | ||||
|                   '# Completed on Fri Feb 18 15:17:05 2011'] | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(IptablesManagerTestCase, self).setUp() | ||||
|         self.manager = linux_net.IptablesManager() | ||||
|  | ||||
|     def test_filter_rules_are_wrapped(self): | ||||
|         current_lines = self.sample_filter | ||||
|  | ||||
|         table = self.manager.ipv4['filter'] | ||||
|         table.add_rule('FORWARD', '-s 1.2.3.4/5 -j DROP') | ||||
|         new_lines = self.manager._modify_rules(current_lines, table) | ||||
|         self.assertTrue('-A run_tests.py-FORWARD ' | ||||
|                         '-s 1.2.3.4/5 -j DROP' in new_lines) | ||||
|  | ||||
|         table.remove_rule('FORWARD', '-s 1.2.3.4/5 -j DROP') | ||||
|         new_lines = self.manager._modify_rules(current_lines, table) | ||||
|         self.assertTrue('-A run_tests.py-FORWARD ' | ||||
|                         '-s 1.2.3.4/5 -j DROP' not in new_lines) | ||||
|  | ||||
|     def test_nat_rules(self): | ||||
|         current_lines = self.sample_nat | ||||
|         new_lines = self.manager._modify_rules(current_lines, | ||||
|                                                self.manager.ipv4['nat']) | ||||
|  | ||||
|         for line in [':nova-compute-OUTPUT - [0:0]', | ||||
|                      ':nova-compute-floating-ip-snat - [0:0]', | ||||
|                      ':nova-compute-SNATTING - [0:0]', | ||||
|                      ':nova-compute-PREROUTING - [0:0]', | ||||
|                      ':nova-compute-POSTROUTING - [0:0]']: | ||||
|             self.assertTrue(line in new_lines, "One of nova-compute's chains " | ||||
|                                                "went missing.") | ||||
|  | ||||
|         seen_lines = set() | ||||
|         for line in new_lines: | ||||
|             line = line.strip() | ||||
|             self.assertTrue(line not in seen_lines, | ||||
|                             "Duplicate line: %s" % line) | ||||
|             seen_lines.add(line) | ||||
|  | ||||
|         last_postrouting_line = '' | ||||
|  | ||||
|         for line in new_lines: | ||||
|             if line.startswith('-A POSTROUTING'): | ||||
|                 last_postrouting_line = line | ||||
|  | ||||
|         self.assertTrue('-j nova-postrouting-bottom' in last_postrouting_line, | ||||
|                         "Last POSTROUTING rule does not jump to " | ||||
|                         "nova-postouting-bottom: %s" % last_postrouting_line) | ||||
|  | ||||
|         for chain in ['POSTROUTING', 'PREROUTING', 'OUTPUT']: | ||||
|             self.assertTrue('-A %s -j run_tests.py-%s' \ | ||||
|                             % (chain, chain) in new_lines, | ||||
|                             "Built-in chain %s not wrapped" % (chain,)) | ||||
|  | ||||
|     def test_filter_rules(self): | ||||
|         current_lines = self.sample_filter | ||||
|         new_lines = self.manager._modify_rules(current_lines, | ||||
|                                                self.manager.ipv4['filter']) | ||||
|  | ||||
|         for line in [':nova-compute-FORWARD - [0:0]', | ||||
|                      ':nova-compute-INPUT - [0:0]', | ||||
|                      ':nova-compute-local - [0:0]', | ||||
|                      ':nova-compute-OUTPUT - [0:0]']: | ||||
|             self.assertTrue(line in new_lines, "One of nova-compute's chains" | ||||
|                                                " went missing.") | ||||
|  | ||||
|         seen_lines = set() | ||||
|         for line in new_lines: | ||||
|             line = line.strip() | ||||
|             self.assertTrue(line not in seen_lines, | ||||
|                             "Duplicate line: %s" % line) | ||||
|             seen_lines.add(line) | ||||
|  | ||||
|         for chain in ['FORWARD', 'OUTPUT']: | ||||
|             for line in new_lines: | ||||
|                 if line.startswith('-A %s' % chain): | ||||
|                     self.assertTrue('-j nova-filter-top' in line, | ||||
|                                     "First %s rule does not " | ||||
|                                     "jump to nova-filter-top" % chain) | ||||
|                     break | ||||
|  | ||||
|         self.assertTrue('-A nova-filter-top ' | ||||
|                         '-j run_tests.py-local' in new_lines, | ||||
|                         "nova-filter-top does not jump to wrapped local chain") | ||||
|  | ||||
|         for chain in ['INPUT', 'OUTPUT', 'FORWARD']: | ||||
|             self.assertTrue('-A %s -j run_tests.py-%s' \ | ||||
|                             % (chain, chain) in new_lines, | ||||
|                             "Built-in chain %s not wrapped" % (chain,)) | ||||
|  | ||||
|  | ||||
| class NetworkTestCase(test.TestCase): | ||||
|     """Test cases for network code""" | ||||
|     def setUp(self): | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| import re | ||||
| import os | ||||
|  | ||||
| import eventlet | ||||
| @@ -301,16 +302,22 @@ class IptablesFirewallTestCase(test.TestCase): | ||||
|         self.manager.delete_user(self.user) | ||||
|         super(IptablesFirewallTestCase, self).tearDown() | ||||
|  | ||||
|     in_rules = [ | ||||
|     in_nat_rules = [ | ||||
|       '# Generated by iptables-save v1.4.10 on Sat Feb 19 00:03:19 2011', | ||||
|       '*nat', | ||||
|       ':PREROUTING ACCEPT [1170:189210]', | ||||
|       ':INPUT ACCEPT [844:71028]', | ||||
|       ':OUTPUT ACCEPT [5149:405186]', | ||||
|       ':POSTROUTING ACCEPT [5063:386098]', | ||||
|     ] | ||||
|  | ||||
|     in_filter_rules = [ | ||||
|       '# Generated by iptables-save v1.4.4 on Mon Dec  6 11:54:13 2010', | ||||
|       '*filter', | ||||
|       ':INPUT ACCEPT [969615:281627771]', | ||||
|       ':FORWARD ACCEPT [0:0]', | ||||
|       ':OUTPUT ACCEPT [915599:63811649]', | ||||
|       ':nova-block-ipv4 - [0:0]', | ||||
|       '-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT ', | ||||
|       '-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT ', | ||||
|       '-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT ', | ||||
|       '-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ', | ||||
|       '-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED' | ||||
|       ',ESTABLISHED -j ACCEPT ', | ||||
| @@ -322,7 +329,7 @@ class IptablesFirewallTestCase(test.TestCase): | ||||
|       '# Completed on Mon Dec  6 11:54:13 2010', | ||||
|     ] | ||||
|  | ||||
|     in6_rules = [ | ||||
|     in6_filter_rules = [ | ||||
|       '# Generated by ip6tables-save v1.4.4 on Tue Jan 18 23:47:56 2011', | ||||
|       '*filter', | ||||
|       ':INPUT ACCEPT [349155:75810423]', | ||||
| @@ -385,21 +392,31 @@ class IptablesFirewallTestCase(test.TestCase): | ||||
|         def fake_iptables_execute(*cmd, **kwargs): | ||||
|             process_input = kwargs.get('process_input', None) | ||||
|             if cmd == ('sudo', 'ip6tables-save', '-t', 'filter'): | ||||
|                 return '\n'.join(self.in6_rules), None | ||||
|                 return '\n'.join(self.in6_filter_rules), None | ||||
|             if cmd == ('sudo', 'iptables-save', '-t', 'filter'): | ||||
|                 return '\n'.join(self.in_rules), None | ||||
|                 return '\n'.join(self.in_filter_rules), None | ||||
|             if cmd == ('sudo', 'iptables-save', '-t', 'nat'): | ||||
|                 return '\n'.join(self.in_nat_rules), None | ||||
|             if cmd == ('sudo', 'iptables-restore'): | ||||
|                 self.out_rules = process_input.split('\n') | ||||
|                 lines = process_input.split('\n') | ||||
|                 if '*filter' in lines: | ||||
|                     self.out_rules = lines | ||||
|                 return '', '' | ||||
|             if cmd == ('sudo', 'ip6tables-restore'): | ||||
|                 self.out6_rules = process_input.split('\n') | ||||
|                 lines = process_input.split('\n') | ||||
|                 if '*filter' in lines: | ||||
|                     self.out6_rules = lines | ||||
|                 return '', '' | ||||
|         self.fw.execute = fake_iptables_execute | ||||
|             print cmd, kwargs | ||||
|  | ||||
|         from nova.network import linux_net | ||||
|         linux_net.iptables_manager.execute = fake_iptables_execute | ||||
|  | ||||
|         self.fw.prepare_instance_filter(instance_ref) | ||||
|         self.fw.apply_instance_filter(instance_ref) | ||||
|  | ||||
|         in_rules = filter(lambda l: not l.startswith('#'), self.in_rules) | ||||
|         in_rules = filter(lambda l: not l.startswith('#'), | ||||
|                           self.in_filter_rules) | ||||
|         for rule in in_rules: | ||||
|             if not 'nova' in rule: | ||||
|                 self.assertTrue(rule in self.out_rules, | ||||
| @@ -422,17 +439,18 @@ class IptablesFirewallTestCase(test.TestCase): | ||||
|         self.assertTrue(security_group_chain, | ||||
|                         "The security group chain wasn't added") | ||||
|  | ||||
|         self.assertTrue('-A %s -p icmp -s 192.168.11.0/24 -j ACCEPT' % \ | ||||
|                                security_group_chain in self.out_rules, | ||||
|         regex = re.compile('-A .* -p icmp -s 192.168.11.0/24 -j ACCEPT') | ||||
|         self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, | ||||
|                         "ICMP acceptance rule wasn't added") | ||||
|  | ||||
|         self.assertTrue('-A %s -p icmp -s 192.168.11.0/24 -m icmp --icmp-type ' | ||||
|                         '8 -j ACCEPT' % security_group_chain in self.out_rules, | ||||
|         regex = re.compile('-A .* -p icmp -s 192.168.11.0/24 -m icmp ' | ||||
|                            '--icmp-type 8 -j ACCEPT') | ||||
|         self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, | ||||
|                         "ICMP Echo Request acceptance rule wasn't added") | ||||
|  | ||||
|         self.assertTrue('-A %s -p tcp -s 192.168.10.0/24 -m multiport ' | ||||
|                         '--dports 80:81 -j ACCEPT' % security_group_chain \ | ||||
|                             in self.out_rules, | ||||
|         regex = re.compile('-A .* -p tcp -s 192.168.10.0/24 -m multiport ' | ||||
|                            '--dports 80:81 -j ACCEPT') | ||||
|         self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, | ||||
|                         "TCP port 80/81 acceptance rule wasn't added") | ||||
|         db.instance_destroy(admin_ctxt, instance_ref['id']) | ||||
|  | ||||
|   | ||||
| @@ -55,6 +55,7 @@ class XenAPIVolumeTestCase(test.TestCase): | ||||
|     def setUp(self): | ||||
|         super(XenAPIVolumeTestCase, self).setUp() | ||||
|         self.stubs = stubout.StubOutForTesting() | ||||
|         self.context = context.RequestContext('fake', 'fake', False) | ||||
|         FLAGS.target_host = '127.0.0.1' | ||||
|         FLAGS.xenapi_connection_url = 'test_url' | ||||
|         FLAGS.xenapi_connection_password = 'test_pass' | ||||
| @@ -62,7 +63,7 @@ class XenAPIVolumeTestCase(test.TestCase): | ||||
|         #db_fakes.stub_out_db_network_api(self.stubs) | ||||
|         stubs.stub_out_get_target(self.stubs) | ||||
|         xenapi_fake.reset() | ||||
|         self.values = {'name': 1, 'id': 1, | ||||
|         self.values = {'id': 1, | ||||
|                   'project_id': 'fake', | ||||
|                   'user_id': 'fake', | ||||
|                   'image_id': 1, | ||||
| @@ -82,7 +83,7 @@ class XenAPIVolumeTestCase(test.TestCase): | ||||
|         vol['availability_zone'] = FLAGS.storage_availability_zone | ||||
|         vol['status'] = "creating" | ||||
|         vol['attach_status'] = "detached" | ||||
|         return db.volume_create(context.get_admin_context(), vol) | ||||
|         return db.volume_create(self.context, vol) | ||||
|  | ||||
|     def test_create_iscsi_storage(self): | ||||
|         """ This shows how to test helper classes' methods """ | ||||
| @@ -118,7 +119,7 @@ class XenAPIVolumeTestCase(test.TestCase): | ||||
|         stubs.stubout_session(self.stubs, stubs.FakeSessionForVolumeTests) | ||||
|         conn = xenapi_conn.get_connection(False) | ||||
|         volume = self._create_volume() | ||||
|         instance = db.instance_create(self.values) | ||||
|         instance = db.instance_create(self.context, self.values) | ||||
|         vm = xenapi_fake.create_vm(instance.name, 'Running') | ||||
|         result = conn.attach_volume(instance.name, volume['id'], '/dev/sdc') | ||||
|  | ||||
| @@ -138,7 +139,7 @@ class XenAPIVolumeTestCase(test.TestCase): | ||||
|                               stubs.FakeSessionForVolumeFailedTests) | ||||
|         conn = xenapi_conn.get_connection(False) | ||||
|         volume = self._create_volume() | ||||
|         instance = db.instance_create(self.values) | ||||
|         instance = db.instance_create(self.context, self.values) | ||||
|         xenapi_fake.create_vm(instance.name, 'Running') | ||||
|         self.assertRaises(Exception, | ||||
|                           conn.attach_volume, | ||||
| @@ -167,12 +168,12 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|         self.project = self.manager.create_project('fake', 'fake', 'fake') | ||||
|         self.network = utils.import_object(FLAGS.network_manager) | ||||
|         self.stubs = stubout.StubOutForTesting() | ||||
|         FLAGS.xenapi_connection_url = 'test_url' | ||||
|         FLAGS.xenapi_connection_password = 'test_pass' | ||||
|         self.flags(xenapi_connection_url='test_url', | ||||
|                    xenapi_connection_password='test_pass', | ||||
|                    instance_name_template='%d') | ||||
|         xenapi_fake.reset() | ||||
|         xenapi_fake.create_local_srs() | ||||
|         db_fakes.stub_out_db_instance_api(self.stubs) | ||||
|         #db_fakes.stub_out_db_network_api(self.stubs) | ||||
|         xenapi_fake.create_network('fake', FLAGS.flat_network_bridge) | ||||
|         stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) | ||||
|         stubs.stubout_get_this_vm_uuid(self.stubs) | ||||
| @@ -182,6 +183,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|         glance_stubs.stubout_glance_client(self.stubs, | ||||
|                                            glance_stubs.FakeGlance) | ||||
|         fake_utils.stub_out_utils_execute(self.stubs) | ||||
|         self.context = context.RequestContext('fake', 'fake', False) | ||||
|         self.conn = xenapi_conn.get_connection(False) | ||||
|  | ||||
|     def test_list_instances_0(self): | ||||
| @@ -235,8 +237,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|  | ||||
|         # Get Nova record for VM | ||||
|         vm_info = conn.get_info('1') | ||||
|  | ||||
|         # Get XenAPI record for VM | ||||
|        # Get XenAPI record for VM | ||||
|         vms = [(ref, rec) for ref, rec | ||||
|                in xenapi_fake.get_all_records('VM').iteritems() | ||||
|                if not rec['is_control_domain']] | ||||
| @@ -262,7 +263,8 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|         self.assertEquals(vm['power_state'], 'Running') | ||||
|  | ||||
|         if check_injection: | ||||
|             xenstore_data = xenapi_fake.VM_get_xenstore_data(vm_ref) | ||||
|             session = xenapi_conn.XenAPISession('fake', 'fake', 'fake') | ||||
|             xenstore_data = session.call_xenapi('VM.get_xenstore_data', vm_ref) | ||||
|             key = 'vm-data/networking/aabbccddeeff' | ||||
|             xenstore_value = xenstore_data[key] | ||||
|             tcpip_data = ast.literal_eval(xenstore_value) | ||||
| @@ -282,10 +284,8 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|  | ||||
|     def _test_spawn(self, image_id, kernel_id, ramdisk_id, | ||||
|         instance_type="m1.large", check_injection=False): | ||||
|  | ||||
|         stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) | ||||
|         values = {'name': "1", | ||||
|                   'id': "1", | ||||
|         stubs.stubout_loopingcall_start(self.stubs) | ||||
|         values = {'id': 1, | ||||
|                   'project_id': self.project.id, | ||||
|                   'user_id': self.user.id, | ||||
|                   'image_id': image_id, | ||||
| @@ -294,10 +294,9 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|                   'instance_type': instance_type, | ||||
|                   'mac_address': 'aa:bb:cc:dd:ee:ff', | ||||
|                   } | ||||
|         conn = xenapi_conn.get_connection(False) | ||||
|         instance = db.instance_create(values) | ||||
|         conn.spawn(instance) | ||||
|         self.check_vm_record(conn, check_injection=check_injection) | ||||
|         instance = db.instance_create(self.context, values) | ||||
|         self.conn.spawn(instance) | ||||
|         self.check_vm_record(self.conn, check_injection=check_injection) | ||||
|  | ||||
|     def test_spawn_not_enough_memory(self): | ||||
|         FLAGS.xenapi_image_service = 'glance' | ||||
| @@ -333,14 +332,12 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|  | ||||
|         self._tee_executed = False | ||||
|  | ||||
|         def _tee_handler(cmd, input, *ignore_args): | ||||
|         def _tee_handler(cmd, **kwargs): | ||||
|             input = kwargs.get('process_input', None) | ||||
|             self.assertNotEqual(input, None) | ||||
|  | ||||
|             config = [line.strip() for line in input.split("\n")] | ||||
|  | ||||
|             # Find the start of eth0 configuration and check it | ||||
|             index = config.index('auto eth0') | ||||
|  | ||||
|             self.assertEquals(config[index + 1:index + 8], [ | ||||
|                 'iface eth0 inet static', | ||||
|                 'address 10.0.0.3', | ||||
| @@ -349,9 +346,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|                 'gateway 10.0.0.1', | ||||
|                 'dns-nameservers 10.0.0.2', | ||||
|                 '']) | ||||
|  | ||||
|             self._tee_executed = True | ||||
|  | ||||
|             return '', '' | ||||
|  | ||||
|         fake_utils.fake_execute_set_repliers([ | ||||
| @@ -371,12 +366,14 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|  | ||||
|         self._tee_executed = False | ||||
|  | ||||
|         def _mount_handler(cmd, *ignore_args): | ||||
|         def _mount_handler(cmd, *ignore_args, **ignore_kwargs): | ||||
|             # When mounting, create real files under the mountpoint to simulate | ||||
|             # files in the mounted filesystem | ||||
|  | ||||
|             # RegExp extracts the path of the mountpoint | ||||
|             match = re.match(r'(sudo\s+)?mount[^"]*"[^"]*"\s+"([^"]*)"', cmd) | ||||
|             cmd_str = ' '.join(cmd) | ||||
|             match = re.match(r'(sudo\s+)?mount[^"]*"[^"]*"\s+"([^"]*)"', | ||||
|                              cmd_str) | ||||
|             self._tmpdir = match.group(2) | ||||
|             LOG.debug(_('Creating files in %s to simulate guest agent' % | ||||
|                 self._tmpdir)) | ||||
| @@ -386,7 +383,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|                 'xe-update-networking'), 'w').close() | ||||
|             return '', '' | ||||
|  | ||||
|         def _umount_handler(cmd, *ignore_args): | ||||
|         def _umount_handler(cmd, *ignore_args, **ignore_kwargs): | ||||
|             # Umount would normall make files in the m,ounted filesystem | ||||
|             # disappear, so do that here | ||||
|             LOG.debug(_('Removing simulated guest agent files in %s' % | ||||
| @@ -397,7 +394,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|             os.rmdir(os.path.join(self._tmpdir, 'usr')) | ||||
|             return '', '' | ||||
|  | ||||
|         def _tee_handler(cmd, input, *ignore_args): | ||||
|         def _tee_handler(cmd, *ignore_args, **ignore_kwargs): | ||||
|             self._tee_executed = True | ||||
|             return '', '' | ||||
|  | ||||
| @@ -419,9 +416,9 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|  | ||||
|     def _create_instance(self): | ||||
|         """Creates and spawns a test instance""" | ||||
|         stubs.stubout_loopingcall_start(self.stubs) | ||||
|         values = { | ||||
|             'name': '1', | ||||
|             'id': '1', | ||||
|             'id': 1, | ||||
|             'project_id': self.project.id, | ||||
|             'user_id': self.user.id, | ||||
|             'image_id': 1, | ||||
| @@ -429,7 +426,7 @@ class XenAPIVMTestCase(test.TestCase): | ||||
|             'ramdisk_id': 3, | ||||
|             'instance_type': 'm1.large', | ||||
|             'mac_address': 'aa:bb:cc:dd:ee:ff'} | ||||
|         instance = db.instance_create(values) | ||||
|         instance = db.instance_create(self.context, values) | ||||
|         self.conn.spawn(instance) | ||||
|         return instance | ||||
|  | ||||
| @@ -474,11 +471,13 @@ class XenAPIMigrateInstance(test.TestCase): | ||||
|         db_fakes.stub_out_db_instance_api(self.stubs) | ||||
|         stubs.stub_out_get_target(self.stubs) | ||||
|         xenapi_fake.reset() | ||||
|         xenapi_fake.create_network('fake', FLAGS.flat_network_bridge) | ||||
|         self.manager = manager.AuthManager() | ||||
|         self.user = self.manager.create_user('fake', 'fake', 'fake', | ||||
|                                              admin=True) | ||||
|         self.project = self.manager.create_project('fake', 'fake', 'fake') | ||||
|         self.values = {'name': 1, 'id': 1, | ||||
|         self.context = context.RequestContext('fake', 'fake', False) | ||||
|         self.values = {'id': 1, | ||||
|                   'project_id': self.project.id, | ||||
|                   'user_id': self.user.id, | ||||
|                   'image_id': 1, | ||||
| @@ -488,6 +487,7 @@ class XenAPIMigrateInstance(test.TestCase): | ||||
|                   'mac_address': 'aa:bb:cc:dd:ee:ff', | ||||
|                   } | ||||
|         stubs.stub_out_migration_methods(self.stubs) | ||||
|         stubs.stubout_get_this_vm_uuid(self.stubs) | ||||
|         glance_stubs.stubout_glance_client(self.stubs, | ||||
|                                            glance_stubs.FakeGlance) | ||||
|  | ||||
| @@ -498,14 +498,15 @@ class XenAPIMigrateInstance(test.TestCase): | ||||
|         self.stubs.UnsetAll() | ||||
|  | ||||
|     def test_migrate_disk_and_power_off(self): | ||||
|         instance = db.instance_create(self.values) | ||||
|         instance = db.instance_create(self.context, self.values) | ||||
|         stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) | ||||
|         conn = xenapi_conn.get_connection(False) | ||||
|         conn.migrate_disk_and_power_off(instance, '127.0.0.1') | ||||
|  | ||||
|     def test_finish_resize(self): | ||||
|         instance = db.instance_create(self.values) | ||||
|         instance = db.instance_create(self.context, self.values) | ||||
|         stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) | ||||
|         stubs.stubout_loopingcall_start(self.stubs) | ||||
|         conn = xenapi_conn.get_connection(False) | ||||
|         conn.finish_resize(instance, dict(base_copy='hurr', cow='durr')) | ||||
|  | ||||
|   | ||||
							
								
								
									
										172
									
								
								nova/tests/test_zones.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								nova/tests/test_zones.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| # Copyright 2010 United States Government as represented by the | ||||
| # All Rights Reserved. | ||||
| # | ||||
| #    Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #    not use this file except in compliance with the License. You may obtain | ||||
| #    a copy of the License at | ||||
| # | ||||
| #         http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #    Unless required by applicable law or agreed to in writing, software | ||||
| #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
| """ | ||||
| Tests For ZoneManager | ||||
| """ | ||||
|  | ||||
| import datetime | ||||
| import mox | ||||
| import novaclient | ||||
|  | ||||
| from nova import context | ||||
| from nova import db | ||||
| from nova import flags | ||||
| from nova import service | ||||
| from nova import test | ||||
| from nova import rpc | ||||
| from nova import utils | ||||
| from nova.auth import manager as auth_manager | ||||
| from nova.scheduler import zone_manager | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
|  | ||||
| class FakeZone: | ||||
|     """Represents a fake zone from the db""" | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         for k, v in kwargs.iteritems(): | ||||
|             setattr(self, k, v) | ||||
|  | ||||
|  | ||||
| def exploding_novaclient(zone): | ||||
|     """Used when we want to simulate a novaclient call failing.""" | ||||
|     raise Exception("kaboom") | ||||
|  | ||||
|  | ||||
| class ZoneManagerTestCase(test.TestCase): | ||||
|     """Test case for zone manager""" | ||||
|     def test_ping(self): | ||||
|         zm = zone_manager.ZoneManager() | ||||
|         self.mox.StubOutWithMock(zm, '_refresh_from_db') | ||||
|         self.mox.StubOutWithMock(zm, '_poll_zones') | ||||
|         zm._refresh_from_db(mox.IgnoreArg()) | ||||
|         zm._poll_zones(mox.IgnoreArg()) | ||||
|  | ||||
|         self.mox.ReplayAll() | ||||
|         zm.ping(None) | ||||
|         self.mox.VerifyAll() | ||||
|  | ||||
|     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='user1', | ||||
|                     password='pass1'), | ||||
|             ]) | ||||
|  | ||||
|         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 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='user1', password='pass1')) | ||||
|         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='user2', | ||||
|                     password='pass2'), | ||||
|             ]) | ||||
|  | ||||
|         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): | ||||
|         zm = zone_manager.ZoneManager() | ||||
|         zone_state = zone_manager.ZoneState() | ||||
|         zone_state.update_credentials(FakeZone(id=1, api_url='http://foo.com', | ||||
|                         username='user1', password='pass1')) | ||||
|         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='user1', password='pass1')) | ||||
|         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='user2', | ||||
|                     password='pass2'), | ||||
|             ]) | ||||
|         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_poll_zone(self): | ||||
|         self.mox.StubOutWithMock(zone_manager, '_call_novaclient') | ||||
|         zone_manager._call_novaclient(mox.IgnoreArg()).AndReturn( | ||||
|                         dict(name='zohan', capabilities='hairdresser')) | ||||
|  | ||||
|         zone_state = zone_manager.ZoneState() | ||||
|         zone_state.update_credentials(FakeZone(id=2, | ||||
|                        api_url='http://foo.com', username='user2', | ||||
|                        password='pass2')) | ||||
|         zone_state.attempt = 1 | ||||
|  | ||||
|         self.mox.ReplayAll() | ||||
|         zone_manager._poll_zone(zone_state) | ||||
|         self.mox.VerifyAll() | ||||
|         self.assertEquals(zone_state.attempt, 0) | ||||
|         self.assertEquals(zone_state.name, 'zohan') | ||||
|  | ||||
|     def test_poll_zone_fails(self): | ||||
|         self.stubs.Set(zone_manager, "_call_novaclient", exploding_novaclient) | ||||
|  | ||||
|         zone_state = zone_manager.ZoneState() | ||||
|         zone_state.update_credentials(FakeZone(id=2, | ||||
|                        api_url='http://foo.com', username='user2', | ||||
|                        password='pass2')) | ||||
|         zone_state.attempt = FLAGS.zone_failures_to_offline - 1 | ||||
|  | ||||
|         self.mox.ReplayAll() | ||||
|         zone_manager._poll_zone(zone_state) | ||||
|         self.mox.VerifyAll() | ||||
|         self.assertEquals(zone_state.attempt, 3) | ||||
|         self.assertFalse(zone_state.is_active) | ||||
|         self.assertEquals(zone_state.name, None) | ||||
| @@ -21,6 +21,7 @@ from nova.virt.xenapi import fake | ||||
| from nova.virt.xenapi import volume_utils | ||||
| from nova.virt.xenapi import vm_utils | ||||
| from nova.virt.xenapi import vmops | ||||
| from nova import utils | ||||
|  | ||||
|  | ||||
| def stubout_instance_snapshot(stubs): | ||||
| @@ -137,14 +138,17 @@ def stubout_is_vdi_pv(stubs): | ||||
|     stubs.Set(vm_utils, '_is_vdi_pv', f) | ||||
|  | ||||
|  | ||||
| def stubout_loopingcall_start(stubs): | ||||
|     def f_1(self, interval, now=True): | ||||
|         self.f(*self.args, **self.kw) | ||||
|     stubs.Set(utils.LoopingCall, 'start', f_1) | ||||
|  | ||||
|  | ||||
| class FakeSessionForVMTests(fake.SessionBase): | ||||
|     """ Stubs out a XenAPISession for VM tests """ | ||||
|     def __init__(self, uri): | ||||
|         super(FakeSessionForVMTests, self).__init__(uri) | ||||
|  | ||||
|     def network_get_all_records_where(self, _1, _2): | ||||
|         return self.xenapi.network.get_all_records() | ||||
|  | ||||
|     def host_call_plugin(self, _1, _2, _3, _4, _5): | ||||
|         sr_ref = fake.get_all('SR')[0] | ||||
|         vdi_ref = fake.create_vdi('', False, sr_ref, False) | ||||
| @@ -178,12 +182,6 @@ class FakeSessionForVMTests(fake.SessionBase): | ||||
|     def VM_destroy(self, session_ref, vm_ref): | ||||
|         fake.destroy_vm(vm_ref) | ||||
|  | ||||
|     def VM_add_to_xenstore_data(self, session_ref, vm_ref, key, value): | ||||
|         fake.VM_add_to_xenstore_data(vm_ref, key, value) | ||||
|  | ||||
|     def VM_remove_from_xenstore_data(self, session_ref, vm_ref, key): | ||||
|         fake.VM_remove_from_xenstore_data(vm_ref, key) | ||||
|  | ||||
|     def SR_scan(self, session_ref, sr_ref): | ||||
|         pass | ||||
|  | ||||
|   | ||||
| @@ -139,34 +139,44 @@ def execute(*cmd, **kwargs): | ||||
|     stdin = kwargs.get('stdin', subprocess.PIPE) | ||||
|     stdout = kwargs.get('stdout', subprocess.PIPE) | ||||
|     stderr = kwargs.get('stderr', subprocess.PIPE) | ||||
|     attempts = kwargs.get('attempts', 1) | ||||
|     cmd = map(str, cmd) | ||||
|  | ||||
|     LOG.debug(_("Running cmd (subprocess): %s"), ' '.join(cmd)) | ||||
|     env = os.environ.copy() | ||||
|     if addl_env: | ||||
|         env.update(addl_env) | ||||
|     obj = subprocess.Popen(cmd, stdin=stdin, | ||||
|             stdout=stdout, stderr=stderr, env=env) | ||||
|     result = None | ||||
|     if process_input != None: | ||||
|         result = obj.communicate(process_input) | ||||
|     else: | ||||
|         result = obj.communicate() | ||||
|     obj.stdin.close() | ||||
|     if obj.returncode: | ||||
|         LOG.debug(_("Result was %s") % obj.returncode) | ||||
|         if type(check_exit_code) == types.IntType \ | ||||
|                 and obj.returncode != check_exit_code: | ||||
|             (stdout, stderr) = result | ||||
|             raise ProcessExecutionError(exit_code=obj.returncode, | ||||
|                                         stdout=stdout, | ||||
|                                         stderr=stderr, | ||||
|                                         cmd=' '.join(cmd)) | ||||
|     # NOTE(termie): this appears to be necessary to let the subprocess call | ||||
|     #               clean something up in between calls, without it two | ||||
|     #               execute calls in a row hangs the second one | ||||
|     greenthread.sleep(0) | ||||
|     return result | ||||
|     while attempts > 0: | ||||
|         attempts -= 1 | ||||
|         try: | ||||
|             LOG.debug(_("Running cmd (subprocess): %s"), ' '.join(cmd)) | ||||
|             env = os.environ.copy() | ||||
|             if addl_env: | ||||
|                 env.update(addl_env) | ||||
|             obj = subprocess.Popen(cmd, stdin=stdin, | ||||
|                     stdout=stdout, stderr=stderr, env=env) | ||||
|             result = None | ||||
|             if process_input != None: | ||||
|                 result = obj.communicate(process_input) | ||||
|             else: | ||||
|                 result = obj.communicate() | ||||
|             obj.stdin.close() | ||||
|             if obj.returncode: | ||||
|                 LOG.debug(_("Result was %s") % obj.returncode) | ||||
|                 if type(check_exit_code) == types.IntType \ | ||||
|                         and obj.returncode != check_exit_code: | ||||
|                     (stdout, stderr) = result | ||||
|                     raise ProcessExecutionError(exit_code=obj.returncode, | ||||
|                                                 stdout=stdout, | ||||
|                                                 stderr=stderr, | ||||
|                                                 cmd=' '.join(cmd)) | ||||
|             # NOTE(termie): this appears to be necessary to let the subprocess | ||||
|             #               call clean something up in between calls, without | ||||
|             #               it two execute calls in a row hangs the second one | ||||
|             greenthread.sleep(0) | ||||
|             return result | ||||
|         except ProcessExecutionError: | ||||
|             if not attempts: | ||||
|                 raise | ||||
|             else: | ||||
|                 LOG.debug(_("%r failed. Retrying."), cmd) | ||||
|                 greenthread.sleep(random.randint(20, 200) / 100.0) | ||||
|  | ||||
|  | ||||
| def ssh_execute(ssh, cmd, process_input=None, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Salvatore Orlando
					Salvatore Orlando