Merge branch 'master' of https://github.com/open-cloud/xos into AddHelloWorldService
diff --git a/xos/configurations/common/Dockerfile.common b/xos/configurations/common/Dockerfile.common
index 1f42c34..5329142 100644
--- a/xos/configurations/common/Dockerfile.common
+++ b/xos/configurations/common/Dockerfile.common
@@ -4,8 +4,8 @@
# XXX Workaround for docker bug:
# https://github.com/docker/docker/issues/6345
# Kernel 3.15 breaks docker, uss the line below as a workaround
-# until there is a fix
-RUN ln -s -f /bin/true /usr/bin/chfn
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
# XXX End workaround
# Install.
@@ -23,12 +23,12 @@
python-httplib2 \
geoip-database \
libgeoip1 \
- wget \
- curl \
+ wget \
+ curl \
python-dev \
- libyaml-dev \
- pkg-config \
- python-pycurl
+ libyaml-dev \
+ pkg-config \
+ python-pycurl
RUN pip install django==1.7
RUN pip install djangorestframework==2.4.4
@@ -64,6 +64,7 @@
RUN easy_install python_gflags
RUN easy_install --upgrade httplib2
RUN easy_install google_api_python_client
+RUN easy_install httplib2.ca_certs_locater
# Install custom Ansible
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-crypto
@@ -97,7 +98,7 @@
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y supervisor
ADD observer.conf /etc/supervisor/conf.d/
-# Get XOS
+# Get XOS
ADD xos /opt/xos
# Initscript is broken in Ubuntu
diff --git a/xos/configurations/common/Makefile.cloudlab b/xos/configurations/common/Makefile.cloudlab
index ddf9daf..929bc14 100644
--- a/xos/configurations/common/Makefile.cloudlab
+++ b/xos/configurations/common/Makefile.cloudlab
@@ -1,4 +1,7 @@
-all: admin-openrc flat_name nodes_yaml public_key install_docker
+all: prereqs admin-openrc flat_name nodes_yaml public_key
+
+prereqs:
+ make -f Makefile.prereqs
admin-openrc:
sudo cat /root/setup/admin-openrc.sh > admin-openrc.sh
@@ -15,6 +18,3 @@
~/.ssh/id_rsa.pub:
cat /dev/zero | ssh-keygen -q -N ""
-install_docker:
- which docker > /dev/null || wget -qO- https://get.docker.com/ | sh
- sudo usermod -aG docker $(shell whoami)
diff --git a/xos/configurations/common/Makefile.prereqs b/xos/configurations/common/Makefile.prereqs
new file mode 100644
index 0000000..0325224
--- /dev/null
+++ b/xos/configurations/common/Makefile.prereqs
@@ -0,0 +1,34 @@
+UBUNTU:=$(shell which apt > /dev/null 2>&1; echo $$?)
+
+ifeq ($(UBUNTU),0)
+
+# ******************* apt-based distros ***************************
+prereqs: /usr/bin/http docker
+
+/usr/bin/http:
+ sudo apt-get -y install httpie
+
+docker:
+ which docker > /dev/null || wget -qO- https://get.docker.com/ | sh
+ sudo usermod -aG docker $(shell whoami)
+
+else
+
+# ****************** RPM-based distros ******************
+
+# (untested / work-in-progress)
+
+prereqs: /usr/bin/pip /usr/bin/http docker
+
+/usr/bin/pip:
+ curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
+ sudo python ./get-pip.py
+
+docker:
+ which docker > /dev/null || wget -qO- https://get.docker.com/ | sh
+ sudo usermod -aG docker $(shell whoami)
+
+/usr/bin/http:
+ sudo pip install httpie
+
+endif
diff --git a/xos/configurations/devel/Makefile b/xos/configurations/devel/Makefile
index e7bf0f4..90dabcc 100644
--- a/xos/configurations/devel/Makefile
+++ b/xos/configurations/devel/Makefile
@@ -1,5 +1,5 @@
MYIP:=$(shell hostname -i)
-EXISTING_CONTAINER:=$(shell sudo docker ps|grep "xos"|awk '{print $$NF}')
+RUNNING_CONTAINER:=$(shell sudo docker ps|grep "xos"|awk '{print $$NF}')
LAST_CONTAINER=$(shell sudo docker ps -l -q)
test: common_cloudlab
@@ -13,10 +13,10 @@
make -C ../common -f Makefile.cloudlab
stop:
- sudo docker stop $(EXISTING_CONTAINER)
+ sudo docker stop $(RUNNING_CONTAINER)
showlogs:
sudo docker logs $(LAST_CONTAINER)
enter:
- sudo docker exec -t -i $(EXISTING_CONTAINER) bash
+ sudo docker exec -t -i $(RUNNING_CONTAINER) bash
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index e44062d..d03e1bc 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -18,4 +18,4 @@
sudo docker logs $(LAST_CONTAINER)
enter:
- sudo docker exec -t -i $(EXISTING_CONTAINER) bash
\ No newline at end of file
+ sudo docker exec -t -i $(RUNNING_CONTAINER) bash
diff --git a/xos/configurations/kilo-install/Dockerfile b/xos/configurations/kilo-install/Dockerfile
new file mode 100644
index 0000000..f0ced90
--- /dev/null
+++ b/xos/configurations/kilo-install/Dockerfile
@@ -0,0 +1,154 @@
+# Autogenerated -- do not edit
+FROM ubuntu:14.04.2
+MAINTAINER Andy Bavier <acb@cs.princeton.edu>
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN apt-get update && apt-get install -y \
+ git \
+ postgresql \
+ python-psycopg2 \
+ graphviz \
+ graphviz-dev \
+ libxslt1.1 \
+ libxslt1-dev \
+ python-pip \
+ tar \
+ gcc \
+ python-httplib2 \
+ geoip-database \
+ libgeoip1 \
+ wget \
+ curl \
+ python-dev \
+ libyaml-dev \
+ pkg-config \
+ python-pycurl
+
+RUN pip install django==1.7
+RUN pip install djangorestframework==2.4.4
+RUN pip install markdown # Markdown support for the browseable API.
+RUN pip install pyyaml # YAML content-type support.
+RUN pip install django-filter # Filtering support
+RUN pip install lxml # XML manipulation library
+RUN pip install netaddr # IP Addr library
+RUN pip install pytz
+RUN pip install django-timezones
+RUN pip install requests
+RUN pip install django-crispy-forms
+RUN pip install django-geoposition
+RUN pip install django-extensions
+RUN pip install django-suit
+RUN pip install django-bitfield
+RUN pip install django-ipware
+RUN pip install django-encrypted-fields
+RUN pip install python-keyczar
+RUN pip install pygraphviz
+RUN pip install dnslib
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-keystoneclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-novaclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-neutronclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-glanceclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-ceilometerclient
+
+RUN pip install django_rest_swagger
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-setuptools
+RUN easy_install django_evolution
+RUN easy_install python_gflags
+RUN easy_install --upgrade httplib2
+RUN easy_install google_api_python_client
+RUN easy_install httplib2.ca_certs_locater
+
+# Install custom Ansible
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-crypto
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-yaml
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-client
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-paramiko
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-jinja2
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-httplib2
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras
+RUN git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core
+RUN git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core
+ADD ansible-hosts /etc/ansible/hosts
+
+ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# For Observer
+RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum
+RUN cd /tmp/fofum; python setup.py install
+RUN rm -rf /tmp/fofum
+
+RUN mkdir -p /usr/local/share /bin
+ADD http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2 /usr/local/share/
+RUN tar jxvf /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 -C /usr/local/share/
+RUN rm -f /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2
+RUN ln -s /usr/local/share/phantomjs-1.7.0-linux-x86_64 /usr/local/share/phantomjs
+RUN ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs
+
+# Supervisor
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y supervisor
+ADD observer.conf /etc/supervisor/conf.d/
+
+# Get XOS
+ADD xos /opt/xos
+
+# Initscript is broken in Ubuntu
+#ADD observer-initscript /etc/init.d/xosobserver
+
+RUN chmod +x /opt/xos/scripts/opencloud
+RUN /opt/xos/scripts/opencloud genkeys
+
+# Workaround for AUFS issue
+# https://github.com/docker/docker/issues/783#issuecomment-56013588
+RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private
+
+# Set postgres password to match default value in settings.py
+RUN service postgresql start; sudo -u postgres psql -c "alter user postgres with password 'password';"
+
+# Turn DEBUG on so that devel server will serve static files
+# (not necessary if --insecure is passed to 'manage.py runserver')
+# RUN sed -i 's/DEBUG = False/DEBUG = True/' /opt/xos/xos/settings.py
+
+# Cruft to workaround problems with migrations, should go away...
+RUN /opt/xos/scripts/opencloud remigrate
+
+# git clone uses cached copy, doesn't pick up latest
+RUN git -C /opt/ansible pull
+RUN git -C /opt/ansible/lib/ansible/modules/core pull
+RUN git -C /opt/ansible/v2/ansible/modules/core pull
+
+# install Tosca engine
+RUN apt-get install -y m4
+RUN pip install python-dateutil
+RUN bash /opt/xos/tosca/install_tosca.sh
+
+EXPOSE 8000
+
+# Set environment variables.
+ENV HOME /root
+
+# Define working directory.
+WORKDIR /root
+
+# Define default command.
+#CMD ["/bin/bash"]
+#CMD /opt/xos/scripts/docker_start_xos
+RUN mkdir -p /root/setup
+ADD xos/configurations/common/admin-openrc.sh /root/setup/
+RUN bash -c 'echo "nat-net" > /root/setup/flat_net_name'
+ADD xos/configurations/common/cloudlab-nodes.yaml /opt/xos/configurations/commmon/
+ADD xos/configurations/common/id_rsa.pub /root/setup/padmin_public_key
+
+CMD /usr/bin/make -C /opt/xos/configurations/kilo-install -f Makefile.inside; /bin/bash
+
+#CMD ["/bin/bash"]
diff --git a/xos/configurations/kilo-install/Dockerfile.kilo-install b/xos/configurations/kilo-install/Dockerfile.kilo-install
new file mode 100644
index 0000000..e4d301b
--- /dev/null
+++ b/xos/configurations/kilo-install/Dockerfile.kilo-install
@@ -0,0 +1,9 @@
+RUN mkdir -p /root/setup
+ADD xos/configurations/common/admin-openrc.sh /root/setup/
+RUN bash -c 'echo "nat-net" > /root/setup/flat_net_name'
+ADD xos/configurations/common/cloudlab-nodes.yaml /opt/xos/configurations/commmon/
+ADD xos/configurations/common/id_rsa.pub /root/setup/padmin_public_key
+
+CMD /usr/bin/make -C /opt/xos/configurations/kilo-install -f Makefile.inside; /bin/bash
+
+#CMD ["/bin/bash"]
diff --git a/xos/configurations/kilo-install/Makefile b/xos/configurations/kilo-install/Makefile
new file mode 100644
index 0000000..7d11490
--- /dev/null
+++ b/xos/configurations/kilo-install/Makefile
@@ -0,0 +1,30 @@
+MYIP:=$(shell hostname -i)
+RUNNING_CONTAINER:=$(shell sudo docker ps|grep "xos"|awk '{print $$NF}')
+LAST_CONTAINER=$(shell sudo docker ps -l -q)
+
+test: common_cloudlab images
+ echo "# Autogenerated -- do not edit" > Dockerfile
+ cat ../common/Dockerfile.common Dockerfile.kilo-install >> Dockerfile
+ cd ../../..; sudo docker build -t xos -f xos/configurations/kilo-install/Dockerfile .
+ sudo docker run -d --add-host="0.0.0.0:$(MYIP)" -p 9999:8000 -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro xos
+ bash ../common/wait_for_xos.sh
+
+common_cloudlab:
+ make -C ../common -f Makefile.cloudlab
+
+stop:
+ sudo docker stop $(RUNNING_CONTAINER)
+
+showlogs:
+ sudo docker logs $(LAST_CONTAINER)
+
+enter:
+ sudo docker exec -t -i $(RUNNING_CONTAINER) bash
+
+images:
+ sudo bash -c "source /root/setup/admin-openrc.sh; \
+ glance image-show trusty-server-multi-nic || \
+ glance image-create --name trusty-server-multi-nic \
+ --disk-format qcow2 \
+ --file /proj/xos-PG0/acb/images/trusty-server-multi-nic.img \
+ --container-format bare"
diff --git a/xos/configurations/kilo-install/Makefile.inside b/xos/configurations/kilo-install/Makefile.inside
new file mode 100644
index 0000000..40b2672
--- /dev/null
+++ b/xos/configurations/kilo-install/Makefile.inside
@@ -0,0 +1,12 @@
+all: setup_xos update_certificates run_develserver
+
+setup_xos:
+ bash /opt/xos/scripts/docker_setup_xos
+ python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab.yaml
+ python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-nodes.yaml
+
+update_certificates:
+ update-ca-certificates
+
+run_develserver:
+ cd /opt/xos; python manage.py runserver 0.0.0.0:8000 --insecure
diff --git a/xos/configurations/kilo-install/README b/xos/configurations/kilo-install/README
new file mode 100644
index 0000000..2ff7549
--- /dev/null
+++ b/xos/configurations/kilo-install/README
@@ -0,0 +1,8 @@
+This configuration is based on the "devel" configuration for CloudLab. It is
+meant to work with an OpenStack Kilo cluster installed on CloudLab using the
+procedure documented here:
+
+https://github.com/andybavier/opencloud-cluster-setup
+
+It launches an XOS container on Cloudlab that runs the XOS develserver. The
+container is left running in the background.
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
index ea8da80..c26ac54 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -392,10 +392,18 @@
return Response( {"vbng_mapping": mappings} )
+class CordDebugIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+ # Swagger is failing because CordDebugViewSet has neither a model nor
+ # a serializer_class. Stuck this in here as a placeholder for now.
+ id = ReadOnlyField()
+ class Meta:
+ model = CordSubscriber
+
class CordDebugViewSet(XOSViewSet):
base_name = "cord_debug"
method_name = "rs/cord_debug"
method_kind = "viewset"
+ serializer_class = CordDebugIdSerializer
@classmethod
def get_urlpatterns(self):
diff --git a/xos/openstack/client.py b/xos/openstack/client.py
index 4962e06..c500204 100644
--- a/xos/openstack/client.py
+++ b/xos/openstack/client.py
@@ -36,7 +36,7 @@
return opts
class Client:
- def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, controller=None, admin=True, *args, **kwds):
+ def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, controller=None, cacert=None, admin=True, *args, **kwds):
self.has_openstack = has_openstack
self.url = controller.auth_url
@@ -62,6 +62,8 @@
if endpoint:
self.endpoint = endpoint
+ self.cacert = cacert
+
#if '@' in self.username:
# self.username = self.username[:self.username.index('@')]
@@ -157,7 +159,8 @@
self.client = quantum_client.Client(username=self.username,
password=self.password,
tenant_name=self.tenant,
- auth_url=self.url)
+ auth_url=self.url,
+ ca_cert=self.cacert)
@require_enabled
def connect(self, *args, **kwds):
self.__init__(*args, **kwds)
diff --git a/xos/openstack_observer/steps/sync_instances.yaml b/xos/openstack_observer/steps/sync_instances.yaml
index 803a294..a61e5cf 100644
--- a/xos/openstack_observer/steps/sync_instances.yaml
+++ b/xos/openstack_observer/steps/sync_instances.yaml
@@ -17,6 +17,7 @@
wait_for: 200
flavor_name: {{ flavor_name }}
user_data: "{{ user_data }}"
+ config_drive: yes
nics:
{% for net in nics %}
- net-id: {{ net }}
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 1a5bee1..b929eda 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -8,11 +8,11 @@
no-delete:
type: boolean
default: false
- description: do not allow Tosca to delete this object
+ description: Do not allow Tosca to delete this object
no-create:
type: boolean
default: false
- description: do not allow Tosca to create this object)
+ description: Do not allow Tosca to create this object)
# Service
define(xos_base_service_caps,
scalable:
@@ -23,24 +23,30 @@
kind:
type: string
default: generic
+ description: Type of service.
view_url:
type: string
required: false
+ description: URL to follow when icon is clicked in the Service Directory.
icon_url:
type: string
required: false
+ description: ICON to display in the Service Directory.
enabled:
type: boolean
default: true
published:
type: boolean
default: true
+ description: If True then display this Service in the Service Directory.
public_key:
type: string
required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
versionNumber:
type: string
- required: false)
+ required: false
+ description: Version number of Service.)
# Subscriber
define(xos_base_subscriber_caps,
subscriber:
@@ -67,12 +73,17 @@
node_types:
tosca.nodes.Service:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Service object. Services may be listed in the Service
+ directory and may be linked together via Tenancy Relationships.
capabilities:
xos_base_service_caps
properties:
xos_base_service_props
tosca.nodes.VCPEService:
+ description: >
+ CORD: The vCPE Service.
derived_from: tosca.nodes.Root
capabilities:
xos_base_service_caps
@@ -81,9 +92,12 @@
backend_network_label:
type: string
required: false
+ description: Label that matches network used to connect HPC and BBS services.
tosca.nodes.VBNGService:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: The vBNG Service.
capabilities:
xos_base_service_caps
properties:
@@ -91,9 +105,12 @@
vbng_url:
type: string
required: false
+ description: URL of REST API endpoint for vBNG Service.
tosca.nodes.CDNService:
derived_from: tosca.nodes.Root
+ description: >
+ Content Delivery Network Service. Includes Request Routing and Hypercache.
capabilities:
xos_base_service_caps
properties:
@@ -101,6 +118,7 @@
tosca.nodes.Subscriber:
derived_from: tosca.nodes.Root
+ description: XOS subscriber base class.
capabilities:
xos_base_subscriber_caps
properties:
@@ -108,6 +126,10 @@
tosca.nodes.CORDSubscriber:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: Subscriber. The Subscriber object contains all of the settings
+ for a CORD household. For example, it contains parental control
+ filter settings.
capabilities:
xos_base_subscriber_caps
properties:
@@ -115,37 +137,54 @@
firewall_enable:
type: boolean
default: false
+ description: If True, then firewalling is enabled.
url_filter_enable:
type: boolean
default: false
+ description: If True, then parental controls are enabled.
url_filter_level:
type: string
default: PG
+ description: The default URL filter level for the household.
cdn_enable:
type: boolean
default: true
+ description: If True, then the CDN is enabled.
tosca.nodes.CORDUser:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: User. The CORD user represents an individual device beloning
+ to the CORD Subscriber. Each device may have its own parental
+ controls.
properties:
level:
type: string
default: PG_13
+ description: Parental control level for this device.
mac:
type: string
required: true
+ description: MAC address for this device.
tosca.nodes.VOLTTenant:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: A Tenant of the vOLT Service. Each Tenant is tied to a
+ specific vlan_id.
properties:
xos_base_tenant_props
vlan_id:
type: string
required: false
+ description: vlan_id for connection to subscriber household.
tosca.nodes.User:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS User record. Users are able to login and use the XOS GUI.
+
capabilities:
user:
type: tosca.capabilities.xos.User
@@ -157,31 +196,43 @@
firstname:
type: string
required: true
+ description: First name of User.
lastname:
type: string
required: true
+ description: Last name of User.
phone:
type: string
required: false
+ description: Phone number of User.
user_url:
type: string
required: false
+ description: URL to User web page.
public_key:
type: string
required: false
+ description: Public key that will be installed in Instances.
is_active:
type: boolean
default: true
+ description: If True, the user may log in.
is_admin:
type: boolean
default: false
+ description: If True, the user has root admin privileges.
login_page:
type: string
required: false
+ description: Indicates what page the user should go to on login.
tosca.nodes.NetworkTemplate:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS network template. Network templates contain settings associated
+ with a particular class of network.
+
capabilities:
network_template:
type: tosca.capabilities.xos.NetworkTemplate
@@ -190,21 +241,27 @@
visibility:
type: string
default: private
+ description: Indicates whether network is publicly routable.
translation:
type: string
default: none
+ description: Indicates whether network uses address translation.
shared_network_name:
type: string
required: false
+ description: Attaches this template to a specific OpenStack network.
shared_network_id:
type: string
required: false
+ description: Attaches this template to a specific OpenStack network.
topology_kind:
type: string
default: BigSwitch
+ descrption: Describes the topology of the network.
controller_kind:
type: string
required: false
+ description: Indicates the type of controller that the network is connected to.
tosca.nodes.network.Network.XOS:
# Due to bug? in implementation, we have to copy everything from
@@ -280,41 +337,27 @@
ports:
type: string
required: false
+ description: >
+ A comma-separated list of protocols and ports. For example,
+ "tcp/123, tcp/456-459, udp/111"
labels:
type: string
required: false
+ description: A comma-separated list of labels for this network.
permit_all_slices:
type: boolean
# In the data model, this is defaulted to false. However, to
# preserve Tosca semantics, we default it to true instead.
default: true
+ description: If True, then any slice may be attached to this network.
capabilities:
link:
type: tosca.capabilities.network.Linkable
-# tosca.nodes.XOSNetwork:
-# derived_from: tosca.nodes.Root
-#
-# capabilities:
-# network:
-# type: tosca.capabilities.xos.Network
-#
-# properties:
-# ports:
-# type: string
-# required: false
-# labels:
-# type: string
-# required: false
-# permit_all_slices:
-# type: boolean
-# default: false
-# permitted_slices:
-# type: string
-# required: false
-
tosca.nodes.Deployment:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Deployment.
capabilities:
deployment:
type: tosca.capabilities.xos.Deployment
@@ -323,12 +366,16 @@
accessControl:
type: string
default: allow all
+ description: ACL that describes who may use this deployment.
flavors:
type: string
required: false
+ description: Comma-separated list of flavors that this deployment supports.
tosca.nodes.Image:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Operating System Image.
capabilities:
image:
type: tosca.capabilities.xos.Image
@@ -336,15 +383,21 @@
disk_format:
type: string
required: false
+ description: Glance disk format.
container_format:
type: string
required: false
+ description: Glance container format.
path:
type: string
required: false
+ description: Path to Image file inside XOS docker container.
tosca.nodes.Controller:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS controller. Controllers serve as the interface between
+ XOS and services such as OpenStack.
capabilities:
controller:
type: tosca.capabilities.xos.Controller
@@ -352,27 +405,36 @@
backend_type:
type: string
required: false
+ description: Type of backend.
version:
type: string
required: false
+ description: Version of backend.
auth_url:
type: string
required: false
+ description: Keystone auth_url.
admin_user:
type: string
required: false
+ description: Keystone username.
admin_password:
type: string
required: false
+ description: Keystone password.
admin_tenant:
type: string
required: false
+ description: Tenant associated with admin account.
domain:
type: string
required: false
+ description: OpenStack domain (or "Default")
tosca.nodes.Site:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Site. Sites are containers for Users and/or Nodes.
capabilities:
site:
type: tosca.capabilities.xos.Site
@@ -380,19 +442,22 @@
display_name:
type: string
required: false
- description: name of the site
+ description: Name of the site.
site_url:
type: string
required: false
+ description: URL of site web page.
enabled:
type: boolean
default: true
hosts_nodes:
type: boolean
default: true
+ description: If True, then this site hosts nodes where Instances may be instantiated.
hosts_users:
type: boolean
default: true
+ description: If True, then this site hosts users who may use XOS.
is_public:
type: boolean
default: true
@@ -400,6 +465,9 @@
tosca.nodes.Slice:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Slice. A slice is a collection of instances that share
+ common attributes.
capability:
slice:
type: tosca.capabilities.xos.Slice
@@ -410,15 +478,21 @@
description:
type: string
required: false
+ description: Description of this slice.
slice_url:
type: string
required: false
+ description: URL to web page that describes slice.
max_instances:
type: integer
default: 10
+ description: Quota of instances that this slice may create.
tosca.nodes.Node:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Node. Nodes are physical machines that host virtual machines
+ and/or containers.
capability:
node:
type: tosca.capabilities.xos.Node
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 96c03fa..2c674eb 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -20,6 +20,9 @@
node_types:
tosca.nodes.Service:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Service object. Services may be listed in the Service
+ directory and may be linked together via Tenancy Relationships.
capabilities:
scalable:
type: tosca.capabilities.Scalable
@@ -29,26 +32,34 @@
kind:
type: string
default: generic
+ description: Type of service.
view_url:
type: string
required: false
+ description: URL to follow when icon is clicked in the Service Directory.
icon_url:
type: string
required: false
+ description: ICON to display in the Service Directory.
enabled:
type: boolean
default: true
published:
type: boolean
default: true
+ description: If True then display this Service in the Service Directory.
public_key:
type: string
required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
versionNumber:
type: string
required: false
+ description: Version number of Service.
tosca.nodes.VCPEService:
+ description: >
+ CORD: The vCPE Service.
derived_from: tosca.nodes.Root
capabilities:
scalable:
@@ -59,30 +70,39 @@
kind:
type: string
default: generic
+ description: Type of service.
view_url:
type: string
required: false
+ description: URL to follow when icon is clicked in the Service Directory.
icon_url:
type: string
required: false
+ description: ICON to display in the Service Directory.
enabled:
type: boolean
default: true
published:
type: boolean
default: true
+ description: If True then display this Service in the Service Directory.
public_key:
type: string
required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
versionNumber:
type: string
required: false
+ description: Version number of Service.
backend_network_label:
type: string
required: false
+ description: Label that matches network used to connect HPC and BBS services.
tosca.nodes.VBNGService:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: The vBNG Service.
capabilities:
scalable:
type: tosca.capabilities.Scalable
@@ -92,30 +112,39 @@
kind:
type: string
default: generic
+ description: Type of service.
view_url:
type: string
required: false
+ description: URL to follow when icon is clicked in the Service Directory.
icon_url:
type: string
required: false
+ description: ICON to display in the Service Directory.
enabled:
type: boolean
default: true
published:
type: boolean
default: true
+ description: If True then display this Service in the Service Directory.
public_key:
type: string
required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
versionNumber:
type: string
required: false
+ description: Version number of Service.
vbng_url:
type: string
required: false
+ description: URL of REST API endpoint for vBNG Service.
tosca.nodes.CDNService:
derived_from: tosca.nodes.Root
+ description: >
+ Content Delivery Network Service. Includes Request Routing and Hypercache.
capabilities:
scalable:
type: tosca.capabilities.Scalable
@@ -125,27 +154,34 @@
kind:
type: string
default: generic
+ description: Type of service.
view_url:
type: string
required: false
+ description: URL to follow when icon is clicked in the Service Directory.
icon_url:
type: string
required: false
+ description: ICON to display in the Service Directory.
enabled:
type: boolean
default: true
published:
type: boolean
default: true
+ description: If True then display this Service in the Service Directory.
public_key:
type: string
required: false
+ description: Public key to install into Instances to allows Services to SSH into them.
versionNumber:
type: string
required: false
+ description: Version number of Service.
tosca.nodes.Subscriber:
derived_from: tosca.nodes.Root
+ description: XOS subscriber base class.
capabilities:
subscriber:
type: tosca.capabilities.xos.Subscriber
@@ -159,6 +195,10 @@
tosca.nodes.CORDSubscriber:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: Subscriber. The Subscriber object contains all of the settings
+ for a CORD household. For example, it contains parental control
+ filter settings.
capabilities:
subscriber:
type: tosca.capabilities.xos.Subscriber
@@ -172,28 +212,41 @@
firewall_enable:
type: boolean
default: false
+ description: If True, then firewalling is enabled.
url_filter_enable:
type: boolean
default: false
+ description: If True, then parental controls are enabled.
url_filter_level:
type: string
default: PG
+ description: The default URL filter level for the household.
cdn_enable:
type: boolean
default: true
+ description: If True, then the CDN is enabled.
tosca.nodes.CORDUser:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: User. The CORD user represents an individual device beloning
+ to the CORD Subscriber. Each device may have its own parental
+ controls.
properties:
level:
type: string
default: PG_13
+ description: Parental control level for this device.
mac:
type: string
required: true
+ description: MAC address for this device.
tosca.nodes.VOLTTenant:
derived_from: tosca.nodes.Root
+ description: >
+ CORD: A Tenant of the vOLT Service. Each Tenant is tied to a
+ specific vlan_id.
properties:
kind:
type: string
@@ -204,10 +257,14 @@
vlan_id:
type: string
required: false
+ description: vlan_id for connection to subscriber household.
tosca.nodes.User:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS User record. Users are able to login and use the XOS GUI.
+
capabilities:
user:
type: tosca.capabilities.xos.User
@@ -219,31 +276,43 @@
firstname:
type: string
required: true
+ description: First name of User.
lastname:
type: string
required: true
+ description: Last name of User.
phone:
type: string
required: false
+ description: Phone number of User.
user_url:
type: string
required: false
+ description: URL to User web page.
public_key:
type: string
required: false
+ description: Public key that will be installed in Instances.
is_active:
type: boolean
default: true
+ description: If True, the user may log in.
is_admin:
type: boolean
default: false
+ description: If True, the user has root admin privileges.
login_page:
type: string
required: false
+ description: Indicates what page the user should go to on login.
tosca.nodes.NetworkTemplate:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS network template. Network templates contain settings associated
+ with a particular class of network.
+
capabilities:
network_template:
type: tosca.capabilities.xos.NetworkTemplate
@@ -252,21 +321,27 @@
visibility:
type: string
default: private
+ description: Indicates whether network is publicly routable.
translation:
type: string
default: none
+ description: Indicates whether network uses address translation.
shared_network_name:
type: string
required: false
+ description: Attaches this template to a specific OpenStack network.
shared_network_id:
type: string
required: false
+ description: Attaches this template to a specific OpenStack network.
topology_kind:
type: string
default: BigSwitch
+ descrption: Describes the topology of the network.
controller_kind:
type: string
required: false
+ description: Indicates the type of controller that the network is connected to.
tosca.nodes.network.Network.XOS:
# Due to bug? in implementation, we have to copy everything from
@@ -342,41 +417,27 @@
ports:
type: string
required: false
+ description: >
+ A comma-separated list of protocols and ports. For example,
+ "tcp/123, tcp/456-459, udp/111"
labels:
type: string
required: false
+ description: A comma-separated list of labels for this network.
permit_all_slices:
type: boolean
# In the data model, this is defaulted to false. However, to
# preserve Tosca semantics, we default it to true instead.
default: true
+ description: If True, then any slice may be attached to this network.
capabilities:
link:
type: tosca.capabilities.network.Linkable
-# tosca.nodes.XOSNetwork:
-# derived_from: tosca.nodes.Root
-#
-# capabilities:
-# network:
-# type: tosca.capabilities.xos.Network
-#
-# properties:
-# ports:
-# type: string
-# required: false
-# labels:
-# type: string
-# required: false
-# permit_all_slices:
-# type: boolean
-# default: false
-# permitted_slices:
-# type: string
-# required: false
-
tosca.nodes.Deployment:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Deployment.
capabilities:
deployment:
type: tosca.capabilities.xos.Deployment
@@ -384,20 +445,24 @@
no-delete:
type: boolean
default: false
- description: do not allow Tosca to delete this object
+ description: Do not allow Tosca to delete this object
no-create:
type: boolean
default: false
- description: do not allow Tosca to create this object
+ description: Do not allow Tosca to create this object
accessControl:
type: string
default: allow all
+ description: ACL that describes who may use this deployment.
flavors:
type: string
required: false
+ description: Comma-separated list of flavors that this deployment supports.
tosca.nodes.Image:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Operating System Image.
capabilities:
image:
type: tosca.capabilities.xos.Image
@@ -405,15 +470,21 @@
disk_format:
type: string
required: false
+ description: Glance disk format.
container_format:
type: string
required: false
+ description: Glance container format.
path:
type: string
required: false
+ description: Path to Image file inside XOS docker container.
tosca.nodes.Controller:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS controller. Controllers serve as the interface between
+ XOS and services such as OpenStack.
capabilities:
controller:
type: tosca.capabilities.xos.Controller
@@ -421,27 +492,36 @@
backend_type:
type: string
required: false
+ description: Type of backend.
version:
type: string
required: false
+ description: Version of backend.
auth_url:
type: string
required: false
+ description: Keystone auth_url.
admin_user:
type: string
required: false
+ description: Keystone username.
admin_password:
type: string
required: false
+ description: Keystone password.
admin_tenant:
type: string
required: false
+ description: Tenant associated with admin account.
domain:
type: string
required: false
+ description: OpenStack domain (or "Default")
tosca.nodes.Site:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Site. Sites are containers for Users and/or Nodes.
capabilities:
site:
type: tosca.capabilities.xos.Site
@@ -449,19 +529,22 @@
display_name:
type: string
required: false
- description: name of the site
+ description: Name of the site.
site_url:
type: string
required: false
+ description: URL of site web page.
enabled:
type: boolean
default: true
hosts_nodes:
type: boolean
default: true
+ description: If True, then this site hosts nodes where Instances may be instantiated.
hosts_users:
type: boolean
default: true
+ description: If True, then this site hosts users who may use XOS.
is_public:
type: boolean
default: true
@@ -469,6 +552,9 @@
tosca.nodes.Slice:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Slice. A slice is a collection of instances that share
+ common attributes.
capability:
slice:
type: tosca.capabilities.xos.Slice
@@ -479,15 +565,21 @@
description:
type: string
required: false
+ description: Description of this slice.
slice_url:
type: string
required: false
+ description: URL to web page that describes slice.
max_instances:
type: integer
default: 10
+ description: Quota of instances that this slice may create.
tosca.nodes.Node:
derived_from: tosca.nodes.Root
+ description: >
+ An XOS Node. Nodes are physical machines that host virtual machines
+ and/or containers.
capability:
node:
type: tosca.capabilities.xos.Node
diff --git a/xos/tosca/doctemplates/html/node_type.html b/xos/tosca/doctemplates/html/node_type.html
new file mode 100644
index 0000000..95e8b7b
--- /dev/null
+++ b/xos/tosca/doctemplates/html/node_type.html
@@ -0,0 +1,46 @@
+<hr>
+<h2 id="{{ node_type.node_type_name }}">{{ node_type.node_type_name }}</h2>
+<blockquote>
+
+<h3>Description:</h3>
+{% if node_type.description %}
+ <blockquote>
+ {{ node_type.description }}
+ </blockquote>
+{% endif %}
+
+<h3>Capabilities:</h3>
+{% if node_type.capabilities %}
+ <blockquote>
+ <table class="properties">
+ <tr><th>name</th><th>type</th></tr>
+ {% for capname,cap in node_type.capabilities.iteritems() %}
+ <tr><td>{{ capname }}</td><td>{{ cap.type }}</td></tr>
+ {% endfor %}
+ </table>
+ </blockquote>
+{% endif %}
+
+<h3>Properties:</h3>
+{% if node_type.properties %}
+ <blockquote>
+ <table class="properties">
+ <tr><th>name</th><th>required</th><th>type</th><th>default</th></tr>
+ {% for propname,prop in node_type.properties.iteritems() %}
+ <tr><td>{{ propname }}</td>
+ <td>{{ prop.required }}</td>
+ <td>{{ prop.type }}</td>
+ <td>{{ prop.default }}</td>
+ </tr>
+ {% if prop.description %}
+ <tr><td colspan=4 class="helptext" style="apadding-left: 30px;">{{ prop.description }}</td></tr>
+ {% endif %}
+ {% endfor %}
+ </table>
+ </blockquote>
+{% endif %}
+
+</blockquote>
+
+
+
diff --git a/xos/tosca/doctemplates/html/toscadoctemplate.html b/xos/tosca/doctemplates/html/toscadoctemplate.html
new file mode 100644
index 0000000..8568d33
--- /dev/null
+++ b/xos/tosca/doctemplates/html/toscadoctemplate.html
@@ -0,0 +1,80 @@
+<html><head>
+<title>XOS TOSCA Reference</title>
+
+<style>
+.properties {
+ border-collapse: collapse;
+}
+.properties td, .properties th {
+ border: 1px solid black;
+ padding: 3px 7px 2px 7px;
+}
+.properties th {
+ font-size: 1.1em;
+ padding-top: 5px;
+ padding-bottom: 4px;
+ oldbackground-color: #A7C942;
+ background-color: #2d6ca2;
+ color: #ffffff;
+}
+.helptext {
+ padding-left: 30px !important;
+ color: rgb(153, 153, 153);
+}
+</style>
+
+</head>
+<body>
+
+<h1>XOS TOSCA Reference</h1>
+
+<p>This documentation is autogenerated from the XOS Tosca custom_types
+specification (xos/tosca/custom_types/xos.m4).
+
+Table of Contents:
+<ul>
+<li>Node Types
+<ul>
+{% for node_type in node_types %}
+ {% if node_type.node_type_kind == "node" %}
+ <li><a href="#{{ node_type.node_type_name }}">{{ node_type.node_type_name }}</a></li>
+ {% endif %}
+{% endfor %}
+</li>
+</ul>
+<li><a href="#xos_relationships">Relationships</a></li>
+<li><a href="#xos_capabilities">Capabilities</a></li>
+</ul>
+
+{% for node_type in node_types %}
+ {% if node_type.node_type_kind == "node" %}
+ {% include 'node_type.html' %}
+ {% endif %}
+{% endfor %}
+
+<h3 id="xos_relationships">XOS Relationships</h3>
+<blockquote>
+<table class="properties">
+<tr><th>name</th><th>target_types</th></tr>
+{% for node_type in node_types %}
+ {% if node_type.node_type_kind == "relationship" %}
+ <tr><td>{{ node_type.node_type_name }}</td><td>{{ node_type.valid_target_types|join(', ') }}</td></tr>
+ {% endif %}
+{% endfor %}
+</table>
+</blockquote>
+
+<h3 id="xos_capabilities">XOS Capabilities</h3>
+<blockquote>
+<table class="properties">
+<tr><th>name</th></tr>
+{% for node_type in node_types %}
+ {% if node_type.node_type_kind == "capability" %}
+ <tr><td>{{ node_type.node_type_name }}</td></tr>
+ {% endif %}
+{% endfor %}
+</table>
+</blockquote>
+
+</body>
+</html>
diff --git a/xos/tosca/makedocs.py b/xos/tosca/makedocs.py
new file mode 100644
index 0000000..f7dc11b
--- /dev/null
+++ b/xos/tosca/makedocs.py
@@ -0,0 +1,59 @@
+import jinja2
+import os
+import sys
+import yaml
+import pdb
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+# a bit of a hack for developing -- run m4 to generate xos.yaml from xos.m4
+os.system("m4 %s/custom_types/xos.m4 > %s/custom_types/xos.yaml" % (currentdir, currentdir))
+
+"""
+{'derived_from': 'tosca.nodes.Root', 'capabilities': {'scalable': {'type': 'tosca.capabilities.Scalable'},
+'service': {'type': 'tosca.capabilities.xos.Service'}}, 'properties': {'icon_url': {'required': False,
+'type': 'string'}, 'public_key': {'required': False, 'type': 'string'}, 'kind': {'default': 'generic',
+'type': 'string'}, 'published': {'default': True, 'type': 'boolean'}, 'view_url': {'required': False, 'type': 'string'}, 'enabled': {'default': True, 'type': 'boolean'}, 'versionNumber': {'required': False, 'type': 'string'}}}
+"""
+
+class ToscaDocumenter(object):
+ def __init__(self, fn="./custom_types/xos.yaml", templatedir="./doctemplates/html", templatename="toscadoctemplate.html", destfn="tosca_reference.html"):
+ self.env = jinja2.Environment(loader=jinja2.FileSystemLoader(templatedir))
+
+ self.custom_types = yaml.load(file(fn).read())
+ self.node_types = self.custom_types.get("node_types")
+
+ self.destfn = destfn
+ self.templatename = templatename
+
+ def run(self):
+ node_types=[]
+ for k in sorted(self.node_types.keys()):
+ nt = self.node_types[k]
+ nt["node_type_name"] = k
+
+ derived_from = nt.get("derived_from","")
+
+ if derived_from.startswith("tosca.nodes"):
+ nt["node_type_kind"] = "node"
+ elif derived_from.startswith("tosca.capabilities"):
+ nt["node_type_kind"] = "capability"
+ elif derived_from.startswith("tosca.relationships"):
+ nt["node_type_kind"] = "relationship"
+
+ node_types.append(nt)
+
+ template = self.env.get_template(self.templatename)
+
+ self.destf = open(self.destfn,"w")
+ self.destf.write(template.render(node_types=node_types))
+
+def main():
+ ToscaDocumenter().run()
+
+if __name__=="__main__":
+ main()
diff --git a/xos/tosca/tests/allObserverTests.py b/xos/tosca/tests/allObserverTests.py
index 82bb10b..d06daba 100644
--- a/xos/tosca/tests/allObserverTests.py
+++ b/xos/tosca/tests/allObserverTests.py
@@ -1,6 +1,12 @@
from observerComputeTest import ObserverComputeTest
from observerImageTest import ObserverImageTest
+from observerUserTest import ObserverUserTest
+from observerSiteTest import ObserverSiteTest
+from observerSliceTest import ObserverSliceTest
if __name__ == "__main__":
ObserverComputeTest()
ObserverImageTest()
+ ObserverSiteTest()
+ ObserverUserTest()
+ ObserverSliceTest()
diff --git a/xos/tosca/tests/observerSiteTest.py b/xos/tosca/tests/observerSiteTest.py
new file mode 100644
index 0000000..0ebc8be
--- /dev/null
+++ b/xos/tosca/tests/observerSiteTest.py
@@ -0,0 +1,56 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, ControllerSite
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverSiteTest(BaseObserverToscaTest):
+ tests = ["create_site"]
+ # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+ def cleanup(self):
+ # We don't want to leak rezsources, so we make sure to let the observer
+ # attempt to delete these objects.
+ self.try_to_delete(Site, purge=False, login_base="testsite")
+ self.run_observer()
+ self.try_to_delete(Site, purge=True, login_base="testsite")
+
+ def create_site(self):
+ self.assert_noobj(Site, "testsite")
+ self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+ props={"no-delete": True}) + \
+"""
+ testsite:
+ type: tosca.nodes.Site
+ properties:
+ site_url: http://opencloud.us/
+ requirements:
+ - deployment:
+ node: %s
+ relationship: tosca.relationships.SiteDeployment
+ requirements:
+ - controller:
+ node: %s
+ relationship: tosca.relationships.UsesController
+""" % (self.get_usable_deployment(), self.get_usable_controller()))
+
+ testsite = self.assert_obj(Site, "testsite")
+
+ self.run_model_policy(save_output="/tmp/sitetest:create_site:model_policy")
+
+ # make sure a ControllerSite object was created
+ cs = ControllerSite.objects.filter(site=testsite)
+ assert(len(cs) == 1)
+
+ self.run_observer(save_output="/tmp/sitetest:create_site:observer")
+
+ testsite = self.assert_obj(Site, "testsite")
+
+ cs = ControllerSite.objects.filter(site=testsite)
+ assert(len(cs) == 1)
+ assert(cs[0].tenant_id is not None)
+ assert(cs[0].tenant_id != "")
+
+if __name__ == "__main__":
+ ObserverSiteTest()
+
diff --git a/xos/tosca/tests/observerSliceTest.py b/xos/tosca/tests/observerSliceTest.py
new file mode 100644
index 0000000..749f4ed
--- /dev/null
+++ b/xos/tosca/tests/observerSliceTest.py
@@ -0,0 +1,48 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, Slice, ControllerSlice
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverSliceTest(BaseObserverToscaTest):
+ tests = ["create_slice"]
+ # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+ def cleanup(self):
+ # We don't want to leak resources, so we make sure to let the observer
+ # attempt to delete these objects.
+ self.try_to_delete(Slice, purge=False, name="testsite_slice1")
+ self.try_to_delete(Site, purge=False, login_base="testsite")
+ self.run_observer()
+ self.try_to_delete(Slice, purge=True, name="testsite_slice1")
+ self.try_to_delete(Site, purge=True, login_base="testsite")
+
+ def create_slice(self):
+ self.assert_noobj(Site, "testsite")
+ self.assert_noobj(Slice, "testsite_slice1")
+ self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+ props={"no-delete": True}) +
+ self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+ self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+
+ testsite = self.assert_obj(Site, "testsite")
+ testslice = self.assert_obj(Slice, "testsite_slice1")
+
+ self.run_model_policy(save_output="/tmp/slicetest:create_slice:model_policy")
+
+ # make sure a ControllerSlice object was created
+ cs = ControllerSlice.objects.filter(slice=testslice)
+ assert(len(cs) == 1)
+
+ self.run_observer(save_output="/tmp/slicetest:create_slice:observer")
+
+ testslice = self.assert_obj(Slice, "testsite_slice1")
+
+ cs = ControllerSlice.objects.filter(slice=testslice)
+ assert(len(cs) == 1)
+ assert(cs[0].tenant_id is not None)
+ assert(cs[0].tenant_id != "")
+
+if __name__ == "__main__":
+ ObserverSliceTest()
+
diff --git a/xos/tosca/tests/observerUserTest.py b/xos/tosca/tests/observerUserTest.py
new file mode 100644
index 0000000..44b47d3
--- /dev/null
+++ b/xos/tosca/tests/observerUserTest.py
@@ -0,0 +1,82 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, User, ControllerUser
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverUserTest(BaseObserverToscaTest):
+ tests = ["create_user"]
+ # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+ def cleanup(self):
+ # We don't want to leak resources, so we make sure to let the observer
+ # attempt to delete these objects.
+ self.try_to_delete(User, purge=False, email="johndoe@foo.bar")
+ self.try_to_delete(Site, purge=False, login_base="testsite")
+ self.run_observer()
+ self.try_to_delete(User, purge=True, email="johndoe@foo.bar")
+ self.try_to_delete(Site, purge=True, login_base="testsite")
+
+ def assert_nouser(self, email):
+ assert(not User.objects.filter(email=email))
+
+ def assert_user(self, email, **kwargs):
+ obj = User.objects.get(email=email)
+ assert(obj)
+ for (k,v) in kwargs.items():
+ if (getattr(obj,k,None) != v):
+ print "Object %s property '%s' is '%s' and should be '%s'" % (obj, k, getattr(obj,k,None), v)
+ assert(False)
+ return obj
+
+ def create_user(self):
+ self.assert_noobj(Site, "testsite")
+ self.assert_nouser("johndoe@foo.bar")
+ self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+ props={"no-delete": True}) + \
+"""
+ testsite:
+ type: tosca.nodes.Site
+ properties:
+ site_url: http://opencloud.us/
+ requirements:
+ - deployment:
+ node: %s
+ relationship: tosca.relationships.SiteDeployment
+ requirements:
+ - controller:
+ node: %s
+ relationship: tosca.relationships.UsesController
+ johndoe@foo.bar:
+ type: tosca.nodes.User
+ properties:
+ password: letmein
+ firstname: john
+ lastname: doe
+ requirements:
+ - site:
+ node: testsite
+ relationship: tosca.relationships.MemberOfSite
+""" % (self.get_usable_deployment(), self.get_usable_controller()))
+
+ testsite = self.assert_obj(Site, "testsite")
+ testuser = self.assert_user("johndoe@foo.bar")
+
+ self.run_model_policy(save_output="/tmp/usertest:create_user:model_policy")
+
+ # make sure a ControllerSite object was created
+ cu = ControllerUser.objects.filter(user=testuser)
+ assert(len(cu) == 1)
+
+ self.run_observer(save_output="/tmp/usertest:create_user:observer")
+
+ testuser = self.assert_user("johndoe@foo.bar")
+
+ cu = ControllerUser.objects.filter(user=testuser)
+ assert(len(cu) == 1)
+ assert(cu[0].kuser_id is not None)
+ assert(cu[0].kuser_id != "")
+
+if __name__ == "__main__":
+ ObserverUserTest()
+
diff --git a/xos/tosca/tests/observertest.py b/xos/tosca/tests/observertest.py
index f714045..1ec8797 100644
--- a/xos/tosca/tests/observertest.py
+++ b/xos/tosca/tests/observertest.py
@@ -19,6 +19,9 @@
def get_usable_deployment(self):
return "MyDeployment"
+ def get_usable_controller(self):
+ return "CloudLab"
+
def ensure_observer_not_running(self):
ps_output = subprocess.Popen("ps -elfy", shell=True, stdout=subprocess.PIPE).stdout.read()
if "/opt/xos/xos-observer.py" in ps_output: