def ensure_mesh(self): with util.RecordedOperation('ensure mesh', self) as _: instances = [] for iface in db.get_network_interfaces(self.uuid): if not iface['instance_uuid'] in instances: instances.append(iface['instance_uuid']) node_fqdns = [] for inst in instances: i = db.get_instance(inst) if not i['node'] in node_fqdns: node_fqdns.append(i['node']) # NOTE(mikal): why not use DNS here? Well, DNS might be outside # the control of the deployer if we're running in a public cloud # as an overlay cloud... node_ips = [config.parsed.get('NETWORK_NODE_IP')] for fqdn in node_fqdns: ip = db.get_node(fqdn)['ip'] if ip not in node_ips: node_ips.append(ip) discovered = list(self.discover_mesh()) LOG.debug('%s: Discovered mesh elements %s' % (self, discovered)) for node in discovered: if node in node_ips: node_ips.remove(node) else: self._remove_mesh_element(node) for node in node_ips: self._add_mesh_element(node)
def delete(self, network_uuid=None, network_from_db=None): db.add_event('network', network_uuid, 'api', 'delete', None, None) if network_uuid == 'floating': return error(403, 'you cannot delete the floating network') # We only delete unused networks if len(list(db.get_network_interfaces(network_uuid))) > 0: return error(403, 'you cannot delete an in use network') # Check if network has already been deleted if network_from_db['state'] == 'deleted': return error(404, 'network not found') with db.get_lock('sf/network/%s' % network_uuid, ttl=900) as _: n = net.from_db(network_uuid) n.remove_dhcp() n.delete() if n.floating_gateway: with db.get_lock('sf/ipmanager/floating', ttl=120) as _: ipm = db.get_ipmanager('floating') ipm.release(n.floating_gateway) db.persist_ipmanager('floating', ipm.save()) db.update_network_state(network_uuid, 'deleted')
def _make_hosts(self): if not os.path.exists(self.subst['config_dir']): os.makedirs(self.subst['config_dir']) t = self._read_template('dhcphosts.tmpl') instances = [] for ni in list(db.get_network_interfaces(self.network_uuid)): instance = db.get_instance(ni['instance_uuid']) if not instance: continue instances.append({ 'uuid': ni['instance_uuid'], 'macaddr': ni['macaddr'], 'ipv4': ni['ipv4'], 'name': instance.get('name', 'instance').replace(',', '') }) self.subst['instances'] = instances c = t.render(self.subst) with open(os.path.join(self.subst['config_dir'], 'hosts'), 'w') as f: f.write(c)
def ensure_mesh(self): with db.get_object_lock(self, ttl=120, op='Network ensure mesh'): # Ensure network was not deleted whilst waiting for the lock. if self.is_dead(): raise DeadNetwork('network=%s' % self) removed = [] added = [] instances = [] for iface in db.get_network_interfaces(self.db_entry['uuid']): if not iface['instance_uuid'] in instances: instances.append(iface['instance_uuid']) node_fqdns = [] for inst in instances: i = db.get_instance(inst) if not i: continue if not i['node']: continue if not i['node'] in node_fqdns: node_fqdns.append(i['node']) # NOTE(mikal): why not use DNS here? Well, DNS might be outside # the control of the deployer if we're running in a public cloud # as an overlay cloud... node_ips = [config.NETWORK_NODE_IP] for fqdn in node_fqdns: ip = db.get_node(fqdn)['ip'] if ip not in node_ips: node_ips.append(ip) discovered = list(self.discover_mesh()) LOG.withObj(self).withField( 'discovered', discovered).debug('Discovered mesh elements') for node in discovered: if node in node_ips: node_ips.remove(node) else: self._remove_mesh_element(node) removed.append(node) for node in node_ips: self._add_mesh_element(node) added.append(node) if removed: db.add_event('network', self.db_entry['uuid'], 'remove mesh elements', None, None, ' '.join(removed)) if added: db.add_event('network', self.db_entry['uuid'], 'add mesh elements', None, None, ' '.join(added))
def delete(self, network_uuid=None, network_from_db=None): if network_uuid == 'floating': return error(403, 'you cannot delete the floating network') # We only delete unused networks if len(list(db.get_network_interfaces(network_uuid))) > 0: return error(403, 'you cannot delete an in use network') # Check if network has already been deleted if network_from_db['state'] in 'deleted': return error(404, 'network not found') _delete_network(network_from_db)
def ensure_mesh(self): with db.get_lock('network', None, self.uuid, ttl=120): removed = [] added = [] instances = [] for iface in db.get_network_interfaces(self.uuid): if not iface['instance_uuid'] in instances: instances.append(iface['instance_uuid']) node_fqdns = [] for inst in instances: i = db.get_instance(inst) if not i: continue if not i['node']: continue if not i['node'] in node_fqdns: node_fqdns.append(i['node']) # NOTE(mikal): why not use DNS here? Well, DNS might be outside # the control of the deployer if we're running in a public cloud # as an overlay cloud... node_ips = [config.parsed.get('NETWORK_NODE_IP')] for fqdn in node_fqdns: ip = db.get_node(fqdn)['ip'] if ip not in node_ips: node_ips.append(ip) discovered = list(self.discover_mesh()) logutil.debug([self], 'Discovered mesh elements %s' % discovered) for node in discovered: if node in node_ips: node_ips.remove(node) else: self._remove_mesh_element(node) removed.append(node) for node in node_ips: self._add_mesh_element(node) added.append(node) if removed: db.add_event('network', self.uuid, 'remove mesh elements', None, None, ' '.join(removed)) if added: db.add_event('network', self.uuid, 'add mesh elements', None, None, ' '.join(added))
def delete(self, confirm=False, namespace=None): """Delete all networks in the namespace.""" if confirm is not True: return error(400, 'parameter confirm is not set true') if get_jwt_identity() == 'system': if not isinstance(namespace, str): # A client using a system key must specify the namespace. This # ensures that deleting all networks in the cluster (by # specifying namespace='system') is a deliberate act. return error(400, 'system user must specify parameter namespace') else: if namespace and namespace != get_jwt_identity(): return error(401, 'you cannot delete other namespaces') namespace = get_jwt_identity() networks_del = [] networks_unable = [] for n in list(db.get_networks(all=all, namespace=namespace)): if n['uuid'] == 'floating': continue if len(list(db.get_network_interfaces(n['uuid']))) > 0: logutil.info([n], 'Network in use, cannot be deleted by delete-all') networks_unable.append(n['uuid']) continue if n['state'] == 'deleted': continue _delete_network(n) networks_del.append(n['uuid']) if networks_unable: return error(403, { 'deleted': networks_del, 'unable': networks_unable }) return networks_del
def delete(self, network_uuid=None, network_from_db=None): db.add_event('network', network_uuid, 'API DELETE', None, None, None) if network_uuid == 'floating': return error(403, 'you cannot delete the floating network') # We only delete unused networks if len(list(db.get_network_interfaces(network_uuid))) > 0: return error(403, 'you cannot delete an in use network') n = net.from_db(network_uuid) n.remove_dhcp() n.delete() if n.floating_gateway: floating_network = net.from_db('floating') floating_network.ipmanager.release(n.floating_gateway) floating_network.persist_ipmanager() db.delete_network(network_uuid)
def get(self, network_uuid=None, network_from_db=None): return list(db.get_network_interfaces(network_uuid))
def _maintain_networks(self): LOG.info('Maintaining networks') # Discover what networks are present _, _, vxid_to_mac = util.discover_interfaces() # Determine what networks we should be on host_networks = [] seen_vxids = [] if not util.is_network_node(): # For normal nodes, just the ones we have instances for for inst in list(db.get_instances(only_node=config.parsed.get('NODE_NAME'))): for iface in db.get_instance_interfaces(inst['uuid']): if not iface['network_uuid'] in host_networks: host_networks.append(iface['network_uuid']) else: # For network nodes, its all networks for n in db.get_networks(): host_networks.append(n['uuid']) # Network nodes also look for interfaces for absent instances # and delete them for ni in db.get_network_interfaces(n['uuid']): inst = db.get_instance(ni['instance_uuid']) if (not inst or inst.get('state', 'unknown') in ['deleted', 'error', 'unknown']): db.hard_delete_network_interface(ni['uuid']) LOG.withInstance( ni['instance_uuid']).withNetworkInterface( ni['uuid']).info('Hard deleted stray network interface') # Ensure we are on every network we have a host for for network in host_networks: try: n = net.from_db(network) if not n: continue if n.db_entry['state_updated'] - time.time() < 60: # Network state changed in the last minute, punt for now continue if not n.is_okay(): LOG.withObj(n).info('Recreating not okay network') n.create() n.ensure_mesh() seen_vxids.append(n.vxlan_id) except exceptions.LockException as e: LOG.warning( 'Failed to acquire lock while maintaining networks: %s' % e) # Determine if there are any extra vxids extra_vxids = set(vxid_to_mac.keys()) - set(seen_vxids) # Delete "deleted" SF networks and log unknown vxlans if extra_vxids: LOG.withField('vxids', extra_vxids).warning( 'Extra vxlans present!') # Determine the network uuids for those vxids # vxid_to_uuid = {} # for n in db.get_networks(): # vxid_to_uuid[n['vxid']] = n['uuid'] # for extra in extra_vxids: # if extra in vxid_to_uuid: # with db.get_lock('network', None, vxid_to_uuid[extra], # ttl=120, op='Network reap VXLAN'): # n = net.from_db(vxid_to_uuid[extra]) # n.delete() # LOG.info('Extra vxlan %s (network %s) removed.' # % (extra, vxid_to_uuid[extra])) # else: # LOG.error('Extra vxlan %s does not map to any network.' # % extra) # And record vxids in the database db.persist_node_vxid_mapping( config.parsed.get('NODE_NAME'), vxid_to_mac)