Example #1
0
  def save(self, user):
    """
    Completes node registration.
    """
    ip = self.cleaned_data.get('ip')
    project = self.cleaned_data.get('project')
    pool = self.cleaned_data.get('pool')
    prefix_len = self.cleaned_data.get('prefix_len')
    if prefix_len == 0:
      prefix_len = None
    subnet = None

    if not ip:
      # Assign a new IP address from the selected pool (if no IP address selected)
      node = Node()
      fresh_subnet = pool.allocate_subnet(prefix_len)
      net = ipcalc.Network(fresh_subnet.network, fresh_subnet.cidr)
      node.ip = str(net.host_first())
      
      # Create a new subnet for this node or use an existing one if available
      subnet = Subnet(node = node, subnet = fresh_subnet.network, cidr = fresh_subnet.cidr)
      subnet.allocated = True
      subnet.allocated_at = datetime.now()
      subnet.status = SubnetStatus.NotAnnounced
    else:
      # When prefix is not available we should use /32
      if prefix_len is None:
        prefix_len = 32
      
      net = ipcalc.Network(ip, prefix_len)
      sub_ip = str(net.network())
      
      # Check if this node already exists
      try:
        node = Node.objects.get(ip = str(net.host_first()))
      except Node.DoesNotExist:
        node = Node(ip = str(net.host_first()))
      
      # Reserve existing IP in the pool
      pool.reserve_subnet(sub_ip, prefix_len)
      try:
        subnet = Subnet.objects.get(node = node, subnet = sub_ip, cidr = prefix_len)
        subnet.status = SubnetStatus.AnnouncedOk
      except Subnet.DoesNotExist:
        subnet = Subnet(node = node, subnet = sub_ip, cidr = prefix_len)
        subnet.status = SubnetStatus.NotAnnounced
      
      subnet.allocated = True
      subnet.allocated_at = datetime.now()

    # Update node metadata
    node.name = self.cleaned_data.get('name').lower()
    node.project = project
    node.owner = user
    node.location = self.cleaned_data.get('location')
    node.geo_lat = self.cleaned_data.get('geo_lat')
    node.geo_long = self.cleaned_data.get('geo_long')
    node.ant_external = self.cleaned_data.get('ant_external')
    node.ant_polarization = self.cleaned_data.get('ant_polarization')
    node.ant_type = self.cleaned_data.get('ant_type')
    node.node_type = self.cleaned_data.get('node_type')
    node.notes = self.cleaned_data.get('notes')
    node.url = self.cleaned_data.get('url')
    node.redundancy_req = self.cleaned_data.get('redundancy_req')
    node.warnings = False

    for i in xrange(10):
      try:
        mac = gen_mac_address()
        Node.objects.get(vpn_mac_conf = mac)
      except Node.DoesNotExist: 
        node.vpn_mac_conf = mac
        break
    else:
      raise Exception, "unable to generate unique MAC"

    if user.is_staff:
      node.system_node = self.cleaned_data.get('system_node')
      node.vpn_server = self.cleaned_data.get('vpn_server')
    
    if user.is_staff or getattr(settings, 'NONSTAFF_BORDER_ROUTERS', False):
      node.border_router = self.cleaned_data.get('border_router') 
    
    node.status = NodeStatus.New
    node.save()

    # Create node traffic control policy
    tc_ingress = self.cleaned_data.get('tc_ingress')
    if tc_ingress:
      Policy.set_policy(node, node.vpn_mac_conf, PolicyAction.Shape, tc_ingress, PolicyFamily.Ethernet)
    
    # Create node profile for image generator
    if self.cleaned_data.get('template'):
      profile = Profile(node = node, template = self.cleaned_data.get('template'))
      if self.cleaned_data.get('channel') in ('', "0", None):
        profile.channel = node.project.channel
      else:
        profile.channel = self.cleaned_data.get('channel')
      profile.root_pass = self.cleaned_data.get('root_pass')
      profile.use_vpn = self.cleaned_data.get('use_vpn')
      profile.antenna = self.cleaned_data.get('ant_conn') or 0
      profile.lan_bridge = self.cleaned_data.get('lan_bridge') or False
      profile.wan_dhcp = self.cleaned_data.get('wan_dhcp')
      profile.wan_ip = self.cleaned_data.get('wan_ip')
      profile.wan_cidr = self.cleaned_data.get('wan_cidr')
      profile.wan_gw = self.cleaned_data.get('wan_gw')

      if self.cleaned_data.get('tc_egress'):
        profile.vpn_egress_limit = self.cleaned_data.get('tc_egress').bandwidth

      profile.save()

      profile.optional_packages = self.cleaned_data.get('optional_packages')
      profile.save()

    if subnet:
      subnet.node = node
      subnet.save()

    # Update DNS entries
    Record.update_for_node(node)
    
    # Registers node name
    NodeNames(name = node.name, node = node).save()

    # Generate node added event
    Event.create_event(node, EventCode.NodeAdded, '', EventSource.NodeDatabase,
                       data = 'Maintainer: %s' % node.owner.username)

    self.node = node
    return node
Example #2
0
  def save(self, node, user):
    """
    Completes node data update.
    """
    self.requires_firmware_update = False
    ip = self.cleaned_data.get('ip')
    oldName = node.name
    oldProject = node.project
    
    # Update node metadata
    node.name = self.cleaned_data.get('name').lower()
    node.owner = self.cleaned_data.get('owner')
    node.location = self.cleaned_data.get('location')
    node.geo_lat = self.cleaned_data.get('geo_lat')
    node.geo_long = self.cleaned_data.get('geo_long')
    node.ant_external = self.cleaned_data.get('ant_external')
    node.ant_polarization = self.cleaned_data.get('ant_polarization')
    node.ant_type = self.cleaned_data.get('ant_type')
    node.project = self.cleaned_data.get('project')
    node.node_type = self.cleaned_data.get('node_type')
    node.notes = self.cleaned_data.get('notes')
    node.url = self.cleaned_data.get('url')
    node.redundancy_req = self.cleaned_data.get('redundancy_req')

    if user.is_staff:
      node.system_node = self.cleaned_data.get('system_node')
      node.vpn_server = self.cleaned_data.get('vpn_server')
    
    if user.is_staff or getattr(settings, 'NONSTAFF_BORDER_ROUTERS', False):
      node.border_router = self.cleaned_data.get('border_router')
    
    node.save()

    # Update node traffic control policy
    tc_ingress = self.cleaned_data.get('tc_ingress')
    if tc_ingress:
      Policy.set_policy(node, node.vpn_mac_conf, PolicyAction.Shape, tc_ingress, PolicyFamily.Ethernet)
    else:
      try:
        node.gw_policy.get(addr = node.vpn_mac_conf, family = PolicyFamily.Ethernet).delete()
      except Policy.DoesNotExist:
        pass

    # Update DNS records on name changes
    if oldName != node.name or oldProject != node.project:
      Record.update_for_node(node, old_name = oldName, old_project = oldProject)

      # Generate node renamed event
      if oldName != node.name:
        Event.create_event(node, EventCode.NodeRenamed, '', EventSource.NodeDatabase, data = 'Old name: %s\n  New name: %s' % (oldName, node.name))

    # Update node profile for image generator
    try:
      profile = node.profile
    except Profile.DoesNotExist:
      profile = None

    if self.cleaned_data.get('template'):
      if not profile:
        profile = Profile(node = node, template = self.cleaned_data.get('template'))
      
      # Handle potential hardware changes
      new_template = self.cleaned_data.get('template')
      if profile.template != new_template:
        # Rename traffic graphs to preserve history
        node.rename_graphs(GraphType.Traffic, profile.template.iface_wifi, new_template.iface_wifi)
      
      def set_and_check(**kwargs):
        for key, value in kwargs.iteritems():
          field = getattr(profile, key)
          meta = profile._meta.get_field(key)
          prep = meta.get_db_prep_value(value, connection)
          
          if isinstance(meta, models.ManyToManyField):
            if set([m.pk for m in field.all()]) != set([m.pk for m in value]):
              self.requires_firmware_update = True
          elif field != prep:
            self.requires_firmware_update = True
          
          setattr(profile, key, value)
      
      if not self.cleaned_data.get('channel'):
        set_and_check(channel = node.project.channel)
      else:
        set_and_check(channel = self.cleaned_data.get('channel'))
      
      set_and_check(
        template = self.cleaned_data.get('template'),
        root_pass = self.cleaned_data.get('root_pass'),
        use_vpn = self.cleaned_data.get('use_vpn'),
        antenna = self.cleaned_data.get('ant_conn') or 0,
        lan_bridge = self.cleaned_data.get('lan_bridge') or False,
        wan_dhcp = self.cleaned_data.get('wan_dhcp'),
        wan_ip = self.cleaned_data.get('wan_ip'),
        wan_cidr = self.cleaned_data.get('wan_cidr'),
        wan_gw = self.cleaned_data.get('wan_gw')
      )
      
      if self.cleaned_data.get('tc_egress'):
        set_and_check(vpn_egress_limit = self.cleaned_data.get('tc_egress').bandwidth)
      else:
        set_and_check(vpn_egress_limit = None)
 
      profile.save()

      set_and_check(optional_packages = self.cleaned_data.get('optional_packages'))
      profile.save()
    elif profile and (settings.IMAGE_GENERATOR_ENABLED or settings.DEBUG):
      profile.delete()
    
    # Registers node name
    NodeNames(name = node.name, node = node).save()
    
    return node
Example #3
0
 def save(self):
   """
   Performs the actual renumbering.
   """
   # We must ensure exclusive access during node updates as otherwise this might happen
   # in the middle of a monitor update and this would cause unwanted consequences
   self.__node.ensure_exclusive_access()
   
   # Determine what subnet primary IP belonged to
   primary = self.__node.get_primary_subnet()
   renumber_primary = False
   old_router_id = self.__node.ip
   
   # Renumber subnets first
   for subnet in queryset_by_ip(self.__node.subnet_set.filter(allocated = True), 'ip_subnet')[:]:
     action = int(self.cleaned_data.get('subnet_%s' % subnet.pk))
     prefix_len = int(self.cleaned_data.get('prefix_%s' % subnet.pk) or 27)
     manual_ip = self.cleaned_data.get('manual_%s' % subnet.pk)
     
     if action == RenumberAction.Keep:
       pass
     elif action == RenumberAction.Remove:
       subnet.delete()
     else:
       # This means we should renumber to some other pool
       pool = Pool.objects.get(pk = action)
       if manual_ip:
         new_subnet = pool.reserve_subnet(manual_ip, prefix_len)
       else:
         new_subnet = pool.allocate_subnet(prefix_len)
       
       # If the old subnet has been the source of node's primary IP remember that
       save_primary = (not renumber_primary and primary and primary[0] == subnet)
       
       # Remove old subnet and create a new one; it is deleted here so the old allocation
       # is returned to the pool and all status info is reset
       subnet.delete()
       
       s = Subnet(node = self.__node, subnet = new_subnet.network, cidr = new_subnet.cidr)
       s.allocated = True
       s.allocated_at = datetime.now()
       s.status = SubnetStatus.NotAnnounced
       s.description = subnet.description
       s.gen_iface_type = subnet.gen_iface_type
       s.gen_dhcp = subnet.gen_dhcp
       s.save()
       
       if save_primary:
         primary = s
         renumber_primary = True
   
   # The subnet have now been renumbered, check if we need to renumber the primary IP
   router_id_changed = False
   if renumber_primary:
     net = ipcalc.Network(primary.subnet, primary.cidr)
     self.__node.ip = str(net.host_first())
     router_id_changed = True
   
   # Remove conflicting invalid nodes (another node with the IP we just renumbered to)
   existing_nodes = Node.objects.filter(ip = self.__node.ip, status = NodeStatus.Invalid)
   if existing_nodes.count() > 0:
     self.warning_or_continue(_("There is an existing but unregistered node with the same primary IP address you are currently renumbering to! If you continue with this operation, this invalid node will be replaced."))
   existing_nodes.delete()
   
   # Node has been renumbered, reset monitoring status as this node is obviously not
   # visible right after renumbering.
   if router_id_changed:
     # Update node's DNS record
     Record.update_for_node(self.__node)
     
     if not self.__node.is_pending():
       self.__node.status = NodeStatus.Down
       self.__node.peers = 0
       Link.objects.filter(src = self.__node).delete()
       Link.objects.filter(dst = self.__node).delete()
       self.__node.subnet_set.filter(allocated = False).delete()
       self.__node.subnet_set.all().update(status = SubnetStatus.NotAnnounced)
       
       # Setup a node renumbered notice (if one doesn't exist yet)
       try:
         notice = RenumberNotice.objects.get(node = self.__node)
         
         if notice.original_ip == self.__node.ip:
           notice.delete()
           self.__node.awaiting_renumber = False
         else:
           self.__node.awaiting_renumber = True
       except RenumberNotice.DoesNotExist:
         notice = RenumberNotice(node = self.__node)
         notice.original_ip = old_router_id
         notice.renumbered_at = datetime.now()
         notice.save()
         self.__node.awaiting_renumber = True
   
   self.__node.save()
   
   # Generate node renumbered event
   Event.create_event(self.__node, EventCode.NodeRenumbered, '', EventSource.NodeDatabase,
                      data = 'Old address: %s' % old_router_id)