Add docstrings for VPN service
diff --git a/xos/observers/vpn/steps/sync_vpntenant.py b/xos/observers/vpn/steps/sync_vpntenant.py
index b579f12..d6bc664 100644
--- a/xos/observers/vpn/steps/sync_vpntenant.py
+++ b/xos/observers/vpn/steps/sync_vpntenant.py
@@ -8,6 +8,7 @@
 sys.path.insert(0, parentdir)
 
 class SyncVPNTenant(SyncInstanceUsingAnsible):
+    """Class for syncing a VPNTenant using Ansible."""
     provides = [VPNTenant]
     observes = VPNTenant
     requested_interval = 0
@@ -36,7 +37,12 @@
                 "client_address": o.client_address}
 
     def generate_client_conf(self, tenant):
-        # tenant.nat_ip maybe None when the first line executes
+        """str: Generates the client configuration to use to connect to this VPN server.
+
+        Args:
+            tenant (VPNTenant): The tenant to generate the client configuration for.
+            
+        """
         conf = "remote " + str(tenant.nat_ip) + "\n"
         conf += "dev tun\n"
         conf += "ifconfig " + tenant.client_address + " " + tenant.server_address + "\n"
diff --git a/xos/services/vpn/admin.py b/xos/services/vpn/admin.py
index f7e78f8..a7096be 100644
--- a/xos/services/vpn/admin.py
+++ b/xos/services/vpn/admin.py
@@ -1,13 +1,16 @@
 
+from subprocess import PIPE, Popen
+
 from core.admin import ReadOnlyAwareAdmin, SliceInline
 from core.middleware import get_request
 from core.models import User
 from django import forms
 from django.contrib import admin
-from subprocess import Popen, PIPE
-from services.vpn.models import VPNService, VPNTenant, VPN_KIND
+from services.vpn.models import VPN_KIND, VPNService, VPNTenant
+
 
 class VPNServiceAdmin(ReadOnlyAwareAdmin):
+    """Defines the admin for the VPNService."""
     model = VPNService
     verbose_name = "VPN Service"
 
@@ -38,12 +41,27 @@
     def queryset(self, request):
         return VPNService.get_service_objects_by_user(request.user)
 
+
 class VPNTenantForm(forms.ModelForm):
+    """The form used to create and edit a VPNTenant.
+
+    Attributes:
+        creator (forms.ModelChoiceField): The XOS user that created this tenant.
+        server_key (forms.CharField): The readonly static key used to the connect to this Tenant.
+        client_conf (forms.CharField): The readonly configuration used on the client to connect to this Tenant.
+        server_address (forms.GenericIPAddressField): The ip address on the VPN of this Tenant.
+        client_address (forms.GenericIPAddressField): The ip address on the VPN of the client.
+        is_persistent (forms.BooleanField): Determines if this Tenant keeps this connection alive through failures.
+        can_view_subnet (forms.BooleanField): Determins if this Tenant makes it's subnet available to the client.
+    
+    """
     creator = forms.ModelChoiceField(queryset=User.objects.all())
     server_key = forms.CharField(required=False, widget=forms.Textarea)
     client_conf = forms.CharField(required=False, widget=forms.Textarea)
-    server_address = forms.GenericIPAddressField(protocol='IPv4', required=True)
-    client_address = forms.GenericIPAddressField(protocol='IPv4', required=True)
+    server_address = forms.GenericIPAddressField(
+        protocol='IPv4', required=True)
+    client_address = forms.GenericIPAddressField(
+        protocol='IPv4', required=True)
     is_persistent = forms.BooleanField(required=False)
     can_view_subnet = forms.BooleanField(required=False)
 
@@ -61,10 +79,13 @@
             self.fields['creator'].initial = self.instance.creator
             self.fields['server_key'].initial = self.instance.server_key
             self.fields['client_conf'].initial = self.instance.client_conf
-            self.fields['server_address'].initial = self.instance.server_address
-            self.fields['client_address'].initial = self.instance.client_address
+            self.fields[
+                'server_address'].initial = self.instance.server_address
+            self.fields[
+                'client_address'].initial = self.instance.client_address
             self.fields['is_persistent'].initial = self.instance.is_persistent
-            self.fields['can_view_subnet'].initial = self.instance.can_view_subnet
+            self.fields[
+                'can_view_subnet'].initial = self.instance.can_view_subnet
 
         if (not self.instance) or (not self.instance.pk):
             self.fields['creator'].initial = get_request().user
@@ -74,7 +95,8 @@
             self.fields['is_persistent'].initial = True
             self.fields['can_view_subnet'].initial = False
             if VPNService.get_service_objects().exists():
