diff options
| author | Trey Morris <trey.morris@rackspace.com> | 2011-02-24 23:35:21 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-02-24 23:35:21 +0000 |
| commit | c59109e32678535320a39599cce50fec65689082 (patch) | |
| tree | be72b6a8b2a34b79d83f794275ca7c4081fb1f34 | |
| parent | 0d6c226afa8085753b85e9b6ab94f239a2549d2d (diff) | |
| parent | f4221346418ef103635b104fc152a2507d60a8dc (diff) | |
| download | nova-c59109e32678535320a39599cce50fec65689082.tar.gz nova-c59109e32678535320a39599cce50fec65689082.tar.xz nova-c59109e32678535320a39599cce50fec65689082.zip | |
adds live network injection/reconfiguration. Some refactoring.
| -rw-r--r-- | nova/api/openstack/__init__.py | 1 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 14 | ||||
| -rw-r--r-- | nova/compute/api.py | 7 | ||||
| -rw-r--r-- | nova/compute/manager.py | 12 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_servers.py | 12 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 111 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 4 |
7 files changed, 121 insertions, 40 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index d0b18eced..b1b38ed2d 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -81,6 +81,7 @@ class APIRouter(wsgi.Router): server_members['suspend'] = 'POST' server_members['resume'] = 'POST' server_members['reset_network'] = 'POST' + server_members['inject_network_info'] = 'POST' mapper.resource("zone", "zones", controller=zones.Controller(), collection={'detail': 'GET'}) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 841bab6d0..73c7bfe17 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -292,6 +292,20 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() + def inject_network_info(self, req, id): + """ + Inject network info for an instance (admin only). + + """ + context = req.environ['nova.context'] + try: + self.compute_api.inject_network_info(context, id) + except: + readable = traceback.format_exc() + LOG.exception(_("Compute.api::inject_network_info %s"), readable) + return faults.Fault(exc.HTTPUnprocessableEntity()) + return exc.HTTPAccepted() + def pause(self, req, id): """ Permit Admins to Pause the server. """ ctxt = req.environ['nova.context'] diff --git a/nova/compute/api.py b/nova/compute/api.py index d9431c679..c475e3bff 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -501,6 +501,13 @@ class API(base.Base): """ self._cast_compute_message('reset_network', context, instance_id) + def inject_network_info(self, context, instance_id): + """ + Inject network info for the instance. + + """ + self._cast_compute_message('inject_network_info', context, instance_id) + def attach_volume(self, context, instance_id, volume_id, device): if not re.match("^/dev/[a-z]d[a-z]+$", device): raise exception.ApiError(_("Invalid device specified: %s. " diff --git a/nova/compute/manager.py b/nova/compute/manager.py index b8d4b7ee9..d659712ad 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -527,6 +527,18 @@ class ComputeManager(manager.Manager): context=context) self.driver.reset_network(instance_ref) + @checks_instance_lock + def inject_network_info(self, context, instance_id): + """ + Inject network info for the instance. + + """ + context = context.elevated() + instance_ref = self.db.instance_get(context, instance_id) + LOG.debug(_('instance %s: inject network info'), instance_id, + context=context) + self.driver.inject_network_info(instance_ref) + @exception.wrap_exception def get_console_output(self, context, instance_id): """Send the console output for an instance.""" diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 054996658..dc093842d 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -360,6 +360,18 @@ class ServersTest(unittest.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 202) + def test_server_inject_network_info(self): + FLAGS.allow_admin_api = True + body = dict(server=dict( + name='server_test', imageId=2, flavorId=2, metadata={}, + personality={})) + req = webob.Request.blank('/v1.0/servers/1/inject_network_info') + req.method = 'POST' + req.content_type = 'application/json' + req.body = json.dumps(body) + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 202) + def test_server_diagnostics(self): req = webob.Request.blank("/v1.0/servers/1/diagnostics") req.method = "GET" diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 0168681f6..2aa0dde70 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -105,45 +105,9 @@ class VMOps(object): instance, kernel, ramdisk, pv_kernel) VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True) - # write network info - admin_context = context.get_admin_context() - - # TODO(tr3buchet) - remove comment in multi-nic - # I've decided to go ahead and consider multiple IPs and networks - # at this stage even though they aren't implemented because these will - # be needed for multi-nic and there was no sense writing it for single - # network/single IP and then having to turn around and re-write it - IPs = db.fixed_ip_get_all_by_instance(admin_context, instance['id']) - for network in db.network_get_all_by_instance(admin_context, - instance['id']): - network_IPs = [ip for ip in IPs if ip.network_id == network.id] - - def ip_dict(ip): - return {'netmask': network['netmask'], - 'enabled': '1', - 'ip': ip.address} - - mac_id = instance.mac_address.replace(':', '') - location = 'vm-data/networking/%s' % mac_id - mapping = {'label': network['label'], - 'gateway': network['gateway'], - 'mac': instance.mac_address, - 'dns': [network['dns']], - 'ips': [ip_dict(ip) for ip in network_IPs]} - self.write_to_param_xenstore(vm_ref, {location: mapping}) - - # TODO(tr3buchet) - remove comment in multi-nic - # this bit here about creating the vifs will be updated - # in multi-nic to handle multiple IPs on the same network - # and multiple networks - # for now it works as there is only one of each - bridge = network['bridge'] - network_ref = \ - NetworkHelper.find_network_with_bridge(self._session, bridge) - - if network_ref: - VMHelper.create_vif(self._session, vm_ref, - network_ref, instance.mac_address) + # inject_network_info and create vifs + networks = self.inject_network_info(instance) + self.create_vifs(instance, networks) LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) @@ -193,7 +157,7 @@ class VMOps(object): timer.f = _wait_for_boot - # call reset networking + # call to reset network to configure network from xenstore self.reset_network(instance) return timer.start(interval=0.5, now=True) @@ -483,6 +447,73 @@ class VMOps(object): # TODO: implement this! return 'http://fakeajaxconsole/fake_url' + def inject_network_info(self, instance): + """ + Generate the network info and make calls to place it into the + xenstore and the xenstore param list + + """ + # TODO(tr3buchet) - remove comment in multi-nic + # I've decided to go ahead and consider multiple IPs and networks + # at this stage even though they aren't implemented because these will + # be needed for multi-nic and there was no sense writing it for single + # network/single IP and then having to turn around and re-write it + vm_opaque_ref = self._get_vm_opaque_ref(instance.id) + logging.debug(_("injecting network info to xenstore for vm: |%s|"), + vm_opaque_ref) + admin_context = context.get_admin_context() + IPs = db.fixed_ip_get_all_by_instance(admin_context, instance['id']) + networks = db.network_get_all_by_instance(admin_context, + instance['id']) + for network in networks: + network_IPs = [ip for ip in IPs if ip.network_id == network.id] + + def ip_dict(ip): + return {'netmask': network['netmask'], + 'enabled': '1', + 'ip': ip.address} + + mac_id = instance.mac_address.replace(':', '') + location = 'vm-data/networking/%s' % mac_id + mapping = {'label': network['label'], + 'gateway': network['gateway'], + 'mac': instance.mac_address, + 'dns': [network['dns']], + 'ips': [ip_dict(ip) for ip in network_IPs]} + self.write_to_param_xenstore(vm_opaque_ref, {location: mapping}) + try: + self.write_to_xenstore(vm_opaque_ref, location, + mapping['location']) + except KeyError: + # catch KeyError for domid if instance isn't running + pass + + return networks + + def create_vifs(self, instance, networks=None): + """ + Creates vifs for an instance + + """ + vm_opaque_ref = self._get_vm_opaque_ref(instance.id) + logging.debug(_("creating vif(s) for vm: |%s|"), vm_opaque_ref) + if networks is None: + networks = db.network_get_all_by_instance(admin_context, + instance['id']) + # TODO(tr3buchet) - remove comment in multi-nic + # this bit here about creating the vifs will be updated + # in multi-nic to handle multiple IPs on the same network + # and multiple networks + # for now it works as there is only one of each + for network in networks: + bridge = network['bridge'] + network_ref = \ + NetworkHelper.find_network_with_bridge(self._session, bridge) + + if network_ref: + VMHelper.create_vif(self._session, vm_opaque_ref, + network_ref, instance.mac_address) + def reset_network(self, instance): """ Creates uuid arg to pass to make_agent_call and calls it. diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index c2f65699f..fc56a4bae 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -198,6 +198,10 @@ class XenAPIConnection(object): """reset networking for specified instance""" self._vmops.reset_network(instance) + def inject_network_info(self, instance): + """inject network info for specified instance""" + self._vmops.inject_network_info(instance) + def get_info(self, instance_id): """Return data about VM instance""" return self._vmops.get_info(instance_id) |
