in between commit
Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
		
					parent
					
						
							
								3d2f8574d3
							
						
					
				
			
			
				commit
				
					
						d3f2a3e071
					
				
			
		
					 4 changed files with 125 additions and 21 deletions
				
			
		| 
						 | 
				
			
			@ -11,3 +11,6 @@ parsedatetime
 | 
			
		|||
pyparsing
 | 
			
		||||
pydot
 | 
			
		||||
django-extensions
 | 
			
		||||
 | 
			
		||||
# PDF creating
 | 
			
		||||
django-hardcopy
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,32 +13,52 @@ log = logging.getLogger(__name__)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
wireguard_template="""
 | 
			
		||||
 | 
			
		||||
[Interface]
 | 
			
		||||
ListenPort = 51820
 | 
			
		||||
PrivateKey = {privatekey}
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
# Nico, 2019-01-23, Switzerland
 | 
			
		||||
#[Peer]
 | 
			
		||||
#PublicKey = kL1S/Ipq6NkFf1MAsNRou4b9VoUsnnb4ZxgiBrH0zA8=
 | 
			
		||||
#AllowedIPs = 2a0a:e5c1:101::/48
 | 
			
		||||
peer_template="""
 | 
			
		||||
# {username}
 | 
			
		||||
[Peer]
 | 
			
		||||
PublicKey = {public_key}
 | 
			
		||||