-                self.fields["provider_service"].initial = VPNService.get_service_objects().all()[0]
+                self.fields["provider_service"].initial = VPNService.get_service_objects().all()[
+                    0]
 
     def save(self, commit=True):
         self.instance.creator = self.cleaned_data.get("creator")
@@ -82,17 +104,21 @@
         self.instance.server_address = self.cleaned_data.get("server_address")
         self.instance.client_address = self.cleaned_data.get("client_address")
         self.instance.is_persistent = self.cleaned_data.get('is_persistent')
-        self.instance.can_view_subnet = self.cleaned_data.get('can_view_subnet')
+        self.instance.can_view_subnet = self.cleaned_data.get(
+            'can_view_subnet')
         return super(VPNTenantForm, self).save(commit=commit)
 
     def generate_VPN_key(self):
-        proc = Popen("openvpn --genkey --secret /dev/stdout", shell=True, stdout=PIPE)
+        """Generates a VPN key using the openvpn command."""
+        proc = Popen("openvpn --genkey --secret /dev/stdout",
+                     shell=True, stdout=PIPE)
         (stdout, stderr) = proc.communicate()
         return stdout
 
     class Meta:
         model = VPNTenant
 
+
 class VPNTenantAdmin(ReadOnlyAwareAdmin):
     verbose_name = "VPN Tenant Admin"
     list_display = ('id', 'backend_status_icon', 'instance')
diff --git a/xos/services/vpn/models.py b/xos/services/vpn/models.py
index b3d2768..313fcc6 100644
--- a/xos/services/vpn/models.py
+++ b/xos/services/vpn/models.py
@@ -1,9 +1,12 @@
 from core.models import Service, TenantWithContainer
 from django.db import transaction
+from typing import Mapping, tuple
 
 VPN_KIND = "vpn"
 
+
 class VPNService(Service):
+    """Defines the Service for creating VPN servers."""
     KIND = VPN_KIND
 
     class Meta:
@@ -12,7 +15,9 @@
         app_label = "vpn"
         verbose_name = "VPN Service"
 
+
 class VPNTenant(TenantWithContainer):
+    """Defines the Tenant for creating VPN servers."""
 
     class Meta:
         proxy = True
@@ -46,6 +51,7 @@
 
     @property
     def server_key(self):
+        """str: The server_key used to connect to the VPN server."""
         return self.get_attribute(
             "server_key",
             self.default_attributes['server_key'])
@@ -56,6 +62,7 @@
 
     @property
     def addresses(self):
+        """Mapping[str, Tuple[str, str, str]]: The ip, mac address, and subnet of networks of this Tenant."""
         if (not self.id) or (not self.instance):
             return {}
 
@@ -71,19 +78,23 @@
     # This getter is necessary because nat_ip is a sync_attribute
     @property
     def nat_ip(self):
+        """str: The IP of this Tenant on the NAT network."""
         return self.addresses.get("nat", (None, None, None))[0]
 
     # This getter is necessary because nat_mac is a sync_attribute
     @property
     def nat_mac(self):
+        """str: The MAC address of this Tenant on the NAT network."""
         return self.addresses.get("nat", (None, None, None))[1]
 
     @property
     def subnet(self):
+        """str: The subnet of this Tenant on the NAT network."""
         return self.addresses.get("nat", (None, None, None))[2]
 
     @property
     def server_address(self):
+        """str: The IP address of the server on the VPN."""
         return self.get_attribute(
             'server_address',
             self.default_attributes['server_address'])
@@ -94,6 +105,7 @@
 
     @property
     def client_address(self):
+        """str: The IP address of the client on the VPN."""
         return self.get_attribute(
             'client_address',
             self.default_attributes['client_address'])
@@ -104,6 +116,7 @@
 
     @property
     def client_conf(self):
+        """str: The client configuration for the client to connect to this server."""
         return self.get_attribute(
             "client_conf",
             self.default_attributes['client_conf'])
@@ -114,6 +127,7 @@
 
     @property
     def is_persistent(self):
+        """bool: True if the VPN connection is persistence, false otherwise."""
         return self.get_attribute(
             "is_persistent",
             self.default_attributes['is_persistent'])
@@ -124,6 +138,7 @@
 
     @property
     def can_view_subnet(self):
+        """bool: True if the client can see the subnet of the server, false otherwise."""
         return self.get_attribute(
             "can_view_subnet",
             self.default_attributes['can_view_subnet'])
@@ -134,6 +149,7 @@
 
 
 def model_policy_vpn_tenant(pk):
+    """Manages the contain for the VPN Tenant."""
     # This section of code is atomic to prevent race conditions
     with transaction.atomic():
         # We find all of the tenants that are waiting to update