diff options
| author | Trey Morris <trey.morris@rackspace.com> | 2011-03-14 13:32:22 -0500 |
|---|---|---|
| committer | Trey Morris <trey.morris@rackspace.com> | 2011-03-14 13:32:22 -0500 |
| commit | 093c8200a102891232e2da166830cd59ee133fc4 (patch) | |
| tree | f07ed6dac0a7e83fe9bf6adf6dc4b4ea0d3da02d | |
| parent | 18e16ab9f5be77764a810b2d6ac5ae8c5be6bb52 (diff) | |
| download | nova-093c8200a102891232e2da166830cd59ee133fc4.tar.gz nova-093c8200a102891232e2da166830cd59ee133fc4.tar.xz nova-093c8200a102891232e2da166830cd59ee133fc4.zip | |
committing to share
| -rwxr-xr-x | bin/nova-manage | 8 | ||||
| -rw-r--r-- | nova/compute/api.py | 3 | ||||
| -rw-r--r-- | nova/compute/manager.py | 12 | ||||
| -rw-r--r-- | nova/db/api.py | 39 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 131 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/models.py | 76 | ||||
| -rw-r--r-- | nova/exception.py | 4 | ||||
| -rw-r--r-- | nova/network/api.py | 6 | ||||
| -rw-r--r-- | nova/network/manager.py | 61 | ||||
| -rw-r--r-- | nova/tests/test_compute.py | 1 | ||||
| -rw-r--r-- | nova/tests/test_quota.py | 1 | ||||
| -rw-r--r-- | nova/tests/test_scheduler.py | 1 | ||||
| -rw-r--r-- | nova/tests/test_volume.py | 1 | ||||
| -rw-r--r-- | nova/utils.py | 8 |
14 files changed, 270 insertions, 82 deletions
diff --git a/bin/nova-manage b/bin/nova-manage index b603c8b07..9dc0f4a62 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -505,7 +505,8 @@ class NetworkCommands(object): def create(self, fixed_range=None, num_networks=None, network_size=None, vlan_start=None, - vpn_start=None, fixed_range_v6=None, label='public'): + vpn_start=None, fixed_range_v6=None, label='public', + flat_network_bridge=None): """Creates fixed ips for host by range arguments: [fixed_range=FLAG], [num_networks=FLAG], [network_size=FLAG], [vlan_start=FLAG], @@ -522,6 +523,8 @@ class NetworkCommands(object): vpn_start = FLAGS.vpn_start if not fixed_range_v6: fixed_range_v6 = FLAGS.fixed_range_v6 + if not flat_network_bridge: + flat_network_bridge = FLAGS.flat_network_bridge net_manager = utils.import_object(FLAGS.network_manager) net_manager.create_networks(context.get_admin_context(), cidr=fixed_range, @@ -530,7 +533,8 @@ class NetworkCommands(object): vlan_start=int(vlan_start), vpn_start=int(vpn_start), cidr_v6=fixed_range_v6, - label=label) + label=label, + flat_network_bridge) def list(self): """List all created networks""" diff --git a/nova/compute/api.py b/nova/compute/api.py index c475e3bff..1737565aa 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -184,8 +184,7 @@ class API(base.Base): instances = [] LOG.debug(_("Going to run %s instances..."), num_instances) for num in range(num_instances): - instance = dict(mac_address=utils.generate_mac(), - launch_index=num, + instance = dict(launch_index=num, **base_options) instance = self.db.instance_create(context, instance) instance_id = instance['id'] diff --git a/nova/compute/manager.py b/nova/compute/manager.py index d659712ad..ce2fa8713 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -193,16 +193,22 @@ class ComputeManager(manager.Manager): # with the address currently, but I'm leaving it as # a call to ensure that network setup completes. We # will eventually also need to save the address here. + #NOTE(tr3buchet): I don't see why we'd save it here when the network + # manager is saving it. if not FLAGS.stub_network: - address = rpc.call(context, - self.get_network_topic(context), - {"method": "allocate_fixed_ip", + rpc.call(context, self.get_network_topic(context), + {"method": "allocate_fixed_ips", "args": {"instance_id": instance_id, "vpn": is_vpn}}) + rpc.call(context, self.get_network_topic(context), + {"method": "allocate_mac_addresses", + "args": {"instance_id": instance_id}}) self.network_manager.setup_compute_network(context, instance_id) + Log.debug(_("instance addresses: |%s|"), instance_ref['fixed_ips']) + # TODO(vish) check to make sure the availability zone matches self.db.instance_set_state(context, instance_id, diff --git a/nova/db/api.py b/nova/db/api.py index dcaf55e8f..5b92afbcd 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -325,6 +325,37 @@ def fixed_ip_update(context, address, values): #################### +def mac_address_create(context, values): + """create a new mac address record in teh database""" + return IMPL.mac_address_create(context, values) + + +def mac_address_get(context, mac_address): + """gets a mac address from the table""" + return IMPL.mac_address_get(context, mac_address) + + +def mac_address_get_all_by_instance(context, instance_id): + """gets all mac addresses for instance""" + return IMPL.mac_address_get_all_by_instance(context, instance_id) + + +def mac_address_get_all_by_network(context, network_id): + """gets all mac addresses for instance""" + return IMPL.mac_address_get_all_by_network(context, network_id) + + +def mac_address_delete(context, mac_address): + """delete mac address record in teh database""" + return IMPL.mac_address_delete(context, mac_address) + + +def mac_address_delete_by_instance(context, instance_id): + """delete mac address record in teh database""" + return IMPL.mac_address_delete_by_instance(context, instance_id) +#################### + + def instance_create(context, values): """Create an instance from the values dictionary.""" return IMPL.instance_create(context, values) @@ -370,13 +401,13 @@ def instance_get_all_by_reservation(context, reservation_id): return IMPL.instance_get_all_by_reservation(context, reservation_id) -def instance_get_fixed_address(context, instance_id): +def instance_get_fixed_addresses(context, instance_id): """Get the fixed ip address of an instance.""" - return IMPL.instance_get_fixed_address(context, instance_id) + return IMPL.instance_get_fixed_addresses(context, instance_id) -def instance_get_fixed_address_v6(context, instance_id): - return IMPL.instance_get_fixed_address_v6(context, instance_id) +def instance_get_fixed_addresses_v6(context, instance_id): + return IMPL.instance_get_fixed_addresses_v6(context, instance_id) def instance_get_floating_address(context, instance_id): diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 6df2a8843..6e59f4b1d 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -630,11 +630,16 @@ def fixed_ip_get_all_by_instance(context, instance_id): @require_context def fixed_ip_get_instance_v6(context, address): session = get_session() + + # convert IPv6 address to mac mac = utils.to_mac(address) + # get mac address row + mac_ref = mac_address_get(context, mac) + + # look up instance based on instance_id from mac address row result = session.query(models.Instance).\ - filter_by(mac_address=mac).\ - first() + filter_by(id=mac_ref.instance_id) return result @@ -659,6 +664,98 @@ def fixed_ip_update(context, address, values): @require_context +def mac_address_create(context, values): + """create a new mac address record in teh database + + context = request context object + values = dict containing column values + """ + mac_address_ref = models.MacAddress() + mac_address_ref.update(values) + mac_address_ref.save() + + session = get_session() + with session.begin(): + instance = instance_get(context, instance_id, session=session) + network = network_get(context, network_id, session=session) + mac_address.instance = instance + mac_address.network = network + mac_address_ref.save(session=session) + return mac_address_ref + + +def mac_address_get(context, mac_address): + """gets a mac address from the table + + context = request context object + mac_address = the mac you're looking to get + """ + session = get_session() + with session.begin(): + mac_address_ref = session.query(models.MacAddress).\ + filter_by(mac_address=mac_address) + return mac_address_ref + + +@require_context +def mac_address_get_all_by_instance(context, instance_id): + """gets all mac addresses for instance + + context = request context object + instance_id = instance to retreive macs for + """ + session = get_session() + with session.begin(): + mac_address_refs = session.query(models.MacAddress).\ + filter_by(instance_id=instance_id) + return mac_address_refs + + +@require_context +def mac_address_get_all_by_network(context, network_id): + """gets all mac addresses for instance + + context = request context object + network_id = network to retreive macs for + """ + session = get_session() + with session.begin(): + mac_address_refs = session.query(models.MacAddress).\ + filter_by(network_id=network_id) + return mac_address_refs + + +@require_context +def mac_address_delete(context, mac_address): + """delete mac address record in teh database + + context = request context object + instance_id = instance to remove macs for + """ + ref = mac_address_get(mac_address) + session = get_session() + with session.begin(): + ref.delete(session=session) + + +@require_context +def mac_address_delete_by_instance(context, instance_id): + """delete mac address record in teh database + + context = request context object + instance_id = instance to remove macs for + """ + refs = mac_address_get_all_by_instance(instance_id) + session = get_session() + with session.begin(): + for ref in refs: + ref.delete(session=session) + + +################### + + +@require_context def instance_create(context, values): """Create a new Instance record in the database. @@ -819,24 +916,35 @@ def instance_get_project_vpn(context, project_id): @require_context -def instance_get_fixed_address(context, instance_id): +def instance_get_fixed_addresses(context, instance_id): session = get_session() with session.begin(): instance_ref = instance_get(context, instance_id, session=session) - if not instance_ref.fixed_ip: + if not instance_ref.fixed_ips: return None - return instance_ref.fixed_ip['address'] + return [fixed_ip.address for fixed_ip in instance_ref.fixed_ips] @require_context -def instance_get_fixed_address_v6(context, instance_id): +def instance_get_fixed_addresses_v6(context, instance_id): session = get_session() with session.begin(): + # get instance instance_ref = instance_get(context, instance_id, session=session) - network_ref = network_get_by_instance(context, instance_id) - prefix = network_ref.cidr_v6 - mac = instance_ref.mac_address - return utils.to_global_ipv6(prefix, mac) + # get networks associated with instance + network_refs = network_get_all_by_instance(context, instance_id) + # compile a list of cidr_v6 prefixes sorted by network id + prefixes = [ref.cidr_v6 for ref in + sorted(network_refs, key=lambda ref: ref.id)] + # get mac rows associated with instance + mac_refs = mac_address_get_all_by_instance(context, instance_ref.id) + # compile of list of the mac_addresses sorted by network id + macs = [ref.mac_address for ref in + sorted(mac_refs, key=lambda ref: ref.network_id)] + # combine prefixes and macs into (prefix,mac) pairs + prefix_mac_pairs = zip(prefixes, macs) + # return list containing ipv6 address for each pair + return [utils.to_global_ipv6(pair) for pair in prefix_mac_pairs] @require_context @@ -1081,7 +1189,8 @@ def network_get(context, network_id, session=None): @require_admin_context def network_get_all(context): session = get_session() - result = session.query(models.Network) + result = session.query(models.Network).\ + filter_by(deleted=False) if not result: raise exception.NotFound(_('No networks defined')) return result diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 1882efeba..bbadbeee4 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -174,7 +174,6 @@ class Instance(BASE, NovaBase): user_data = Column(Text) reservation_id = Column(String(255)) - mac_address = Column(String(255)) scheduled_at = Column(DateTime) launched_at = Column(DateTime) @@ -404,21 +403,6 @@ class Network(BASE, NovaBase): host = Column(String(255)) # , ForeignKey('hosts.id')) -class AuthToken(BASE, NovaBase): - """Represents an authorization token for all API transactions. - - Fields are a string representing the actual token and a user id for - mapping to the actual user - - """ - __tablename__ = 'auth_tokens' - token_hash = Column(String(255), primary_key=True) - user_id = Column(String(255)) - server_manageent_url = Column(String(255)) - storage_url = Column(String(255)) - cdn_management_url = Column(String(255)) - - # TODO(vish): can these both come from the same baseclass? class FixedIp(BASE, NovaBase): """Represents a fixed ip for an instance.""" @@ -429,7 +413,7 @@ class FixedIp(BASE, NovaBase): network = relationship(Network, backref=backref('fixed_ips')) instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True) instance = relationship(Instance, - backref=backref('fixed_ip', uselist=False), + backref=backref('fixed_ips'), foreign_keys=instance_id, primaryjoin='and_(' 'FixedIp.instance_id == Instance.id,' @@ -439,6 +423,48 @@ class FixedIp(BASE, NovaBase): reserved = Column(Boolean, default=False) +class FloatingIp(BASE, NovaBase): + """Represents a floating ip that dynamically forwards to a fixed ip.""" + __tablename__ = 'floating_ips' + id = Column(Integer, primary_key=True) + address = Column(String(255)) + fixed_ip_id = Column(Integer, ForeignKey('fixed_ips.id'), nullable=True) + fixed_ip = relationship(FixedIp, + backref=backref('floating_ips'), + foreign_keys=fixed_ip_id, + primaryjoin='and_(' + 'FloatingIp.fixed_ip_id == FixedIp.id,' + 'FloatingIp.deleted == False)') + project_id = Column(String(255)) + host = Column(String(255)) # , ForeignKey('hosts.id')) + + +class MacAddress(BASE, NovaBase): + """Represents a mac address used by an instance""" + __tablename__ = 'mac_addresses' + id = Column(Integer, primary_key=True) + mac_address = Column(String(255), unique=True) + network_id = Column(Integer, ForeignKey('networks.id'), nullable=False) + network = relationship(Network, backref=backref('mac_addresses')) + instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False) + instance = relationship(Instance, backref=backref('mac_addresses')) + + +class AuthToken(BASE, NovaBase): + """Represents an authorization token for all API transactions. + + Fields are a string representing the actual token and a user id for + mapping to the actual user + + """ + __tablename__ = 'auth_tokens' + token_hash = Column(String(255), primary_key=True) + user_id = Column(String(255)) + server_manageent_url = Column(String(255)) + storage_url = Column(String(255)) + cdn_management_url = Column(String(255)) + + class User(BASE, NovaBase): """Represents a user.""" __tablename__ = 'users' @@ -499,22 +525,6 @@ class UserProjectAssociation(BASE, NovaBase): project_id = Column(String(255), ForeignKey(Project.id), primary_key=True) -class FloatingIp(BASE, NovaBase): - """Represents a floating ip that dynamically forwards to a fixed ip.""" - __tablename__ = 'floating_ips' - id = Column(Integer, primary_key=True) - address = Column(String(255)) - fixed_ip_id = Column(Integer, ForeignKey('fixed_ips.id'), nullable=True) - fixed_ip = relationship(FixedIp, - backref=backref('floating_ips'), - foreign_keys=fixed_ip_id, - primaryjoin='and_(' - 'FloatingIp.fixed_ip_id == FixedIp.id,' - 'FloatingIp.deleted == False)') - project_id = Column(String(255)) - host = Column(String(255)) # , ForeignKey('hosts.id')) - - class ConsolePool(BASE, NovaBase): """Represents pool of consoles on the same physical node.""" __tablename__ = 'console_pools' diff --git a/nova/exception.py b/nova/exception.py index 7d65bd6a5..95580ebea 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -123,3 +123,7 @@ def wrap_exception(f): raise _wrap.func_name = f.func_name return _wrap + + +class MacAddress(Error): + pass diff --git a/nova/network/api.py b/nova/network/api.py index bf43acb51..c46d600ca 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -85,3 +85,9 @@ class API(base.Base): self.db.queue_get_for(context, FLAGS.network_topic, host), {"method": "disassociate_floating_ip", "args": {"floating_address": floating_ip['address']}}) + + def get_instance_network_info(self, context, instance_id): + """return the network info for an instance""" + return rpc.call(context, FLAGS.network_topic, + {"method": "get_instance_network_info", + "args": {"instance_id": instance_id}}) diff --git a/nova/network/manager.py b/nova/network/manager.py index 12a0c5018..fba8b405a 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -293,6 +293,20 @@ class NetworkManager(manager.Manager): 'address': address, 'reserved': reserved}) + def generate_mac_address(self): + """generate a mac address for a vif on an instance""" + mac = [0x02, 0x16, 0x3e, + random.randint(0x00, 0x7f), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff)] + return ':'.join(map(lambda x: "%02x" % x, mac)) + + +# def setup_new_instance(self, context, instance_id, host): +# """allocate the network config for a new instance on host""" +# for network in DB_NETWORKGETALLBYHOST(): +# ip = self.allocate_fixed_ip(context, instance_id, network) + class FlatManager(NetworkManager): """Basic network where no vlans are used. @@ -332,31 +346,48 @@ class FlatManager(NetworkManager): for network in self.db.host_get_networks(ctxt, self.host): self._on_set_network_host(ctxt, network['id']) - def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): - """Gets a fixed ip from the pool.""" + def allocate_mac_addresses(self, context, instance_id): + """generates and stores mac addresses""" + mac_address = {'mac_address': self.generate_mac_address(), + 'instance_id': instance_id, + 'network_id': network.id} + + networks = self.db.network_get_all(context) + for network in networks: + for i in range(5): + try: + mac_address['mac_address'] = self.generate_mac_address(), + self.db.mac_address_create(context, row) + break + except: + #TODO(tr3buchet) find this exception + pass + else: + self.db.mac_address_delete(context, instance_id=instance_id) + raise exception.MacAddress(_("5 attempts at create failed")) + + def allocate_fixed_ips(self, context, instance_id, *args, **kwargs): + """Gets a fixed ip from a host's pool.""" # TODO(vish): when this is called by compute, we can associate compute # with a network, or a cluster of computes with a network # and use that network here with a method like # network_get_by_compute_host - network_ref = self.db.network_get_by_bridge(context, - FLAGS.flat_network_bridge) - address = self.db.fixed_ip_associate_pool(context.elevated(), - network_ref['id'], - instance_id) - self.db.fixed_ip_update(context, address, {'allocated': True}) - return address + networks = self.db.network_get_all(context) +# network_ref = self.db.network_get_by_bridge(context, +# FLAGS.flat_network_bridge) + for network in networks: + address = self.db.fixed_ip_associate_pool(context.elevated(), + network.id, + instance_id) + self.db.fixed_ip_update(context, address, {'allocated': True}) def deallocate_fixed_ip(self, context, address, *args, **kwargs): """Returns a fixed ip to the pool.""" self.db.fixed_ip_update(context, address, {'allocated': False}) self.db.fixed_ip_disassociate(context.elevated(), address) - def setup_compute_network(self, context, instance_id): - """Network is created manually.""" - pass - def create_networks(self, context, cidr, num_networks, network_size, - cidr_v6, label, *args, **kwargs): + cidr_v6, label, bridge, *args, **kwargs): """Create networks based on parameters.""" fixed_net = IPy.IP(cidr) fixed_net_v6 = IPy.IP(cidr_v6) @@ -368,7 +399,7 @@ class FlatManager(NetworkManager): cidr = "%s/%s" % (fixed_net[start], significant_bits) project_net = IPy.IP(cidr) net = {} - net['bridge'] = FLAGS.flat_network_bridge + net['bridge'] = bridge net['dns'] = FLAGS.flat_network_dns net['cidr'] = cidr net['netmask'] = str(project_net.netmask()) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index b049ac943..ba1f6be46 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -65,7 +65,6 @@ class ComputeTestCase(test.TestCase): inst['user_id'] = self.user.id inst['project_id'] = self.project.id inst['instance_type'] = 'm1.tiny' - inst['mac_address'] = utils.generate_mac() inst['ami_launch_index'] = 0 return db.instance_create(self.context, inst)['id'] diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py index 1e42fddf3..b1e7910ca 100644 --- a/nova/tests/test_quota.py +++ b/nova/tests/test_quota.py @@ -63,7 +63,6 @@ class QuotaTestCase(test.TestCase): inst['project_id'] = self.project.id inst['instance_type'] = 'm1.large' inst['vcpus'] = cores - inst['mac_address'] = utils.generate_mac() return db.instance_create(self.context, inst)['id'] def _create_volume(self, size=10): diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index b6888c4d2..b34b374fd 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -160,7 +160,6 @@ class SimpleDriverTestCase(test.TestCase): inst['user_id'] = self.user.id inst['project_id'] = self.project.id inst['instance_type'] = 'm1.tiny' - inst['mac_address'] = utils.generate_mac() inst['ami_launch_index'] = 0 inst['vcpus'] = 1 inst['availability_zone'] = kwargs.get('availability_zone', None) diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index b40ca004b..68412a184 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -105,7 +105,6 @@ class VolumeTestCase(test.TestCase): inst['user_id'] = 'fake' inst['project_id'] = 'fake' inst['instance_type'] = 'm1.tiny' - inst['mac_address'] = utils.generate_mac() inst['ami_launch_index'] = 0 instance_id = db.instance_create(self.context, inst)['id'] mountpoint = "/dev/sdf" diff --git a/nova/utils.py b/nova/utils.py index 0cf91e0cc..415976f44 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -231,14 +231,6 @@ def generate_uid(topic, size=8): return '%s-%s' % (topic, ''.join(choices)) -def generate_mac(): - mac = [0x02, 0x16, 0x3e, - random.randint(0x00, 0x7f), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff)] - return ':'.join(map(lambda x: "%02x" % x, mac)) - - def generate_password(length=20): """Generate a random sequence of letters and digits to be used as a password. Note that this is not intended |
