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…
Reference in a new issue