AllowedIPs = {vpnnetwork}
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
    help = 'General uncloud commands'
 | 
			
		||||
 | 
			
		||||
    def add_arguments(self, parser):
 | 
			
		||||
        parser.add_argument('--hostname', action='store_true', help='Name of this VPN Host',
 | 
			
		||||
        parser.add_argument('--hostname',
 | 
			
		||||
                            action='store_true',
 | 
			
		||||
                            help='Name of this VPN Host',
 | 
			
		||||
                            required=True)
 | 
			
		||||
 | 
			
		||||
    def handle(self, *args, **options):
 | 
			
		||||
#        for net
 | 
			
		||||
        if options['bootstrap']:
 | 
			
		||||
            self.bootstrap()
 | 
			
		||||
 | 
			
		||||
        self.create_vpn_config(options['hostname'])
 | 
			
		||||
 | 
			
		||||
    def create_vpn_config(self, hostname):
 | 
			
		||||
        for pool in VPNPool.objects.filter(vpn_hostname
 | 
			
		||||
        default_cluster = VPNNetwork.objects.get_or_create(name="default")
 | 
			
		||||
#        local_host =
 | 
			
		||||
        configs = []
 | 
			
		||||
 | 
			
		||||
        for pool in VPNPool.objects.filter(vpn_hostname=hostname):
 | 
			
		||||
            pool_config = {
 | 
			
		||||
                'private_key': pool.wireguard_private_key,
 | 
			
		||||
                'subnetwork_size': pool.subnetwork_size,
 | 
			
		||||
                'config_file': '/etc/wireguard/{}.conf'.format(pool.network),
 | 
			
		||||
                'peers': []
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for vpnnetwork in VPNNetworkReservation.objects.filter(vpnpool=pool):
 | 
			
		||||
                pool_config['peers'].append({
 | 
			
		||||
                    'vpnnetwork': "{}/{}".format(vpnnetwork.address,
 | 
			
		||||
                                                 pool_config['subnetwork_size']),
 | 
			
		||||
                    'public_key': vpnnetwork.wireguard_public_key,
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            configs.append(pool_config)
 | 
			
		||||
 | 
			
		||||
        print(configs)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,30 +23,96 @@ class VPNPool(UncloudModel):
 | 
			
		|||
    network_size = models.IntegerField(validators=[MinValueValidator(0),
 | 
			
		||||
                                                   MaxValueValidator(128)])
 | 
			
		||||
 | 
			
		||||
    subnetwork_size = models.IntegerField(validators=[MinValueValidator(0),
 | 
			
		||||
                                                   MaxValueValidator(128)])
 | 
			
		||||
    subnetwork_size = models.IntegerField(validators=[
 | 
			
		||||
                                              MinValueValidator(0),
 | 
			
		||||
                                              MaxValueValidator(128)
 | 
			
		||||
                                          ])
 | 
			
		||||
 | 
			
		||||
    vpn_hostname = models.CharField(max_length=256)
 | 
			
		||||
 | 
			
		||||
    wireguard_private_key = models.CharField(max_length=48)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def num_maximum_networks(self):
 | 
			
		||||
        """
 | 
			
		||||
        sample:
 | 
			
		||||
        network_size = 40
 | 
			
		||||
        subnetwork_size = 48
 | 
			
		||||
        maximum_networks = 2^(48-40)
 | 
			
		||||
 | 
			
		||||
        2nd sample:
 | 
			
		||||
        network_size = 8
 | 
			
		||||
        subnetwork_size = 24
 | 
			
		||||
        maximum_networks = 2^(24-8)
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        return 2**(subnetwork_size - network_size)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def used_networks(self):
 | 
			
		||||
        return self.vpnnetworkreservation_set.objects.filter(vpnpool=self, status='used')
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def num_used_networks(self):
 | 
			
		||||
        return len(self.used_networks)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def num_free_networks(self):
 | 
			
		||||
        return self.num_maximum_networks - self.num_used_networks
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def next_free_network(self):
 | 
			
		||||
        free_net = self.vpnnetworkreservation_set.objects.filter(vpnpool=self,
 | 
			
		||||
                                                                 status='free')
 | 
			
		||||
 | 
			
		||||
        last_net = self.vpnnetworkreservation_set.objects.filter(vpnpool=self,
 | 
			
		||||
                                                                 status='used')
 | 
			
		||||
 | 
			
		||||
        if num_free_networks == 0:
 | 
			
		||||
            raise Exception("No free networks")
 | 
			
		||||
 | 
			
		||||
        if len(free_net) > 0:
 | 
			
		||||
            return free_net[0].address
 | 
			
		||||
 | 
			
		||||
        if len(used_net) > 0:
 | 
			
		||||
            """
 | 
			
		||||
            sample:
 | 
			
		||||
 | 
			
		||||
            pool = 2a0a:e5c1:200::/40
 | 
			
		||||
            last_used = 2a0a:e5c1:204::/48
 | 
			
		||||
 | 
			
		||||
            next:
 | 
			
		||||
            """
 | 
			
		||||
 | 
			
		||||
            last_ip = last_net.address
 | 
			
		||||
#            next_ip =
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VPNNetworkReservation(UncloudModel):
 | 
			
		||||
    """
 | 
			
		||||
    This class tracks the used VPN networks. It will be deleted, when the product is cancelled.
 | 
			
		||||
    """
 | 
			
		||||
     This class tracks the used VPN networks. It will be deleted, when the product is cancelled.
 | 
			
		||||
     """
 | 
			
		||||
    vpnpool = models.ForeignKey(VPNPool,
 | 
			
		||||
                                  on_delete=models.CASCADE)
 | 
			
		||||
 | 
			
		||||
                                 on_delete=models.CASCADE)
 | 
			
		||||
    address = models.GenericIPAddressField(primary_key=True)
 | 
			
		||||
 | 
			
		||||
    status = models.CharField(max_length=256,
 | 
			
		||||
                              choices = (
 | 
			
		||||
                                  ('used', 'used'),
 | 
			
		||||
                                  ('free', 'free')
 | 
			
		||||
                              )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VPNNetwork(Product):
 | 
			
		||||
    """
 | 
			
		||||
    A selected network. Used for tracking reservations / used networks
 | 
			
		||||
    """
 | 
			
		||||
    network = models.ForeignKey(VPNNetworkReservation,
 | 
			
		||||
                                on_delete=models.CASCADE,
 | 
			
		||||
                                editable=False)
 | 
			
		||||
                               on_delete=models.CASCADE,
 | 
			
		||||
                               editable=False)
 | 
			
		||||
 | 
			
		||||
    wireguard_public_key = models.CharField(max_length=48)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,6 @@ class VPNPoolSerializer(serializers.ModelSerializer):
 | 
			
		|||
        fields = '__all__'
 | 
			
		||||
 | 
			
		||||
class VPNNetworkSerializer(serializers.ModelSerializer):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = VPNNetwork
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
| 
						 | 
				
			
			@ -53,8 +52,24 @@ class VPNNetworkSerializer(serializers.ModelSerializer):
 | 
			
		|||
            msg = _("No pool available for networks with size = {}. Available are: {}".format(data['network_size'], sizes))
 | 
			
		||||
            raise serializers.ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        from_pool =
 | 
			
		||||
        """
 | 
			
		||||
        Creating a new vpnnetwork - there are a couple of race conditions,
 | 
			
		||||
        especially when run in parallel.
 | 
			
		||||
        """
 | 
			
		||||
        pools = VPNPool.objects.filter(subnetwork_size=data['network_size'])
 | 
			
		||||
 | 
			
		||||
        found_pool = False
 | 
			
		||||
        for pool in pools:
 | 
			
		||||
            if pool.num_free_networks > 0:
 | 
			
		||||
                found_pool = True
 | 
			
		||||
#                address = pool.
 | 
			
		||||
#                reservation = VPNNetworkReservation(vpnpool=pool,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        pool = VPNPool.objects.first(subnetwork_size=data['network_size'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return VPNNetwork(**validated_data)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue