Merge branch 'master' of github.com:jermowery/xos into AddVPNService
diff --git a/containers/xos/Dockerfile.devel b/containers/xos/Dockerfile.devel
index 93f5025..29f1779 100644
--- a/containers/xos/Dockerfile.devel
+++ b/containers/xos/Dockerfile.devel
@@ -34,7 +34,8 @@
python-novaclient \
python-neutronclient \
python-glanceclient \
- python-ceilometerclient
+ python-ceilometerclient \
+ openvpn
RUN pip install \
django==1.7 \
diff --git a/xos/configurations/common/Dockerfile.common b/xos/configurations/common/Dockerfile.common
index fd27593..11f51fc 100644
--- a/xos/configurations/common/Dockerfile.common
+++ b/xos/configurations/common/Dockerfile.common
@@ -28,7 +28,8 @@
python-dev \
libyaml-dev \
pkg-config \
- python-pycurl
+ python-pycurl \
+ openvpn
RUN pip install django==1.7
RUN pip install djangorestframework==2.4.4
diff --git a/xos/configurations/devel/docker-compose.yml b/xos/configurations/devel/docker-compose.yml
index 803e57c..fa3baa8 100644
--- a/xos/configurations/devel/docker-compose.yml
+++ b/xos/configurations/devel/docker-compose.yml
@@ -16,6 +16,19 @@
volumes:
- ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+xos_synchronizer_vpn:
+ image: xosproject/xos-synchronizer-openstack
+ command: bash -c "sleep 120 ; python /opt/xos/synchronizers/vpn/vpn-synchronizer.py -C /opt/xos/synchronizers/vpn/vpn_config"
+ labels:
+ org.xosproject.kind: synchronizer
+ org.xosproject.target: vpn
+ links:
+ - xos_db
+ extra_hosts:
+ - ctl:${MYIP}
+ volumes:
+ - ../setup/id_rsa:/opt/xos/synchronizers/vpn/vpn_private_key:ro # private key
+
# FUTURE
#xos_swarm_synchronizer:
# image: xosproject/xos-swarm-synchronizer
diff --git a/xos/core/admin.py b/xos/core/admin.py
index bc083c4..21b7565 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -270,6 +270,9 @@
def backend_status_text(self, obj):
return mark_safe(backend_text(obj))
+ def script_link(self, obj):
+ return mark_safe('<a href="%s" target="_blank">Script link</a>' % obj.file_name)
+
def backend_status_icon(self, obj):
return mark_safe(backend_icon(obj))
backend_status_icon.short_description = ""
@@ -494,7 +497,7 @@
class SiteHostsUsersInline(SiteInline):
def queryset(self, request):
- return Site.select_by_user(request.user).filter(hosts_users=True)
+ return Site.select_by_user(request.user).filter(hosts_users=True)
class UserInline(XOSTabularInline):
model = User
@@ -571,7 +574,7 @@
kwargs['queryset'] = Service.select_by_user(request.user)
if db_field.name == 'user':
kwargs['queryset'] = User.select_by_user(request.user)
- return super(ServicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+ return super(ServicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
def queryset(self, request):
return ServicePrivilege.select_by_user(request.user)
@@ -803,12 +806,12 @@
def save_model(self, request, obj, form, change):
# update openstack connection to use this site/tenant
obj.save_by_user(request.user)
-
+
def delete_model(self, request, obj):
obj.delete_by_user(request.user)
def queryset(self, request):
- return Controller.select_by_user(request.user)
+ return Controller.select_by_user(request.user)
@property
def suit_form_tabs(self):
@@ -1001,11 +1004,11 @@
def save_model(self, request, obj, form, change):
# update openstack connection to use this site/tenant
- obj.save_by_user(request.user)
+ obj.save_by_user(request.user)
def delete_model(self, request, obj):
obj.delete_by_user(request.user)
-
+
class SitePrivilegeAdmin(XOSBaseAdmin):
fieldList = ['backend_status_text', 'user', 'site', 'role']
@@ -1103,7 +1106,7 @@
('slicenetworks','Networks'),
('sliceprivileges','Privileges'),
('instances','Instances'),
- #('reservations','Reservations'),
+ #('reservations','Reservations'),
('tags','Tags'),
]
@@ -1112,7 +1115,7 @@
tabs.append( ('admin-only', 'Admin-Only') )
return tabs
-
+
def add_view(self, request, form_url='', extra_context=None):
# Ugly hack for CORD
self.inlines = self.normal_inlines
@@ -1209,7 +1212,7 @@
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'slice':
kwargs['queryset'] = Slice.select_by_user(request.user)
-
+
if db_field.name == 'user':
kwargs['queryset'] = User.select_by_user(request.user)
@@ -1589,12 +1592,12 @@
login_details_fields.remove('profile')
#if len(request.user.siteprivileges.filter(role__role = 'pi')) > 0:
# only admins and pis can change a user's site
- # self.readonly_fields = ('backend_status_text', 'site')
+ # self.readonly_fields = ('backend_status_text', 'site')
self.fieldsets = (
('Login Details', {'fields': login_details_fields, 'classes':['suit-tab suit-tab-general']}),
('Contact Information', {'fields': self.fieldListContactInfo, 'classes':['suit-tab suit-tab-contact']}),
)
- return super(UserAdmin, self).get_form(request, obj, **kwargs)
+ return super(UserAdmin, self).get_form(request, obj, **kwargs)
class ControllerDashboardViewInline(XOSTabularInline):
model = ControllerDashboardView
@@ -2067,7 +2070,7 @@
# unregister the Group model from admin.
#admin.site.unregister(Group)
-# When debugging it is often easier to see all the classes, but for regular use
+# When debugging it is often easier to see all the classes, but for regular use
# only the top-levels should be displayed
showAll = False
@@ -2103,4 +2106,3 @@
admin.site.register(TenantRootRole, TenantRootRoleAdmin)
admin.site.register(TenantAttribute, TenantAttributeAdmin)
# admin.site.register(Container, ContainerAdmin)
-
diff --git a/xos/services/vpn/__init__.py b/xos/services/vpn/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/vpn/__init__.py
diff --git a/xos/services/vpn/admin.py b/xos/services/vpn/admin.py
new file mode 100644
index 0000000..4f792c4
--- /dev/null
+++ b/xos/services/vpn/admin.py
@@ -0,0 +1,141 @@
+import time
+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 services.vpn.models import VPN_KIND, VPNService, VPNTenant
+
+
+class VPNServiceAdmin(ReadOnlyAwareAdmin):
+ """Defines the admin for the VPNService."""
+ model = VPNService
+ verbose_name = "VPN Service"
+
+ list_display = ("backend_status_icon", "name", "enabled")
+
+ list_display_links = ('backend_status_icon', 'name', )
+
+ fieldsets = [(None, {'fields': ['backend_status_text', 'name', 'enabled',
+ 'versionNumber', 'description', "view_url"],
+ 'classes':['suit-tab suit-tab-general']})]
+
+ readonly_fields = ('backend_status_text', )
+
+ inlines = [SliceInline]
+
+ extracontext_registered_admins = True
+
+ user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+ suit_form_tabs = (('general', 'VPN Service Details'),
+ ('administration', 'Tenants'),
+ ('slices', 'Slices'),)
+
+ suit_form_includes = (('vpnserviceadmin.html',
+ 'top',
+ 'administration'),)
+
+ 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.
+ 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_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)
+
+
+ def __init__(self, *args, **kwargs):
+ super(VPNTenantForm, self).__init__(*args, **kwargs)
+ self.fields['kind'].widget.attrs['readonly'] = True
+ # self.fields['script_name'].widget.attrs['readonly'] = True
+ self.fields[
+ 'provider_service'].queryset = VPNService.get_service_objects().all()
+
+ self.fields['kind'].initial = VPN_KIND
+
+ if self.instance:
+ self.fields['creator'].initial = self.instance.creator
+ 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
+
+ if (not self.instance) or (not self.instance.pk):
+ self.fields['creator'].initial = get_request().user
+ self.fields['server_address'].initial = "10.8.0.1"
+ self.fields['client_address'].initial = "10.8.0.2"
+ 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]
+
+ def save(self, commit=True):
+ self.instance.creator = self.cleaned_data.get("creator")
+ 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')
+
+ if (not self.instance.script):
+ self.instance.script_name = "hello.vpn"
+
+ if (not self.instance.server_key):
+ self.instance.server_key = self.generate_VPN_key()
+
+ return super(VPNTenantForm, self).save(commit=commit)
+
+ def generate_VPN_key(self):
+ """str: 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')
+ list_display_links = ('id', 'backend_status_icon', 'instance')
+ fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+ 'provider_service', 'instance', 'creator',
+ 'server_address', 'client_address',
+ 'is_persistent', 'can_view_subnet'],
+ 'classes': ['suit-tab suit-tab-general']})]
+ readonly_fields = ('backend_status_text', 'instance')
+ form = VPNTenantForm
+
+ suit_form_tabs = (('general', 'Details'),)
+
+ def queryset(self, request):
+ return VPNTenant.get_tenant_objects_by_user(request.user)
+
+# Associate the admin forms with the models.
+admin.site.register(VPNService, VPNServiceAdmin)
+admin.site.register(VPNTenant, VPNTenantAdmin)
diff --git a/xos/services/vpn/models.py b/xos/services/vpn/models.py
new file mode 100644
index 0000000..cd7ca40
--- /dev/null
+++ b/xos/services/vpn/models.py
@@ -0,0 +1,159 @@
+from core.models import Service, TenantWithContainer
+from django.db import transaction
+
+VPN_KIND = "vpn"
+
+
+class VPNService(Service):
+ """Defines the Service for creating VPN servers."""
+ KIND = VPN_KIND
+
+ class Meta:
+ proxy = True
+ # The name used to find this service, all directories are named this
+ app_label = "vpn"
+ verbose_name = "VPN Service"
+
+
+class VPNTenant(TenantWithContainer):
+ """Defines the Tenant for creating VPN servers."""
+
+ class Meta:
+ proxy = True
+ verbose_name = "VPN Tenant"
+
+ KIND = VPN_KIND
+
+ sync_attributes = ("nat_ip", "nat_mac",)
+
+ default_attributes = {'server_key': None,
+ 'server_address': '10.8.0.1',
+ 'client_address': '10.8.0.2',
+ 'can_view_subnet': False,
+ 'is_persistent': True,
+ 'script_name': None}
+
+ def __init__(self, *args, **kwargs):
+ vpn_services = VPNService.get_service_objects().all()
+ if vpn_services:
+ self._meta.get_field(
+ "provider_service").default = vpn_services[0].id
+ super(VPNTenant, self).__init__(*args, **kwargs)
+
+ def save(self, *args, **kwargs):
+ super(VPNTenant, self).save(*args, **kwargs)
+ model_policy_vpn_tenant(self.pk)
+
+ def delete(self, *args, **kwargs):
+ self.cleanup_container()
+ super(VPNTenant, self).delete(*args, **kwargs)
+
+ @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'])
+
+ @server_key.setter
+ def server_key(self, value):
+ self.set_attribute("server_key", value)
+
+ @property
+ def addresses(self):
+ """Mapping[str, str]: The ip, mac address, and subnet of the NAT network of this Tenant."""
+ if (not self.id) or (not self.instance):
+ return {}
+
+ addresses = {}
+ for ns in self.instance.ports.all():
+ if "nat" in ns.network.name.lower():
+ addresses["ip"] = ns.ip
+ addresses["mac"] = ns.mac
+ addresses["subnet"] = ns.network.subnet
+ break
+
+ return addresses
+
+ # 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("ip", None)
+
+ # 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("mac", None)
+
+ @property
+ def subnet(self):
+ """str: The subnet of this Tenant on the NAT network."""
+ return self.addresses.get("subnet", None)
+
+ @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'])
+
+ @server_address.setter
+ def server_address(self, value):
+ self.set_attribute("server_address", value)
+
+ @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'])
+
+ @client_address.setter
+ def client_address(self, value):
+ self.set_attribute("client_address", value)
+
+ @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'])
+
+ @is_persistent.setter
+ def is_persistent(self, value):
+ self.set_attribute("is_persistent", value)
+
+ @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'])
+
+ @can_view_subnet.setter
+ def can_view_subnet(self, value):
+ self.set_attribute("can_view_subnet", value)
+
+ @property
+ def script(self):
+ """string: The file name of the client script"""
+ self.get_attribute("script", self.default_attributes['script'])
+
+ @script.setter
+ def script(self, value):
+ self.set_attribute("script", value)
+
+
+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
+ tenant = VPNTenant.objects.select_for_update().filter(pk=pk)
+ if not tenant:
+ return
+ # Since this code is atomic it is safe to always use the first tenant
+ tenant = tenant[0]
+ tenant.manage_container()
diff --git a/xos/services/vpn/templates/vpnserviceadmin.html b/xos/services/vpn/templates/vpnserviceadmin.html
new file mode 100644
index 0000000..d983771
--- /dev/null
+++ b/xos/services/vpn/templates/vpnserviceadmin.html
@@ -0,0 +1,10 @@
+<!-- Template used to for the button leading to the HelloWorldTenantComplete form. -->
+<div class = "left-nav">
+ <ul>
+ <li>
+ <a href="/admin/vpn/vpntenant/">
+ VPN Tenants
+ </a>
+ </li>
+ </ul>
+</div>
diff --git a/xos/synchronizers/vpn/__init__.py b/xos/synchronizers/vpn/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/vpn/__init__.py
diff --git a/xos/synchronizers/vpn/model-deps b/xos/synchronizers/vpn/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/vpn/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/vpn/run.sh b/xos/synchronizers/vpn/run.sh
new file mode 100755
index 0000000..9a2e69b
--- /dev/null
+++ b/xos/synchronizers/vpn/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python vpn-synchronizer.py -C $XOS_DIR/synchronizers/vpn/vpn_config
diff --git a/xos/synchronizers/vpn/steps/__init__.py b/xos/synchronizers/vpn/steps/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/vpn/steps/__init__.py
diff --git a/xos/synchronizers/vpn/steps/sync_vpntenant.py b/xos/synchronizers/vpn/steps/sync_vpntenant.py
new file mode 100644
index 0000000..3e9e343
--- /dev/null
+++ b/xos/synchronizers/vpn/steps/sync_vpntenant.py
@@ -0,0 +1,77 @@
+import os
+import sys
+from django.db.models import Q, F
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from services.vpn.models import VPNTenant
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVPNTenant(SyncInstanceUsingAnsible):
+ """Class for syncing a VPNTenant using Ansible."""
+ provides = [VPNTenant]
+ observes = VPNTenant
+ requested_interval = 0
+ template_name = "sync_vpntenant.yaml"
+ service_key_name = "/opt/xos/synchronizers/vpn/vpn_private_key"
+
+ def __init__(self, *args, **kwargs):
+ super(SyncVPNTenant, self).__init__(*args, **kwargs)
+
+ def fetch_pending(self, deleted):
+ if (not deleted):
+ objs = VPNTenant.get_tenant_objects().filter(
+ Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+ else:
+ objs = VPNTenant.get_deleted_tenant_objects()
+
+ return objs
+
+ def get_extra_attributes(self, o):
+ return {"server_key": o.server_key.splitlines(),
+ "is_persistent": o.is_persistent,
+ "can_view_subnet": o.can_view_subnet,
+ "server_address": o.server_address,
+ "client_address": o.client_address}
+
+ def create_client_script(self, tenant):
+ script = open("/opt/xos/core/static/vpn/" + str(tenant.script), 'w')
+ # write the key portion
+ script.write("printf \"")
+ for line in tenant.server_key.splitlines():
+ script.write(line + r"\n")
+ script.write("\" > static.key\n")
+ # write the configuration portion
+ script.write("printf \"")
+ for line in self.generate_client_conf(tenant).splitlines():
+ script.write(line + r"\n")
+ script.write("\" > client.conf\n")
+ # make sure openvpn is installed
+ script.write("apt-get update\n")
+ script.write("apt-get install openvpn\n")
+ script.write("openvpn client.conf &")
+ # close the script
+ script.close()
+
+ def run_playbook(self, o, fields):
+ self.create_client_script(o)
+ super(SyncVPNTenant, self).run_playbook(o, fields)
+
+ def generate_client_conf(self, tenant):
+ """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"
+ conf += "secret static.key"
+ if tenant.is_persistent:
+ conf += "\nkeepalive 10 60\n"
+ conf += "ping-timer-rem\n"
+ conf += "persist-tun\n"
+ conf += "persist-key"
+
+ return conf
diff --git a/xos/synchronizers/vpn/steps/sync_vpntenant.yaml b/xos/synchronizers/vpn/steps/sync_vpntenant.yaml
new file mode 100644
index 0000000..02e2feb
--- /dev/null
+++ b/xos/synchronizers/vpn/steps/sync_vpntenant.yaml
@@ -0,0 +1,47 @@
+---
+- hosts: {{ instance_name }}
+ gather_facts: False
+ connection: ssh
+ user: ubuntu
+ sudo: yes
+ vars:
+ server_address: {{ server_address }}
+ client_address: {{ client_address }}
+ server_key: {{ server_key }}
+ is_persistent: {{ is_persistent }}
+
+ tasks:
+ - name: install openvpn
+ apt: name=openvpn state=present update_cache=yes
+
+ - name: stop openvpn
+ shell: killall openvpn | true
+
+ - name: erase key
+ shell: rm -f static.key
+
+ - name: write key
+ shell: echo {{ '{{' }} item {{ '}}' }} >> static.key
+ with_items: "{{ server_key }}"
+
+ - name: erase config
+ shell: rm -f server.conf
+
+ - name: write base config
+ shell:
+ |
+ printf "dev tun
+ ifconfig {{ server_address }} {{ client_address }}
+ secret static.key" > server.conf
+
+ - name: write persistent config
+ shell:
+ |
+ printf "\nkeepalive 10 60
+ ping-timer-rem
+ persist-tun
+ persist-key" >> server.conf
+ when: {{ is_persistent }}
+
+ - name: start openvpn
+ shell: openvpn server.conf &
diff --git a/xos/synchronizers/vpn/stop.sh b/xos/synchronizers/vpn/stop.sh
new file mode 100755
index 0000000..4178688
--- /dev/null
+++ b/xos/synchronizers/vpn/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f vpn-synchronizer.py
diff --git a/xos/synchronizers/vpn/vpn-synchronizer.py b/xos/synchronizers/vpn/vpn-synchronizer.py
new file mode 100755
index 0000000..3227ed9
--- /dev/null
+++ b/xos/synchronizers/vpn/vpn-synchronizer.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+ os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/vpn/vpn_config b/xos/synchronizers/vpn/vpn_config
new file mode 100644
index 0000000..2cdb192
--- /dev/null
+++ b/xos/synchronizers/vpn/vpn_config
@@ -0,0 +1,23 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=vpn
+dependency_graph=/opt/xos/synchronizers/vpn/model-deps
+steps_dir=/opt/xos/synchronizers/vpn/steps
+sys_dir=/opt/xos/synchronizers/vpn/sys
+logfile=/var/log/xos_backend.log
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
diff --git a/xos/tools/xos-manage b/xos/tools/xos-manage
index 4783bf5..37827b5 100755
--- a/xos/tools/xos-manage
+++ b/xos/tools/xos-manage
@@ -60,13 +60,13 @@
echo Waiting for postgres to start
sleep 1
sudo -u postgres psql -c '\q'
- done
+ done
}
function db_exists {
- sudo -u postgres psql $DBNAME -c '\q' 2>/dev/null
+ sudo -u postgres psql $DBNAME -c '\q' 2>/dev/null
return $?
-}
+}
function createdb {
wait_postgres
@@ -145,6 +145,7 @@
python ./manage.py makemigrations cord
python ./manage.py makemigrations ceilometer
python ./manage.py makemigrations helloworldservice_complete
+ python ./manage.py makemigrations vpn
python ./manage.py makemigrations onos
#python ./manage.py makemigrations servcomp
}
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index 3792224..9486148 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -30,7 +30,7 @@
GEOIP_PATH = "/usr/share/GeoIP"
XOS_DIR = "/opt/xos"
-DEBUG = False
+DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
@@ -180,6 +180,7 @@
'services.ceilometer',
'services.requestrouter',
'services.syndicate_storage',
+ 'services.vpn',
'geoposition',
'rest_framework_swagger',
)