diff --git a/.gitignore b/.gitignore
index 5519dd66386c2cc7d4cfe634d6e19519e42b545a..53f6796ff763007778bdbb7f1abb5db83610374f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ LCS/Blob/ylwrap
 **/*.project
 **/*.settings
 .idea
+__pycache__
 SAS/OTB/RSP/src/nl/astron/lofar/java/sas/otb/rsp/subbandstats/WaveformSettingsListPanel.form
 SAS/OTB/RSP/src/nl/astron/lofar/java/sas/otb/rsp/subbandstats/WaveformSettingsListPanel.java
 SAS/OTB/jParmFacade/Makefile.common
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 778d3fe4390f782b464ae1f1b424e479e9ac63fe..6a70c15aa36c0a75f766ee40e1a336aefb23bf2f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -449,11 +449,15 @@ unit_and_integration_and_regression_test_TMSS:
     RABBITMQ_DEFAULT_USER: guest
     RABBITMQ_DEFAULT_PASS: guest
     LOFAR_DEFAULT_BROKER: 'rabbitmq' # override default 'localhost' which does not work for CI service rabbitmq.
+  before_script:
+    - python3 --version
+    - pip3 --version
+    - pip3 list
   script:
     - PACKAGE=TMSS
     - echo "Unit & Integration Testing $PACKAGE..."
     - cd build/gnucxx11_opt
-    - SKIP_PYTHON_COVERAGE=true SKIP_INTEGRATION_TESTS=false SKIP_UNIT_TESTS=false SKIP_REGRESSION_TESTS=false ctest
+    - SKIP_PYTHON_COVERAGE=true SKIP_INTEGRATION_TESTS=false SKIP_UNIT_TESTS=false SKIP_REGRESSION_TESTS=false ctest --output-on-failure
   interruptible: true
   needs:
     - build_TMSS
diff --git a/Docker/lofar-ci/Dockerfile_ci_tmss b/Docker/lofar-ci/Dockerfile_ci_tmss
index af84282eca95c1b244865aad7dc5d6351bd239ea..c20d60bbee6843b00ac6c0f49bdd9cadba7ecffe 100644
--- a/Docker/lofar-ci/Dockerfile_ci_tmss
+++ b/Docker/lofar-ci/Dockerfile_ci_tmss
@@ -26,7 +26,8 @@ COPY SAS/TMSS/backend/services/scheduling/requirements.txt tmss_scheduling.txt
 COPY SAS/TMSS/backend/services/slack_webhook/requirements.txt tmss_slack_webhook.txt
 COPY SAS/TMSS/backend/services/websocket/requirements.txt tmss_websocket.txt
 
-RUN pip3 install astroplan cachetools comet coverage cx_Oracle cython django-auth-ldap \
+RUN pip3 install "setuptools>=62.6" "wheel>=0.40" "pip>=23.1.2"
+RUN pip3 install astroplan cachetools comet coreapi coverage cx_Oracle cython django-auth-ldap \
     django-debug-toolbar django-filter django-json-widget django-jsoneditor django-jsonforms \
     django-material django-property-filter django-viewflow djangorestframework-xml \
     drf-flex-fields drf-yasg fabric flask flex gevent graphviz gunicorn h5py isodate \
@@ -36,7 +37,8 @@ RUN pip3 install astroplan cachetools comet coverage cx_Oracle cython django-aut
     swagger-spec-validator testing.postgresql ujson websocket_client xmljson \
     -r tmss_lobster.txt -r tmss_ingest_tmss_adapter.txt -r tmss_scheduling.txt \
     -r tmss_slack_webhook.txt -r tmss_websocket.txt \
-    -c tmss_constraints.txt
+    -c tmss_constraints.txt --ignore-installed
+RUN pip3 list
 
 # Note: nodejs now comes with npm, do not install the npm package separately, since that will be taken from the ubuntu repo and is conflicting.
 RUN echo "Installing Nodejs packages...." && \
diff --git a/SAS/TMSS/backend/services/lobster/README.md b/SAS/TMSS/backend/services/lobster/README.md
index edbf60fbcb51f8640a3444c55b066b61706c6c5f..cc094dd25ebe45198144dd538059cc42a6a1d8bc 100644
--- a/SAS/TMSS/backend/services/lobster/README.md
+++ b/SAS/TMSS/backend/services/lobster/README.md
@@ -29,8 +29,8 @@ started
 
 ```sh
 source installed/lofarinit.sh
-docker run -d --hostname lukken-vm-ubuntu-22 --name lofar-broker -p 5672:5672 -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest rabbitmq:3-management
-export LOFAR_DEFAULT_BROKER=lukken-vm-ubuntu-22
+docker run -d --hostname ${HOSTNAME} --name lofar-broker -p 5672:5672 -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest rabbitmq:3-management
+export LOFAR_DEFAULT_BROKER=${HOSTNAME}
 ```
 
 Once started Lobster tests can be run using ctest or Python directly
@@ -39,3 +39,8 @@ Once started Lobster tests can be run using ctest or Python directly
 ctest -VV -R t_l2station_tmss_integration_test
 python ../../SAS/TMSS/backend/test/t_l2station_tmss_integration_test.py
 ```
+
+```sh
+ctest -VV -R t_l2station_tmss_test
+python ../../SAS/TMSS/backend/test/t_l2station_tmss_test.py
+```
\ No newline at end of file
diff --git a/SAS/TMSS/backend/services/lobster/lib/CMakeLists.txt b/SAS/TMSS/backend/services/lobster/lib/CMakeLists.txt
index c26cf158833bcf9191acebedf3613634de14a159..888bd56b03a3dafc6ee2eccfc27403c1a8f8328d 100644
--- a/SAS/TMSS/backend/services/lobster/lib/CMakeLists.txt
+++ b/SAS/TMSS/backend/services/lobster/lib/CMakeLists.txt
@@ -5,8 +5,10 @@ set(_py_files
     __init__.py
     bus_listener.py
     message_handler.py
+    observation_pool.py
     rpc_client.py
     service_handler.py
+    specification_translation.py
 )
 
 python_install(${_py_files}
diff --git a/SAS/TMSS/backend/services/lobster/lib/message_handler.py b/SAS/TMSS/backend/services/lobster/lib/message_handler.py
index 74cb7436e50bbf5692c9a995faff52c958c6c578..06c1adc9b6886cfb52edbb0390184c58be048f1e 100644
--- a/SAS/TMSS/backend/services/lobster/lib/message_handler.py
+++ b/SAS/TMSS/backend/services/lobster/lib/message_handler.py
@@ -23,7 +23,13 @@
 from lofar.sas.tmss.client.tmss_http_rest_client import TMSSsession
 from lofar.sas.tmss.client.tmssbuslistener import TMSSEventMessageHandler
 from lofar.common.datetimeutils import round_to_second_precision
+from lofar.sas.tmss.services.lobster.observation_pool import ObservationPool
+from lofar.sas.tmss.services.lobster.specification_translation import (
+    combine_l2specification_multistation
+)
 
+from copy import copy
+from time import sleep
 from datetime import datetime, timedelta
 from dateutil import parser
 
@@ -42,6 +48,7 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
             tmss_client_credentials_id
         )
         self._last_poll_timestamp = datetime.min
+        self.observation_pool = ObservationPool()
 
     def start_handling(self):
         '''upon startup, connect to TMSS and handle all (near)future scheduled observations'''
@@ -54,6 +61,7 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
 
     def onSubTaskStatusChanged(self, id: int, status: str):
         '''Handle TMSS subtask status changes'''
+
         logger.debug("subtask id=%s status changed to %s", id, status)
 
         if status in ("scheduled", "queued"):
@@ -61,7 +69,7 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
 
             if status == "scheduled":
                 self.enqueue_scheduled_observation_subtask(subtask)
-            elif status == "queue":
+            elif status == "queued":
                 self.start_queued_observation_subtask(subtask)
 
     def before_receive_message(self):
@@ -76,6 +84,7 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
 
     def check_upcoming_scheduled_observations(self):
         '''Fetch all scheduled observations in the upcoming lookahead window, and try to enqueue them.'''
+
         logger.info("checking for upcoming scheduled observations in TMSS...")
         now = round_to_second_precision(datetime.utcnow())
         scheduled_observation_subtasks = self.tmss_client.get_subtasks(
@@ -88,7 +97,6 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
         for subtask in scheduled_observation_subtasks:
             self.enqueue_scheduled_observation_subtask(subtask)
 
-
     def enqueue_scheduled_observation_subtask(self, subtask: dict):
         subtask_id = subtask['id']
 
@@ -118,26 +126,35 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
             self.tmss_client.set_subtask_status(subtask_id, "queueing", retry_count=5)
 
             l2stationspecs = self.tmss_client.get_subtask_l2stationspecs(subtask_id, retry_count=5)
-            logger.info("subtask id=%s stationspecs=%s" % (subtask_id, l2stationspecs))
-
-            # JS 2023-01-31: I'm not sure what actually needs to happen here. JD told me the stations "start" immediately once they get their spec.
-            # So, whould that mean that we "hold" the station specs until 1 seconds before the actual starttime???
-            # See also the method below: start_queued_observation_subtask, which is called when we set the state to queued.
-            # In my opinion, we need to do the preparation here.
-            # and the actual real startup in start_queued_observation_subtask
-
-            # JK 2023-02-01: In my understanding we indeed have to hold off with submitting the station specs until any
-            #  previous observation has concluded and it is safe to reconfigure the station. But the station needs to
-            #  be done with the reconfiguration before Cobalt starts handling the data. The l2stationspecs translation
-            #  should not be so heavy that we have to cache it and I assume this can all happen in start_queued_observation_subtask?
-
-            # ToDo: the Jira ticket says we need to check the specifications_doc for validity. That's superfluous cause TMSS already does that, but it doesn't hurt either.
 
+            # Combine stations with same observation_id to create singular
+            # MultiStationObservation instances in observation_pool
+            observations = combine_l2specification_multistation(l2stationspecs)
+
+            # Add each observation to the pool and test connectivity
+            for observation_id, value in observations.items():
+                logger.info(
+                    "subtask id=%s has observation=%s for stations=%s with "
+                    "spec=%s", subtask_id, observation_id, value['stations'],
+                    value['specification']
+                )
+                station_obs = self.observation_pool.create_multistationobservation(
+                    subtask_id, observation_id, value['stations'], value['specification']
+                )
+
+                if not station_obs.all_connected:
+                    logger.warning(
+                        "Failed to connect to some of stations=%s during"
+                        "preparation!", value['stations']
+                    )
+
+            # ToDo: the Jira ticket says we need to check the specifications_doc for
+            #       validity. That's superfluous cause TMSS already does that, but it
+            #       doesn't hurt either.
+            self.tmss_client.set_subtask_status(subtask_id, "queued", retry_count=5)
         except Exception as e:
-            logger.error(e)
+            logger.exception(e)
             self.tmss_client.set_subtask_status(subtask_id, "error", error_reason=str(e), retry_count=5)
-        finally:
-            self.tmss_client.set_subtask_status(subtask_id, "queued", retry_count=5)
 
     def start_queued_observation_subtask(self, subtask: dict):
         '''start the queued observation subtask by sending the station specs to the station(s)'''
@@ -157,20 +174,45 @@ class L2TMSSObservationControlMessageHandler(TMSSEventMessageHandler):
         try:
             self.tmss_client.set_subtask_status(subtask_id, "starting", retry_count=5)
 
-            l2stationspecs = self.tmss_client.get_subtask_l2stationspecs(subtask_id, retry_count=5)
-            logger.info("subtask id=%s stationspecs=%s" % (subtask_id, l2stationspecs))
+            # Wait until 1 second before observation starts
+            # TODO(Corne): Use threadpool, don't block main thread with sleeping
+            sleep_time = (time_to_start - timedelta(seconds=1)).total_seconds()
+            logger.info("Sleeping for %f", sleep_time)
+            sleep(sleep_time)
+
+            # For each observation get the MultiStationObservation and start,
+            # ignore errors until done for each observation
+            host_errors = {}
+            observe_errors = set()
+            for observation_id, multi_obs in copy(
+                self.observation_pool.get_observations(subtask_id)
+            ).items():
+                results = multi_obs.start()
+
+                # Gather potential errors
+                for host, result in results.items():
+                    if isinstance(result, Exception):
+                        host_errors[host] = result
+                        observe_errors.add(observation_id)
+
+                # Don't need to track observation anymore
+                # TODO(Corne): Periodic task to clean up any leftovers that did
+                #              not get removed
+                self.observation_pool.remove(observation_id)
+
+            self.tmss_client.set_subtask_status(subtask_id, "started", retry_count=5)
 
-            # JS 2023-01-31: I'm not sure what actually needs to happen here. JD told me the stations "start" immediately once they get their spec.
-            # So, whould that mean that we "hold" the station specs until 1 seconds before the actual starttime???
-            # In my opinion, we need to do the preparation in enqueue_scheduled_observation_subtask
-            # and the actual real startup here in start_queued_observation_subtask
+            # If any exception raise
+            if observe_errors:
+                hosts = host_errors.keys()
+                exceptions = host_errors.values()
+                raise RuntimeError(
+                    "Failed to start observations=%s on hosts=%s with"
+                    "exceptions=%s", observe_errors, hosts, exceptions
+                    )
 
-            # todo: use station client to configure station with l2stationspecs
             # todo: start cobalt
-
+            # ok, the observation started! Now just let it run... and wait for it to finish. nothing to be done here anymore.
         except Exception as e:
-            logger.error(e)
+            logger.exception(e)
             self.tmss_client.set_subtask_status(subtask_id, "error", error_reason=str(e), retry_count=5)
-        finally:
-            self.tmss_client.set_subtask_status(subtask_id, "started", retry_count=5)
-            # ok, the observation started! Now just let it run... and wait for it to finish. nothing to be done here anymore.
\ No newline at end of file
diff --git a/SAS/TMSS/backend/services/lobster/lib/observation_pool.py b/SAS/TMSS/backend/services/lobster/lib/observation_pool.py
new file mode 100644
index 0000000000000000000000000000000000000000..3aa455054b73542d71df341a0320f94f6b7d367c
--- /dev/null
+++ b/SAS/TMSS/backend/services/lobster/lib/observation_pool.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023
+# ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This file is part of the LOFAR software suite.
+# The LOFAR software suite is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The LOFAR software suite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+#
+# $Id$
+
+from typing import Dict
+from typing import List
+
+from lofar_station_client.observation.multi_station_observation import (
+    MultiStationObservation,
+)
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class ObservationPool:
+    """ObservationPool for MultiStationObservation managed by id and subtask"""
+
+    def __init__(self):
+        self.pool = {}
+
+    def create_multistationobservation(
+        self, subtask_id: int, observation_id: int, stations: List[str],
+        specification: dict
+    ) -> MultiStationObservation:
+        """Create a multistationobservation instance and add to pool if non-existent"""
+
+        try:
+            self.get_multistationobservation(observation_id)
+            raise ValueError(
+                "Observation: %s already in current observation pool!",
+                observation_id
+            )
+        except KeyError:
+            pass
+
+        if not self.pool.get(subtask_id):
+            self.pool[subtask_id] = {}
+
+        self.pool[subtask_id][observation_id] = MultiStationObservation(
+            specification=specification, hosts=stations
+        )
+
+        return self.pool[subtask_id][observation_id]
+
+    def get_observations(
+        self, subtask_id: int
+    ) -> Dict[int, MultiStationObservation]:
+        """Get observations dict by subtask id
+
+        :param subtask_id: The subtask id to retrieve observations for
+        :raises KeyError: If subtask id not present in pool
+        :return: Dictionary with observation id as key and
+                 MultiStationObservation as values
+        """
+
+        return self.pool[subtask_id]
+
+    def get_multistationobservation(
+        self, observation_id: int
+    ) -> MultiStationObservation:
+        """Get a MultiStationObservation instance by observation id
+
+        :param observation_id: The unique id for the specific observation
+        :raises KeyError: If observation id not present in pool
+        :return: Instance of MultiStationObservation
+        """
+
+        for subtask in self.pool.values():
+            if subtask.get(observation_id):
+                return subtask[observation_id]
+
+        raise KeyError(
+            "Observation: %s not present in pool", observation_id
+        )
+
+    def remove(self, observation_id: int):
+        """Remove an observation
+
+        :raises KeyError: If observation id not in current pool
+        """
+
+        subtask = None
+
+        for _subtask, observations in self.pool.items():
+            if observations.get(observation_id):
+                subtask = _subtask
+                break
+
+        if subtask:
+            del self.pool[subtask][observation_id]
+            if len(self.pool[subtask]) is 0:
+                del self.pool[subtask]
+            return
+
+        raise KeyError(
+            "Observation: %s not in current observation pool!",
+            observation_id
+        )
diff --git a/SAS/TMSS/backend/services/lobster/lib/service_handler.py b/SAS/TMSS/backend/services/lobster/lib/service_handler.py
index 5b9b7df4ec745892fdb1f9195f19a3266bb4bddf..99271ffd03ec28fb402b4a78d1780a66289dfa90 100644
--- a/SAS/TMSS/backend/services/lobster/lib/service_handler.py
+++ b/SAS/TMSS/backend/services/lobster/lib/service_handler.py
@@ -22,6 +22,13 @@
 
 from lofar.messaging import DEFAULT_BUSNAME, DEFAULT_BROKER, RPCService, ServiceMessageHandler
 from lofar.sas.tmss.client.tmss_http_rest_client import TMSSsession
+from lofar.sas.tmss.services.lobster.specification_translation import (
+    combine_l2specification_multistation
+)
+
+from lofar_station_client.observation.multi_station_observation import (
+    MultiStationObservation
+)
 
 import logging
 logger = logging.getLogger(__name__)
@@ -44,16 +51,62 @@ class L2TMSSObservationControlServiceHandler(ServiceMessageHandler):
         self.tmss_client.close()
 
     def abort_observation(self, observation_subtask_id: int):
-        '''abort/kill the observation with given observation_subtask_id if running.'''
+        '''abort/kill the observation with observation_subtask_id if running.'''
         subtask = self.tmss_client.get_subtask(observation_subtask_id)
-        if subtask['state_value'] in ('queueing', 'queued', 'starting', 'started'):
-            logger.info("killing observation subtask id=%s state='%s'...", observation_subtask_id, subtask['state_value'])
-            # ToDo: do the actual "kill" of the observation using the tango api towards the stations
-            return True
-        else:
-            logger.warning("Cannot kill observation subtask id=%s because state='%s'", observation_subtask_id, subtask['state_value'])
-
-        return False
+
+        if not subtask['state_value'] in (
+            'queueing', 'queued', 'starting', 'started'
+        ):
+            logger.warning(
+                "Cannot kill observation subtask id=%s because state='%s'",
+                observation_subtask_id, subtask['state_value']
+            )
+            return
+
+        logger.info(
+            "killing observation subtask id=%s state='%s'...",
+            observation_subtask_id, subtask['state_value']
+        )
+
+        try:
+            exceptions = []
+            multi_station_observations = []
+            l2stationspecs = self.tmss_client.get_subtask_l2stationspecs(
+                observation_subtask_id, retry_count=5
+            )
+            observations = combine_l2specification_multistation(
+                l2stationspecs
+            )
+            for observation_id, value in observations.items():
+                multi_station_observations.append(MultiStationObservation(
+                    value['stations'], value['specification'])
+                )
+
+            for multi_station_observation in multi_station_observations:
+                results = multi_station_observation.stop()
+                for host, result in results.items():
+                    if isinstance(result, Exception):
+                        exceptions.append(result)
+
+            # TODO(Corne): Keep track of which hosts / observations did
+            #              not stop correctly
+            if len(exceptions) > 0:
+                raise RuntimeError(
+                    "Failed to abort subtask=%s with "
+                    "exceptions=%s", observation_subtask_id, exceptions
+                )
+
+            self.tmss_client.set_subtask_status(
+                observation_subtask_id, "cancelled", retry_count=5
+            )
+
+        except Exception as e:
+            logger.error(e)
+            self.tmss_client.set_subtask_status(
+                observation_subtask_id, "error", error_reason=str(e),
+                retry_count=5
+            )
+            return False
 
 
 def create_service(
diff --git a/SAS/TMSS/backend/services/lobster/lib/specification_translation.py b/SAS/TMSS/backend/services/lobster/lib/specification_translation.py
new file mode 100644
index 0000000000000000000000000000000000000000..cee681a3b25138f85633cdde8ae95af3e1a79acb
--- /dev/null
+++ b/SAS/TMSS/backend/services/lobster/lib/specification_translation.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023
+# ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This file is part of the LOFAR software suite.
+# The LOFAR software suite is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The LOFAR software suite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+#
+# $Id$
+
+from typing import Dict
+from typing import TypedDict
+from typing import Union
+from typing import List
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class MultistationData(TypedDict):
+    stations: List[str]
+    specification: dict
+
+
+def station_to_host(station: str) -> str:
+    """Convert name of station into connectable URL for connecting to PyTango"""
+    return f"{station}c.control.lofar"
+
+
+def combine_l2specification_multistation(
+    l2specification: dict
+) -> Dict[str, Union[List[str], Dict]]:
+    """Combine l2specficiation from TMSS into MultiStationObservation format
+
+    :param l2specification: Specification as retrieved from
+                            :method:`TMSSsession.get_subtask_l2stationspecs`
+    :return: Dictionary with {
+                observation_id: MultistationData()
+             }
+    """
+
+    observations = {}
+    for observation in l2specification['stations']:
+        observation_id = observation['specification']['observation_id']
+        if not observations.get(observation_id):
+            observations[observation_id] = MultistationData(
+                stations=[],
+                specification=observation['specification']
+            )
+
+        observations[observation_id]['stations'].append(
+            station_to_host(observation['station'])
+        )
+
+    return observations
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
index 84dc1a9136fb3b3880566aa133257c5b953e2bf2..20a064300785f061eabd2ade3c7d6b20abe7a285 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
@@ -2571,6 +2571,7 @@ def wait_for_subtask_status(subtask: Subtask, expected_status: typing.Union[Subt
         # wait a little...
         fetch_elapsed = (datetime.utcnow() - start_fetch_timestamp).total_seconds()
         sleep(max(0, poll_interval-fetch_elapsed))
+        logger.info("Waiting for status %s on %s", expected_status, subtask)
         # loop, try again
 
     raise TimeoutError("Timeout while waiting for subtask id=%s to get expected status '%s'. Current status: '%s'" % (subtask.id, expected_status, subtask.state))
diff --git a/SAS/TMSS/backend/test/CMakeLists.txt b/SAS/TMSS/backend/test/CMakeLists.txt
index cf045872c0c36b4a08a684a31d8fa3d6a28a3dd5..1c3ac4d135021f8663c8ef22901c33bb9f66ef2c 100644
--- a/SAS/TMSS/backend/test/CMakeLists.txt
+++ b/SAS/TMSS/backend/test/CMakeLists.txt
@@ -25,6 +25,7 @@ if(BUILD_TESTING)
     lofar_add_test(t_conversions)
     lofar_add_test(t_feedback)
     lofar_add_test(t_l2station_tmss_integration_test)
+    lofar_add_test(t_l2station_tmss_test)
     lofar_add_test(t_observation_strategies_specification_and_scheduling_test)
     lofar_add_test(t_observing_strategies_regression_test)
     lofar_add_test(t_permissions_project_roles)
diff --git a/SAS/TMSS/backend/test/t_l2station_tmss_integration_test.py b/SAS/TMSS/backend/test/t_l2station_tmss_integration_test.py
index 03ccae421ea1cab3632709a628854dee8f201221..371b7cea00761241f3cd58e111871806e55ae9bd 100755
--- a/SAS/TMSS/backend/test/t_l2station_tmss_integration_test.py
+++ b/SAS/TMSS/backend/test/t_l2station_tmss_integration_test.py
@@ -1,11 +1,20 @@
 #!/usr/bin/env python3
 import copy
 import unittest
+from unittest import mock
 
 import logging
 logger = logging.getLogger('lofar.'+__name__)
 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
 
+from lofar_station_client.observation import (
+    multi_station_observation
+)
+
+from lofar_station_client.observation.multi_station_observation import (
+    MultiStationObservation
+)
+
 from lofar.sas.tmss.test.test_environment import TMSSTestEnvironment
 
 from lofar.messaging.messagebus import TemporaryExchange, BusListenerJanitor
@@ -46,13 +55,17 @@ class TestL2StationTMSSIntegration(unittest.TestCase):
         cls.tmp_exchange.close()
 
     def test_simple_lofar2_observation(self):
-        from lofar.common.json_utils import add_defaults_to_json_object_for_schema
-        from lofar.sas.tmss.test.test_utils import set_subtask_state_following_allowed_transitions
         from lofar.sas.tmss.test.tmss_test_data_django_models import Project_test_data, SchedulingSet_test_data
         from lofar.sas.tmss.tmss.tmssapp import models
-        from lofar.sas.tmss.tmss.tmssapp.tasks import create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft, update_task_graph_from_specifications_doc, mark_task_blueprint_as_obsolete
+        from lofar.sas.tmss.tmss.tmssapp.tasks import (
+            create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft,
+            update_task_graph_from_specifications_doc, mark_task_blueprint_as_obsolete
+        )
         from lofar.sas.tmss.tmss.tmssapp.subtasks import wait_for_subtask_status, schedule_subtask
 
+        SCHEDULE_TIME = 15
+        SCHEDULE_TIMEOUT = SCHEDULE_TIME * 4
+
         # Setup
         project = models.Project.objects.create(**Project_test_data(auto_ingest=True))
         scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data(project=project))
@@ -61,9 +74,10 @@ class TestL2StationTMSSIntegration(unittest.TestCase):
         strategy_template = models.SchedulingUnitObservingStrategyTemplate.get_latest(name="Simple Observation")
         scheduling_unit_spec = copy.deepcopy(strategy_template.template)
         # overrule the normal stations for this template with just the one CS001 LOFAR2 station
-        scheduling_unit_spec['tasks']['Observation']['specifications_doc']['station_configuration']['station_groups'] = [
-            {'stations': ['CS001'], 'max_nr_missing': 0}
-        ]
+        station_groups = [{'stations': ['CS001'], 'max_nr_missing': 0}]
+        scheduling_unit_spec['tasks']['Observation']['specifications_doc']['station_configuration'][
+            'station_groups'
+        ] = station_groups
 
         # create a scheduling unit draft & blueprint
         su_draft = models.SchedulingUnitDraft.objects.create(
@@ -79,27 +93,38 @@ class TestL2StationTMSSIntegration(unittest.TestCase):
             specifications_template__type__value=models.SubtaskType.Choices.OBSERVATION.value
         )
 
-        # schedule it 1 minute from now
-        observation_subtask = schedule_subtask(observation_subtask, datetime.utcnow()+timedelta(minutes=1))
+        # schedule it 15 seconds from now
+        observation_subtask = schedule_subtask(
+            observation_subtask, datetime.utcnow() + timedelta(seconds=SCHEDULE_TIME)
+        )
         self.assertEqual(models.SubtaskState.Choices.SCHEDULED.value, observation_subtask.state.value)
 
-        # start the lobster buslistener
-        # this should pick up the scheduled observation and send instructions to the (mocked) station.
-        # as a result, the observation subtask should become STARTED
-        with L2TMSSObservationControlBusListener(
-            self.tmp_exchange.address, self.tmp_exchange.broker,
-            self.tmss_test_env.client_credentials.dbcreds_id
-        ) as lobster_buslistener:
-
-            # wait for station client to do it's work...
-            try:
-                wait_for_subtask_status(observation_subtask, models.SubtaskState.Choices.STARTED.value)
-            except TimeoutError:
-                # ToDo: remove this try/except TimeoutError when the station client did it's work and started the observation
-                pass
-
-            # ToDo: add asserts to check if (mocked) station was indeed initialized with this observation's specs.
-            self.assertTrue(True)
+        # Prevent actual connections to real PyTango station controllers
+        # Patch waiting and retrieving on future results
+        with mock.patch.object(
+            multi_station_observation, "StationFutures", autospec=True
+        ):
+            with mock.patch.object(
+                MultiStationObservation, "_get_results"
+            ) as m_result:
+                m_result.return_value = [True] * len(
+                    station_groups[0]['stations']
+                )
+
+                # start the lobster buslistener
+                # this should pick up the scheduled observation and send instructions
+                # to the (mocked) station. as a result, the observation subtask should
+                # become STARTED
+                with L2TMSSObservationControlBusListener(
+                    self.tmp_exchange.address, self.tmp_exchange.broker,
+                    self.tmss_test_env.client_credentials.dbcreds_id
+                ) as lobster_buslistener:
+
+                    wait_for_subtask_status(
+                        observation_subtask,
+                        models.SubtaskState.Choices.STARTED.value,
+                        timeout=SCHEDULE_TIMEOUT
+                    )
 
 
 if __name__ == '__main__':
diff --git a/SAS/TMSS/backend/test/t_l2station_tmss_test.py b/SAS/TMSS/backend/test/t_l2station_tmss_test.py
new file mode 100755
index 0000000000000000000000000000000000000000..7292a766008d5183bb9690d4c88085c28e71b1d2
--- /dev/null
+++ b/SAS/TMSS/backend/test/t_l2station_tmss_test.py
@@ -0,0 +1,240 @@
+#!/usr/bin/env python3
+import unittest
+import logging
+import json
+
+from lofar_station_client.observation.multi_station_observation import (
+    MultiStationObservation,
+)
+
+try:
+    from lofar.sas.tmss.services.lobster.observation_pool import ObservationPool
+    from lofar.sas.tmss.services.lobster.specification_translation import (
+        station_to_host
+    )
+    from lofar.sas.tmss.services.lobster.specification_translation import (
+        combine_l2specification_multistation
+    )
+except ModuleNotFoundError:
+    print("Skipping test. could not import lobster 'TMSSLobster' service. Did you build it?")
+    exit(3)
+
+logger = logging.getLogger('lofar.'+__name__)
+logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
+
+
+# 3 stations, 2 observations, station 1 and two share observation
+test_dummy_spec = json.loads("""
+{
+  "stations": [
+    {
+      "specification": {
+        "SAPs": [
+          {
+            "name": "target",
+            "pointing": {
+              "angle1": 0.6624317181687094,
+              "angle2": 1.5579526427549426,
+              "direction_type": "J2000",
+              "target": "target1"
+            },
+            "purpose": "target",
+            "subbands": [
+              104,
+              105
+            ]
+          }
+        ],
+        "antenna_mask": [
+          1
+        ],
+        "filter": "HBA_110_190",
+        "observation_id": 2021361,
+        "stop_time": "2023-07-06T18:14:00"
+      },
+      "station": "CS001"
+    },
+    {
+      "specification": {
+        "SAPs": [
+          {
+            "name": "target",
+            "pointing": {
+              "angle1": 0.6624317181687094,
+              "angle2": 1.5579526427549426,
+              "direction_type": "J2000",
+              "target": "target1"
+            },
+            "purpose": "target",
+            "subbands": [
+              104,
+              105
+            ]
+          }
+        ],
+        "antenna_mask": [
+          1
+        ],
+        "filter": "HBA_110_190",
+        "observation_id": 2021361,
+        "stop_time": "2023-07-06T18:14:00"
+      },
+      "station": "CS002"
+    },
+    {
+      "specification": {
+        "SAPs": [
+          {
+            "name": "target",
+            "pointing": {
+              "angle1": 1.6624317181687094,
+              "angle2": 0.5579526427549426,
+              "direction_type": "J2000",
+              "target": "target1"
+            },
+            "purpose": "target",
+            "subbands": [
+              104,
+              105
+            ]
+          }
+        ],
+        "antenna_mask": [
+          1
+        ],
+        "filter": "HBA_110_190",
+        "observation_id": 2021362,
+        "stop_time": "2023-07-06T18:14:00"
+      },
+      "station": "CS003"
+    }
+  ]
+}
+""")
+
+
+class TestL2StationTMSS(unittest.TestCase):
+
+    def test_station_to_host(self):
+        "Test station to host"
+
+        self.assertEqual("testc.control.lofar", station_to_host("test"))
+        self.assertEqual("cs001c.control.lofar", station_to_host("cs001"))
+
+    def test_observation_pool_create_multistationobservation_get(self):
+        """Create multistationobservation and retrieve observation from pool"""
+        t_subtask_id = 1234
+        t_observation_id = 2021361
+
+        t_observation_pool = ObservationPool()
+
+        t_observation_pool.create_multistationobservation(
+            subtask_id=t_subtask_id, observation_id=t_observation_id,
+            specification={
+                "observation_id": t_observation_id
+            }, stations=[]
+        )
+
+        self.assertIsInstance(
+            t_observation_pool.get_multistationobservation(t_observation_id),
+            MultiStationObservation
+        )
+
+        self.assertRaises(
+            KeyError, t_observation_pool.get_multistationobservation, 12345
+        )
+
+    def test_observation_pool_create_multistationobservation_duplicate_error(
+        self
+    ):
+        """Create multistationobs duplicate observations which should error"""
+        t_subtask_id = 1234
+        t_observation_id = 2021361
+
+        t_observation_pool = ObservationPool()
+
+        t_observation_pool.create_multistationobservation(
+            subtask_id=t_subtask_id, observation_id=t_observation_id,
+            specification={
+                "observation_id": t_observation_id
+            }, stations=[]
+        )
+
+        self.assertRaises(
+            ValueError, t_observation_pool.create_multistationobservation,
+            subtask_id=t_subtask_id,
+            observation_id=t_observation_id,
+            specification={
+                "observation_id": t_observation_id
+            }, stations=[]
+        )
+
+    def test_observation_pool_create_multistationobservation_remove(self):
+        """create multistationobs and remove observations multiple times"""
+        insertions = 10
+
+        t_subtask_id = 1234
+        t_observation_pool = ObservationPool()
+
+        for i in range(insertions):
+            t_observation_pool.create_multistationobservation(
+                subtask_id=t_subtask_id, observation_id=i,
+                specification={
+                    "observation_id": i
+                }, stations=[]
+            )
+
+        self.assertEqual(1, len(t_observation_pool.pool))
+        self.assertEqual(insertions, len(t_observation_pool.pool[t_subtask_id]))
+
+        for i in range(insertions):
+            self.assertIsInstance(
+                t_observation_pool.get_multistationobservation(i),
+                MultiStationObservation
+            )
+            t_observation_pool.remove(i)
+            self.assertRaises(
+                KeyError, t_observation_pool.get_multistationobservation, i
+            )
+
+        self.assertEqual(0, len(t_observation_pool.pool))
+
+    def test_observation_pool_subtasks_get_observations(self):
+        """Test associating observations to subtask using multi level dict"""
+        num_subtasks = 5
+        num_obs = 10
+
+        t_observation_pool = ObservationPool()
+
+        obs_id = 0
+        for i in range(num_subtasks):
+            for j in range(num_obs-i):
+                t_observation_pool.create_multistationobservation(
+                    subtask_id=i, observation_id=obs_id,
+                    specification={
+                        "observation_id": obs_id
+                    }, stations=[]
+                )
+                obs_id += 1
+
+        for i in range(num_subtasks):
+            self.assertEqual(
+                num_obs-i, len(t_observation_pool.get_observations(i))
+            )
+
+    def test_combine_l2specification_multistation(self):
+        "Test combine_l2specification_multistation"
+
+        result = combine_l2specification_multistation(test_dummy_spec)
+
+        self.assertIn(2021361, result)
+        self.assertIn(2021362, result)
+
+        self.assertIn("CS001c.control.lofar", result[2021361]['stations'])
+        self.assertIn("CS002c.control.lofar", result[2021361]['stations'])
+
+        self.assertIn("CS003c.control.lofar", result[2021362]['stations'])
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/SAS/TMSS/backend/test/t_l2station_tmss_test.run b/SAS/TMSS/backend/test/t_l2station_tmss_test.run
new file mode 100755
index 0000000000000000000000000000000000000000..ba9164b5cf5995117c39c6d21711844836038866
--- /dev/null
+++ b/SAS/TMSS/backend/test/t_l2station_tmss_test.run
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+python3 t_l2station_tmss_test.py
diff --git a/SAS/TMSS/backend/test/t_l2station_tmss_test.sh b/SAS/TMSS/backend/test/t_l2station_tmss_test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..19e4b7fdc4ec433b8029f3affde686d8fb67aa50
--- /dev/null
+++ b/SAS/TMSS/backend/test/t_l2station_tmss_test.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./runctest.sh t_l2station_tmss_test
diff --git a/SAS/TMSS/docker/Jenkinsfile b/SAS/TMSS/docker/Jenkinsfile
deleted file mode 100644
index aa9d46c59d9ef1e64219c2b634cda6c32ab79817..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/Jenkinsfile
+++ /dev/null
@@ -1,50 +0,0 @@
-pipeline {
-    agent {
-        label 'bob'
-    }
-    environment {
-       DOCKER_TAG = "${env.BUILD_TAG}"
-       LOFAR_REGISTRY = "nexus.cep4.control.lofar:18080"
-       LOFAR_REGISTRY_URL = "http://nexus.cep4.control.lofar:18080"
-    }
-
-    stages {
-        stage('Build') {
-
-            steps {
-                script {
-                    dir ('SAS/TMSS/docker/tmss'){
-                        docker.build("tmss", "--build-arg BRANCH=${env.BRANCH_NAME} .").tag("${env.DOCKER_TAG}")
-                    }
-		
-                    dir ('SAS/TMSS/docker/tmss-postgres'){
-                        docker.build("tmss-postgres").tag("${env.DOCKER_TAG}")
-                    }
-                }
-
-            }
-        }
-        stage('Push to nexus') {
-            steps {
-                script {
-                    withDockerRegistry(credentialsId: 'nexus', url: env.LOFAR_REGISTRY_URL) {
-                        tag_and_push("tmss:${env.DOCKER_TAG}", env.LOFAR_REGISTRY)
-			tag_and_push("tmss-postgres:${env.DOCKER_TAG}")
-
-                    }
-                }
-            }
-        }
-        stage('Deploy') {
-            steps {
-                echo 'Deploying....'
-            }
-        }
-    }
-}
-
-def tag_and_push(image_name, registry){
-    sh "docker tag $image_name $registry/$image_name"
-    sh "docker push $registry/$image_name"
-}
-
diff --git a/SAS/TMSS/docker/README.md b/SAS/TMSS/docker/README.md
deleted file mode 100644
index 19deacef0e6cb42bff7c7890880d3c0cd1b20cc7..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-To build:
-
-	docker build -t tmss-postgres tmss-postgres
-	docker build -t tmss [--build-arg BRANCH=TMSS-epic] [--build-arg UID=`id -u`] tmss
-
-To start the PostgreSQL container:
-
-	docker run [-it] --name=postgres-$USER --rm tmss-postgres
-
-To start the TMSS container (exposing port 8001 to surf to) AND TMSS app:
-
-	docker run [-it] --rm -p 0.0.0.0:8001:8000 --link=postgres-$USER:postgres tmss
-
-To start the TMSS container (exposing port 8001 to surf to) for debugging/testing:
-
-	docker run -it --rm -p 0.0.0.0:8001:8000 --link=postgres-$USER:postgres tmss bash
-
-Note: "-it" allows one to abort the container with ^C.
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-compose.yml b/SAS/TMSS/docker/tmss-nginxenv/docker-compose.yml
deleted file mode 100644
index a6eaac2f06d12792832a820388438abbf81bf5a6..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-compose.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-version: "2"
-services:
-  tmss_test:
-    build:
-      context: .
-      dockerfile: tmss_testenv_Dockerfile
-    container_name: tmss_test
-    ports:
-      - "8000:8000"
-     # - "3003:3003"
-    networks:
-      - "tmss"
-    volumes:
-      - static_volume:/staticfiles
-    environment:
-      - OIDC_ENDPOINT_HOST=172.25.0.10
-      - OIDC_RP_CLIENT_ID=1
-  tmss_test_nginx:
-    build:
-      context: .
-      dockerfile: tmss_nginx_Dockerfile
-    container_name: tmss_test_nginx
-    ports:
-      - "80:80"
-    networks:
-      - "tmss"
-    volumes:
-      - static_volume:/staticfiles
-  tmss_test_oidc:
-    build:
-      context: ./docker-test-mozilla-django-oidc/
-      dockerfile: dockerfiles/oidc_testprovider
-    container_name: tmss_test_oidc
-    ports:
-      - "8088:8088"
-    networks:
-      tmss:
-        ipv4_address: 172.25.0.10
-networks:
-  tmss:
-    driver: bridge
-    ipam:
-      driver: default
-      config:
-        - subnet: 172.25.0.0/16
-          gateway: 172.25.0.1
-volumes:
-  static_volume:
\ No newline at end of file
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/.circleci/config.yml b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/.circleci/config.yml
deleted file mode 100644
index 7c2b7c3c55992eb980b14c96eaa1a879ef170369..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/.circleci/config.yml
+++ /dev/null
@@ -1,100 +0,0 @@
-# Python CircleCI 2.0 configuration file
-#
-# Check https://circleci.com/docs/2.0/language-python/ for more details
-#
-version: 2
-jobs:
-  build:
-    docker:
-      - image: mozilla/cidockerbases:docker-latest
-    working_directory: /
-
-    steps:
-      - run:
-          name: Get info
-          command: uname -v
-
-      - setup_remote_docker
-
-      - run:
-          name: Get info 
-          command: docker info
-
-      - run:
-          name: Install essential packages
-          command: apt-get install make
-
-      - checkout:
-          path: /oidc_testprovider
-
-      - run:
-          name: Build Docker images
-          working_directory: /oidc_testprovider
-          command: |
-            make build
-
-      - run:
-          name: Push to Dockerhub on tag
-          working_directory: /oidc_testprovider
-          command: |
-            function retry {
-              set +e
-              local n=0
-              local max=3
-              while true; do
-              "$@" && break || {
-                if [[ $n -lt $max ]]; then
-                  ((n++))
-                  echo "Command failed. Attempt $n/$max:"
-                else
-                  echo "Failed after $n attempts."
-                  exit 1
-                fi
-              }
-              done
-              set -e
-            }
-
-            # Namespace on dockerhub to push:
-            # https://hub.docker.com/u/mozilla/oidc-testprovider
-            export DOCKER_NAMESPACE=mozilla/oidc-testprovider
-            export IMAGES=(oidc_e2e_setup_py2 oidc_e2e_setup_py3 oidc_testprovider oidc_testrp_py2 oidc_testrp_py3 oidc_testrunner)
-
-            # If a tag was pushed to github, push tagged images and latest
-            # images to Dockerhub
-            if [ -n "${CIRCLE_TAG}" ]; then
-              # Log into Dockerhub
-              echo "${DOCKER_PASS}" | docker login -u="${DOCKER_USER}" --password-stdin
-
-              for IMAGE in "${IMAGES[@]}"
-              do
-                echo ""
-                echo ">>> WORKING ON ${IMAGE}..."
-                echo ""
-                # Tag and push tagged image.
-                retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}"
-                retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}"
-
-                # Tag and push latest image.
-                retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-latest"
-                retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-latest"
-              done
-            fi
-
-workflows:
-  version: 2
-
-  # workflow jobs are _not_ run in tag builds by default
-  # we use filters to whitelist jobs that should be run for tags
-
-  # workflow jobs are run in _all_ branch builds by default
-  # we use filters to blacklist jobs that shouldn't be run for a branch
-
-  # see: https://circleci.com/docs/2.0/workflows/#git-tag-job-execution
-
-  build-test-push:
-    jobs:
-      - build:
-          filters:
-            tags:
-              only: /.*/
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/HISTORY.md b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/HISTORY.md
deleted file mode 100644
index 4d8d62422483fd93d04159b64dcc376cec4ae539..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/HISTORY.md
+++ /dev/null
@@ -1,35 +0,0 @@
-HISTORY
-=======
-
-v0.9.3 (October 23rd, 2019)
----------------------------
-
-Bugs:
-
-* fix docker push code
-
-
-v0.9.2 (October 22nd, 2019)
----------------------------
-
-No substantive changes. Doing a new tag so as to push images to dockerhub.
-
-
-v0.9.1 (October 22nd, 2019)
----------------------------
-
-Bugs:
-
-* fix `build` and `pull` rules in Makefile to use the correct tags
-
-
-v0.9.0 (October 22nd, 2019)
----------------------------
-
-First tagged release.
-
-Features:
-
-* new `createuser` command in `oidc_testprovider` image
-* redid how images are tagged and we're now pushing them to dockerhub
-  in the `mozilla` user
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/Makefile b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/Makefile
deleted file mode 100644
index 091744b79538494207e8499c5d2ab1d9a57d49d4..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-DEFAULT_GOAL := help
-
-NS ?= mozilla/oidc-testprovider
-IMAGES := oidc_testprovider oidc_testrunner oidc_testrp_py2 oidc_testrp_py3 oidc_e2e_setup_py2 oidc_e2e_setup_py3
-BUILD := $(addprefix build-,${IMAGES})
-PULL := $(addprefix pull-,$(IMAGES))
-CLEAN := $(addprefix clean-,$(IMAGES))
-
-.PHONY: help
-help:
-	@fgrep -h "##" Makefile | fgrep -v fgrep | sed 's/\(.*\):.*##/\1:/'
-
-.PHONY: build
-build: ${BUILD} ## Build all images
-
-.PHONY: pull
-pull: ${PULL} ## Pull all -latest images
-
-.PHONY: clean
-clean: ${CLEAN} ## Clean images and other artifacts
-
-.PHONY: ${BUILD}
-${BUILD}: build-%:
-	docker build -t $* -f dockerfiles/$* .
-
-.PHONY: ${PULL}
-${PULL}: pull-%:
-	docker pull ${NS}:$*-latest
-
-.PHONY: ${CLEAN}
-${CLEAN}: clean-%:
-	docker rmi ${NS}/$(subst _py,:py,$(*))
-	docker rmi $(subst _py,:py,$(*))
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/README.md b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/README.md
deleted file mode 100644
index 9037b454463959b2a99f01058e314f7d0d8de937..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/README.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# docker-test-mozilla-django-oidc
-
-The purpose of these docker images is to setup a local environment to develop and test
-`mozilla-django-oidc`.
-
-
-## oidc-testprovider
-
-https://hub.docker.com/r/mozilla/oidc-testprovider/tags?name=testprovider
-
-* Provides a docker image for an OIDC OP with preconfigured OIDC client IDs and secrets
-* OIDC provider endpoint is exposed in port `8080`
-* Provides a Django management command for creating users
-* Uses `django-oidc-provider`
-
-
-### Usage
-
-In order for this setup to work `testprovider`, `testrp` hostnames should resolve to the
-IP of the docker image (for local development it's `127.0.0.1`).
-
-You can add the resolution to your `/etc/hosts` file.
-
-You can also use [nip.io](http://nip.io/). For example, if you name the service
-"oidcprovider", then you could have these three variables:
-
-```
-OIDC_OP_AUTHORIZATION_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/authorize
-OIDC_OP_TOKEN_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/token
-OIDC_OP_USER_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/userinfo
-```
-
-### Example setup
-
-`docker-compose.yml`
-
-```
-version: '3'
-services:
-  testprovider:
-    image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3
-    ports:
-      - "8080:8080"
-```
-
-
-### Creating users in the container
-
-The `testprovider` image has a Django management command for creating users in
-the OIDC provider. This lets you create users on the command line.
-
-With an already running `testprovider` container run:
-
-```
-docker-compose exec testprovider manage.py createuser USERNAME PASSWORD EMAIL
-```
-
-
-## Other images
-
-All images are pushed to: https://hub.docker.com/r/mozilla/oidc-testprovider
-
-* `oidc_testprovider` (See above)
-* `oidc_testrunner`
-* `oidc_testrp_py{2,3}`
-    * Test django project preconfigured to work with `testprovider`
-    * Uses `mozilla-django-oidc` as an authentication backend
-    * Test RP is exposed in port `8081`
-    * Builds based in both python 2/3
-    * Environment variables
-        * `TEST_OIDC_ALGO={hs,rs}`
-* `oidc_e2e_setup_py{2,3}`
-    * Dockerized setup for e2e testing of mozilla-django-oidc
-
-
-### Example setup for oidc_testrp
-
-`docker-compose.yml`
-
-```
-version: '3'
-services:
-  testrp:
-    image: mozilla/oidc-testprovider:oidc_testrp_py3-v0.9.3
-    ports:
-      - "8081:8081"
-    environment:
-      - TEST_OIDC_ALGO=hs
-```
-
-## Development
-
-We use `make` to automate the docker image workflow.
-
-For more info run `make help`.
-
-Pushing a tag to GitHub will trigger building images and uploading them
-to Dockerhub.
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/docker-compose.yml b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/docker-compose.yml
deleted file mode 100644
index a1022994588976175c6169fee1051c60b7b89cdf..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/docker-compose.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-version: '3'
-services:
-  testprovider:
-    image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3
-    ports:
-      - "8080:8080"
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2 b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2
deleted file mode 100644
index ac0e6a7bf389c7c6cb802137e8544f889b863853..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2
+++ /dev/null
@@ -1,29 +0,0 @@
-FROM python:2-stretch
-
-EXPOSE 8080 8081
-
-RUN pip install virtualenv
-RUN virtualenv /testrp_env
-RUN virtualenv /testprovider_env
-
-COPY testprovider /testprovider/
-COPY testrp /testrp/
-
-RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt
-RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt
-
-# Install python and python dependencies
-RUN apt-get update && \
-    apt-get install -y wait-for-it
-
-# Install firefox
-RUN apt-get install -y --no-install-recommends firefox-esr && \
-    wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
-    tar xvf /tmp/firefox.tar.bz2 -C /opt && \
-    rm /usr/bin/firefox && \
-    ln -s /opt/firefox/firefox /usr/bin/firefox
-
-# Install geckodriver
-RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
-    tar xvf /tmp/geckodriver.tar.gz -C /opt && \
-    ln -s /opt/geckodriver /usr/bin/geckodriver
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3 b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3
deleted file mode 100644
index 9ed6e566c6b88dd21d5782d7e1b477290042b501..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3
+++ /dev/null
@@ -1,29 +0,0 @@
-FROM python:3.6-stretch
-
-EXPOSE 8080 8081
-
-RUN pip install virtualenv
-RUN virtualenv /testrp_env
-RUN virtualenv /testprovider_env
-
-COPY testprovider /testprovider/
-COPY testrp /testrp/
-
-RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt
-RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt
-
-# Install python and python dependencies
-RUN apt-get update && \
-    apt-get install -y wait-for-it
-
-# Install firefox
-RUN apt-get install -y --no-install-recommends firefox-esr && \
-    wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
-    tar xvf /tmp/firefox.tar.bz2 -C /opt && \
-    rm /usr/bin/firefox && \
-    ln -s /opt/firefox/firefox /usr/bin/firefox
-
-# Install geckodriver
-RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
-    tar xvf /tmp/geckodriver.tar.gz -C /opt && \
-    ln -s /opt/geckodriver /usr/bin/geckodriver
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider
deleted file mode 100644
index e93084d98a19041a1e16b974caee552d6e8ba5d3..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider
+++ /dev/null
@@ -1,10 +0,0 @@
-FROM python:3.6
-EXPOSE 8088
-WORKDIR /code
-
-COPY testprovider/requirements.txt /code/
-RUN pip install -r requirements.txt
-
-COPY testprovider /code/
-
-CMD ./bin/run.sh
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2 b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2
deleted file mode 100644
index 369b2742d7ca7d06b7fa6e2aa20bc71aad6e089d..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM python:2-stretch
-EXPOSE 8081
-COPY testrp /code/
-WORKDIR /code
-
-RUN pip install -r requirements.txt
-CMD ./bin/run.sh
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3 b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3
deleted file mode 100644
index f4d52e4dfe609d8e4fc6168da02bb518200d6f2d..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM python:3-stretch
-EXPOSE 8081
-COPY testrp /code/
-WORKDIR /code
-
-RUN pip install -r requirements.txt
-CMD ./bin/run.sh
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner
deleted file mode 100644
index 422da4a032271f4268b88120df86fbd18e2f13f8..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner
+++ /dev/null
@@ -1,18 +0,0 @@
-FROM python:3-stretch
-
-# Install python and python dependencies
-RUN apt-get update && \
-    apt-get install -y wait-for-it && \
-    pip install six splinter
-
-# Install firefox
-RUN apt-get install -y --no-install-recommends firefox-esr && \
-    wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
-    tar xvf /tmp/firefox.tar.bz2 -C /opt && \
-    rm /usr/bin/firefox && \
-    ln -s /opt/firefox/firefox /usr/bin/firefox
-
-# Install geckodriver
-RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
-    tar xvf /tmp/geckodriver.tar.gz -C /opt && \
-    ln -s /opt/geckodriver /usr/bin/geckodriver
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/bin/run.sh b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/bin/run.sh
deleted file mode 100755
index faf5bf5ed8e04cf5452e6c98c6e8c1c5430f19c2..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/bin/run.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-if [ -n "$OIDC_OP_CALLBACK_ENDPOINT" ]; then sed -i "s|http://localhost:8000/oidc/callback/|$OIDC_OP_CALLBACK_ENDPOINT|" fixtures.json; fi
-
-python manage.py migrate --noinput
-python manage.py loaddata fixtures.json
-python ./manage.py createuser paulus pauluspass paulus@localhost
-python manage.py runserver 0.0.0.0:8088
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/fixtures.json b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/fixtures.json
deleted file mode 100644
index 43edad324d91adad1533b40d9aa0c7a61ca1f104..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/fixtures.json
+++ /dev/null
@@ -1,140 +0,0 @@
-[
-  {
-    "model": "sites.site",
-    "pk": 1,
-    "fields": {
-      "domain": "testprovider:8088",
-      "name": "testprovider"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 1,
-    "fields": {
-      "value": "code",
-      "description": "code (Authorization Code Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 2,
-    "fields": {
-      "value": "id_token",
-      "description": "id_token (Implicit Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 3,
-    "fields": {
-      "value": "id_token token",
-      "description": "id_token token (Implicit Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 4,
-    "fields": {
-      "value": "code token",
-      "description": "code token (Hybrid Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 5,
-    "fields": {
-      "value": "code id_token",
-      "description": "code id_token (Hybrid Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.responsetype",
-    "pk": 6,
-    "fields": {
-      "value": "code id_token token",
-      "description": "code id_token token (Hybrid Flow)"
-    }
-  },
-  {
-    "model": "oidc_provider.client",
-    "pk": 1,
-    "fields": {
-      "name": "testrpHS256",
-      "owner": null,
-      "client_type": "confidential",
-      "client_id": "1",
-      "client_secret": "secret",
-      "jwt_alg": "HS256",
-      "date_created": "2017-11-10",
-      "website_url": "",
-      "terms_url": "",
-      "contact_email": "",
-      "logo": "",
-      "reuse_consent": true,
-      "require_consent": true,
-      "_redirect_uris": "http://localhost/oidc/callback/",
-      "_post_logout_redirect_uris": "",
-      "_scope": "",
-      "response_types": [
-        1
-      ]
-    }
-  },
-    {
-    "model": "oidc_provider.client",
-    "pk": 2,
-    "fields": {
-      "name": "testrpHS256",
-      "owner": null,
-      "client_type": "confidential",
-      "client_id": "2",
-      "client_secret": "secret",
-      "jwt_alg": "HS256",
-      "date_created": "2017-11-10",
-      "website_url": "",
-      "terms_url": "",
-      "contact_email": "",
-      "logo": "",
-      "reuse_consent": true,
-      "require_consent": true,
-      "_redirect_uris": "http://localhost:8000/oidc/callback/",
-      "_post_logout_redirect_uris": "",
-      "_scope": "",
-      "response_types": [
-        1
-      ]
-    }
-  },
-  {
-    "model": "oidc_provider.client",
-    "pk": 3,
-    "fields": {
-      "name": "testrpRS256",
-      "owner": null,
-      "client_type": "confidential",
-      "client_id": "3",
-      "client_secret": "secret",
-      "jwt_alg": "RS256",
-      "date_created": "2017-11-10",
-      "website_url": "",
-      "terms_url": "",
-      "contact_email": "",
-      "logo": "",
-      "reuse_consent": true,
-      "require_consent": true,
-      "_redirect_uris": "http://localhost:8000/oidc/callback/",
-      "_post_logout_redirect_uris": "",
-      "_scope": "",
-      "response_types": [
-        1
-      ]
-    }
-  },
-  {
-    "model": "oidc_provider.rsakey",
-    "pk": 3,
-    "fields": {
-      "key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDAAgiIdiJG7GSMKTRbnGjWpHp1ulJ43/iQjDywWh5MP3in2PK8\nPVI6ItxIFLV81nWZMymA7hjfP7adOlxKY6rI+fExn8cTimI3W/oX6mHrPXm52uj/\nwe839pxxkeD7cmWgaif9Sujuy5AHUuUM1BTlO55POHkmhWyYMKC2P29qgQIDAQAB\nAoGAUHdJri6b1M8yoA6Qk6frw7AwZfAMqf1qxOEQefN6aQfcf7MKntqwAA8l88tB\n96xEokxvo0mlAMJJvIB9tusn4dIHKpmQGacQWVd/KONxPkvyuGgQXX5KCusZTbg7\ni6YQM52RGbExVFWLdGYJRBvzyfRkWX0b4LiderPZUiD6J/UCQQDZIgnLqYyGw3Ro\nnNboWYyOtLhKMF59f/0aSMXLlWdsnFG8kVm/7tw6jcDBalELci/+ExL2JACGwDea\n8DpvWiEDAkEA4mCovWmMDiS8tQCeY5NDic1wMp51+Ya8RX47bvb5F+X7SSE9L87y\n6eU9zVBSY8F+9npkvrxoU9PlKbS3Lzz1KwJAZ5/8BsuS+lnbe3Wmhtr93rlW3mk5\nHzHu7BVg+GkEI+xygcjoiVYImpU+MdB4fzrutpYJzZie+7BOmU4exTfBWwJBAKj+\nN3mO/Xrhee41VAhJuzV4I7XmDXQFXS8TmRKxVCq/COQC6EZ0W2q4M3a964OEw18E\n54hr5gYOPRjxS378JpkCQDjKw2Vyw0S0M8O2hOGuNsUtlGApYKt2iA41jGUf7bvO\nWz/tQuEIXQMd4e9zxNxOzPJOtjR1gyPZyi/FvsgDJDU=\n-----END RSA PRIVATE KEY-----"
-    }
-  }
-]
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/manage.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/manage.py
deleted file mode 100755
index 5fccf17e2ac7382f4d86d3e79a1d789f72bda004..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/manage.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-import os
-import sys
-
-if __name__ == "__main__":
-    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oidcprovider.settings")
-    try:
-        from django.core.management import execute_from_command_line
-    except ImportError:
-        # The above import may fail for some other reason. Ensure that the
-        # issue is really that Django is missing to avoid masking other
-        # exceptions on Python 2.
-        try:
-            import django
-        except ImportError:
-            raise ImportError(
-                "Couldn't import Django. Are you sure it's installed and "
-                "available on your PYTHONPATH environment variable? Did you "
-                "forget to activate a virtual environment?"
-            )
-        raise
-    execute_from_command_line(sys.argv)
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/__init__.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/__init__.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/__init__.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py
deleted file mode 100644
index 76eb780c1f5247a94400bdb7421761416ad20548..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-"""
-Create a user in the OIDC provider.
-"""
-
-from django.contrib.auth.models import User
-from django.core.management.base import BaseCommand
-
-
-class Command(BaseCommand):
-    help = "Create a user in the OIDC provider."
-
-    def add_arguments(self, parser):
-        parser.add_argument("username", help="account username")
-        parser.add_argument("password", help="account password")
-        parser.add_argument("email", help="account email address")
-        parser.add_argument("groups", help="account user groups", nargs='*')
-
-    def handle(self, **options):
-        username = options["username"]
-        password = options["password"]
-        email = options["email"]
-        groups = options["groups"]
-
-        if User.objects.filter(username=username).exists():
-            self.stdout.write("User {} already exists.".format(username))
-            return
-
-        user = User.objects.create(username=username, email=email)
-        user.set_password(password)
-        user.groups.set(groups)
-        user.save()
-        self.stdout.write("User {} created.".format(username))
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py
deleted file mode 100644
index 9f2eca62c36f16daada5279a294470405c38cfdb..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py
+++ /dev/null
@@ -1,149 +0,0 @@
-"""
-Django settings for oidcprovider project.
-
-Generated by 'django-admin startproject' using Django 1.11.6.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.11/ref/settings/
-"""
-
-import os
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = '_brj&4ea0ec%ybc(rz32jpqwypdy4@d9lttg&g7!^e(m!-52si'
-SESSION_COOKIE_NAME = 'oidcprovider'
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
-ALLOWED_HOSTS = ['*']
-SITE_ID = 1
-
-# Application definition
-
-INSTALLED_APPS = [
-    'django.contrib.admin',
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
-    'django.contrib.sessions',
-    'django.contrib.messages',
-    'django.contrib.staticfiles',
-    'django.contrib.sites',
-
-    'oidc_provider',
-    'oidcprovider',
-    'pinax_theme_bootstrap',
-    'account',
-    'bootstrapform',
-
-
-]
-
-MIDDLEWARE = [
-    'django.middleware.security.SecurityMiddleware',
-    'django.contrib.sessions.middleware.SessionMiddleware',
-    'django.middleware.common.CommonMiddleware',
-    'django.middleware.csrf.CsrfViewMiddleware',
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-    'django.contrib.messages.middleware.MessageMiddleware',
-    'django.middleware.clickjacking.XFrameOptionsMiddleware',
-
-    # django-user-accounts
-    'account.middleware.LocaleMiddleware',
-    'account.middleware.TimezoneMiddleware'
-]
-
-ROOT_URLCONF = 'oidcprovider.urls'
-
-TEMPLATES = [
-    {
-        'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        'DIRS': [],
-        'APP_DIRS': True,
-        'OPTIONS': {
-            'context_processors': [
-                'django.template.context_processors.debug',
-                'django.template.context_processors.request',
-                'django.contrib.auth.context_processors.auth',
-                'django.contrib.messages.context_processors.messages',
-                'pinax_theme_bootstrap.context_processors.theme',
-                'account.context_processors.account',
-            ],
-        },
-    },
-]
-
-WSGI_APPLICATION = 'oidcprovider.wsgi.application'
-
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-DATABASES = {
-    'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
-    }
-}
-
-
-# Password validation
-# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
-
-AUTH_PASSWORD_VALIDATORS = [
-    {
-        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
-    },
-]
-
-
-# Internationalization
-# https://docs.djangoproject.com/en/1.11/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-TIME_ZONE = 'UTC'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/1.11/howto/static-files/
-
-STATIC_URL = '/static/'
-
-
-# OIDC provider settings
-LOGIN_URL = '/account/login'
-ACCOUNT_EMAIL_CONFIRMATION_EMAIL = False
-
-
-# Workaround to actually delete the account instead of marking it as inactive
-def _delete_user(obj):
-    obj.user.delete()
-
-
-ACCOUNT_DELETION_MARK_CALLBACK = _delete_user
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html
deleted file mode 100644
index 6daa91684373aadf91bc4e4c9fcbb835e32260be..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{% extends "site_base.html" %}
-
-{% block head_title %}Home{% endblock %}
-
-{% block body %}
-<h1>Welcome to {% if SITE_NAME %}{{ SITE_NAME }}{% else %}testprovider{% endif %}!</h1>
-<div>
-  {% if request.user.is_authenticated %}
-    <p>Current user: {{ user.email }}</p>
-  {% else %}
-    <p>User not logged in</p>
-  {% endif %}
-</div>
-{% endblock body %}
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html
deleted file mode 100644
index 909a80cc317bb3043c437609636d45f44a184112..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{% extends "theme_bootstrap/base.html" %}
-{% load static %}
-
-{% block footer %}
-    <p>Test OIDC provider</p>
-{% endblock %}
-
-{% block styles %}
-  <link rel="stylesheet" href="{% static 'pinax/css/theme.css' %}">
-  <link rel="stylesheet"
-        href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
-        integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
-        crossorigin="anonymous">
-  <link rel="stylesheet"
-        href="https://stackpath.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"
-        integrity="sha384-MI32KR77SgI9QAPUs+6R7leEOwtop70UsjEtFEezfKnMjXWx15NENsZpfDgq8m8S"
-        crossorigin="anonymous">
-{% endblock styles %}
-
-{% block scripts %}
-  <script src="https://code.jquery.com/jquery-2.2.4.min.js"
-          integrity="sha384-rY/jv8mMhqDabXSo+UCggqKtdmBfd3qC2/KvyTDNQ6PcUJXaxK1tMepoQda4g5vB"
-          crossorigin="anonymous"></script>
-  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
-          integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
-          crossorigin="anonymous"></script>
-{% endblock scripts %}
-
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py
deleted file mode 100644
index 3f8296b1167063f2b99f397ea3d166361a41e2a2..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from django.conf.urls import include, url
-from django.contrib import admin
-
-from .views import HomePageView
-
-urlpatterns = [
-    url(r'^openid/', include('oidc_provider.urls', namespace='oidc_provider')),
-    url(r'^account/', include('account.urls')),
-    url(r'^admin/', admin.site.urls),
-    url(r'^$', HomePageView.as_view(), name='home'),
-
-]
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py
deleted file mode 100644
index 14cc50fec47aa54e48618de782f6e235eab07fda..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.views.generic.base import TemplateView
-
-
-class HomePageView(TemplateView):
-
-    template_name = "home.html"
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py
deleted file mode 100644
index a995efc052615dc3c1882ffff6318636e1f3711d..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-WSGI config for oidcprovider project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oidcprovider.settings")
-
-application = get_wsgi_application()
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/requirements.txt b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/requirements.txt
deleted file mode 100644
index 78415f8c8b022fbacb3f6dbe4678483093b76c1d..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testprovider/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-django<3
-django-oidc-provider
-django-user-accounts
-pinax-theme-bootstrap
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run.sh b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run.sh
deleted file mode 100755
index 6c365a5d40df50b7d86136df18a16d4cb67d3358..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-TEST_OIDC_ALGO=${TEST_OIDC_ALGO}
-RUNNER="./bin/run_$TEST_OIDC_ALGO.sh"
-
-exec $RUNNER
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh
deleted file mode 100755
index d2880cfa48ecabdfa4ad011e7d972eb71b365d37..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-export OIDC_RP_CLIENT_ID='1'
-export OIDC_RP_CLIENT_SECRET='bd01adf93cfb'
-python manage.py migrate --noinput
-python manage.py runserver 0.0.0.0:8081
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh
deleted file mode 100755
index 82e27b82659ce09f09899f653a8f8c51735ce816..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-export OIDC_RP_IDP_SIGN_KEY=$(cat provider_rsa.key)
-export OIDC_RP_CLIENT_ID='2'
-export OIDC_RP_CLIENT_SECRET='a6b4dad2f215'
-export OIDC_RP_SIGN_ALGO='RS256'
-python manage.py migrate --noinput
-python manage.py runserver 0.0.0.0:8081
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/manage.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/manage.py
deleted file mode 100755
index b588f3da043208c06dc027303e704d9a2f35b0f5..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/manage.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-import os
-import sys
-
-if __name__ == "__main__":
-    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testrp.settings")
-    try:
-        from django.core.management import execute_from_command_line
-    except ImportError:
-        # The above import may fail for some other reason. Ensure that the
-        # issue is really that Django is missing to avoid masking other
-        # exceptions on Python 2.
-        try:
-            import django
-        except ImportError:
-            raise ImportError(
-                "Couldn't import Django. Are you sure it's installed and "
-                "available on your PYTHONPATH environment variable? Did you "
-                "forget to activate a virtual environment?"
-            )
-        raise
-    execute_from_command_line(sys.argv)
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/provider_rsa.key b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/provider_rsa.key
deleted file mode 100644
index 8d4b4180509d3405354da78ac948c4eda504dc3d..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/provider_rsa.key
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAAgiIdiJG7GSMKTRbnGjWpHp1
-ulJ43/iQjDywWh5MP3in2PK8PVI6ItxIFLV81nWZMymA7hjfP7adOlxKY6rI+fEx
-n8cTimI3W/oX6mHrPXm52uj/we839pxxkeD7cmWgaif9Sujuy5AHUuUM1BTlO55P
-OHkmhWyYMKC2P29qgQIDAQAB
------END PUBLIC KEY-----
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/requirements.txt b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/requirements.txt
deleted file mode 100644
index 4bb815165fb59dae48ce4d0cf1aff7e6ee6c610b..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-django
-djangorestframework
-python-decouple
-mozilla-django-oidc
-six
-splinter
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/__init__.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/settings.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/settings.py
deleted file mode 100644
index e746e99f9d076b29e5a1724eb0317b1b87f8e113..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/settings.py
+++ /dev/null
@@ -1,153 +0,0 @@
-"""
-Django settings for testrp project.
-
-Generated by 'django-admin startproject' using Django 1.11.6.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.11/ref/settings/
-"""
-
-import os
-
-from decouple import config
-
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = '@n!q#(pw!ta3_^*!i7&8m(ev91qdju(5^ijx)a%5+upwv+s_u-'
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
-ALLOWED_HOSTS = ['*']
-
-
-# Application definition
-
-INSTALLED_APPS = [
-    'django.contrib.admin',
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
-    'django.contrib.sessions',
-    'django.contrib.messages',
-    'django.contrib.staticfiles',
-
-    'rest_framework',
-    'mozilla_django_oidc',
-    'testrp'
-]
-
-MIDDLEWARE = [
-    'django.middleware.security.SecurityMiddleware',
-    'django.contrib.sessions.middleware.SessionMiddleware',
-    'django.middleware.common.CommonMiddleware',
-    'django.middleware.csrf.CsrfViewMiddleware',
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-    'django.contrib.messages.middleware.MessageMiddleware',
-    'django.middleware.clickjacking.XFrameOptionsMiddleware',
-]
-
-# Django<1.10 Compatibility
-MIDDLEWARE_CLASSES = MIDDLEWARE
-
-ROOT_URLCONF = 'testrp.urls'
-
-TEMPLATES = [
-    {
-        'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        'DIRS': [],
-        'APP_DIRS': True,
-        'OPTIONS': {
-            'context_processors': [
-                'django.template.context_processors.debug',
-                'django.template.context_processors.request',
-                'django.contrib.auth.context_processors.auth',
-                'django.contrib.messages.context_processors.messages',
-            ],
-        },
-    },
-]
-
-WSGI_APPLICATION = 'testrp.wsgi.application'
-
-
-# Database
-# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
-
-DATABASES = {
-    'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
-    }
-}
-
-
-# Password validation
-# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
-
-AUTH_PASSWORD_VALIDATORS = [
-    {
-        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
-    },
-    {
-        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
-    },
-]
-
-
-# Internationalization
-# https://docs.djangoproject.com/en/1.11/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-TIME_ZONE = 'UTC'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/1.11/howto/static-files/
-
-STATIC_URL = '/static/'
-
-REST_FRAMEWORK = {
-    'DEFAULT_AUTHENTICATION_CLASSES': [
-        'mozilla_django_oidc.contrib.drf.OIDCAuthentication'
-    ]
-}
-
-
-# OIDC SETUP
-AUTHENTICATION_BACKENDS = (
-    'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
-)
-
-OIDC_RP_CLIENT_ID = config('OIDC_RP_CLIENT_ID')
-OIDC_RP_CLIENT_SECRET = config('OIDC_RP_CLIENT_SECRET')
-OIDC_RP_SIGN_ALGO = config('OIDC_RP_SIGN_ALGO', default='HS256')
-OIDC_RP_IDP_SIGN_KEY = config('OIDC_RP_IDP_SIGN_KEY', default=None)
-OIDC_OP_AUTHORIZATION_ENDPOINT = 'http://testprovider:8080/openid/authorize'
-OIDC_OP_TOKEN_ENDPOINT = 'http://testprovider:8080/openid/token'
-OIDC_OP_USER_ENDPOINT = 'http://testprovider:8080/openid/userinfo'
-
-LOGOUT_REDIRECT_URL = '/'
-LOGIN_REDIRECT_URL = '/'
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html
deleted file mode 100644
index 0b07cc8c9ec7d6e92d3bed40928d6d5111d46074..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<html>
-  <body>
-    <div>
-      Welcome to testrp!
-    </div>
-    <div>
-      {% if request.user.is_authenticated %}
-        <p>Current user: {{ user.email }}</p>
-        <div>
-          <form action="/oidc/logout/" method="POST">
-            {% csrf_token %}
-            <input type="submit" value="Logout"/>
-          </form>
-        </div>
-      {% else %}
-        <a href="{% url 'oidc_authentication_init' %}">
-          Login
-        </a>
-      {% endif %}
-    </div>
-  </body>
-</html>
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/urls.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/urls.py
deleted file mode 100644
index beaf5a5920817232dc4e9e3b36fb25c9b48c0c39..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/urls.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.conf.urls import include, url
-
-from .views import HomePageView, TestAPIView
-
-
-urlpatterns = [
-    url(r'^oidc/', include('mozilla_django_oidc.urls')),
-    url(r'^api/$', TestAPIView.as_view(), name='api'),
-    url(r'^$', HomePageView.as_view(), name='home')
-]
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/views.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/views.py
deleted file mode 100644
index 47b860cce32ef0b7be8f307f0ea352cb16ce486c..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/views.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from django.views.generic.base import TemplateView
-from mozilla_django_oidc.utils import is_authenticated
-from rest_framework.response import Response
-from rest_framework.views import APIView
-
-
-class HomePageView(TemplateView):
-
-    template_name = "home.html"
-
-
-class TestAPIView(APIView):
-
-    def get(self, request):
-        return Response({
-            'is_authenticated': is_authenticated(request.user)
-        })
diff --git a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py b/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py
deleted file mode 100644
index ea4648b82c599721ede45f39c98263c3fac19d73..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-WSGI config for testrp project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testrp.settings")
-
-application = get_wsgi_application()
diff --git a/SAS/TMSS/docker/tmss-nginxenv/nginx.conf b/SAS/TMSS/docker/tmss-nginxenv/nginx.conf
deleted file mode 100644
index 263e487dc66c68f0ca1ac2ba5f540ca1a2928173..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/nginx.conf
+++ /dev/null
@@ -1,39 +0,0 @@
-events {}
-http {
-  
-  include  /etc/nginx/mime.types;  
-
-  upstream django {
-    server tmss_test:8000;
-  }
-
-  server {
-    proxy_http_version 1.1;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-
-    proxy_redirect off;
-    proxy_set_header Host $host;
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Host $server_name;
-
-    location / {
-      try_files $uri @proxy_to_app;
-    }
-
-
-    location /static/ {
-      alias /staticfiles/;
-   }
-
-    location @proxy_to_app {
-      proxy_pass http://django;
-    }
-       
-    location /openid/ {
-      proxy_pass http://tmss_test_oidc:8088;
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/SAS/TMSS/docker/tmss-nginxenv/tmss_frontend_Dockerfile b/SAS/TMSS/docker/tmss-nginxenv/tmss_frontend_Dockerfile
deleted file mode 100644
index 496f41036a2186cb1cdc1aee50c93dba54cb5400..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/tmss_frontend_Dockerfile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# This sets up a Docker image that runs the tmss frontend for testing
-#
-FROM centos:7
-
-RUN yum install -y nginx
diff --git a/SAS/TMSS/docker/tmss-nginxenv/tmss_nginx_Dockerfile b/SAS/TMSS/docker/tmss-nginxenv/tmss_nginx_Dockerfile
deleted file mode 100644
index e352793767ac76501e099cf529e48363e0ebde75..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/tmss_nginx_Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# This sets up a Docker image that runs an nginx proxy for tmss fronend testing
-# Both the frontend as well as the API have to be served from the same origin (unless TMSS serves appropriate CORS headers).
-#
-FROM centos:7
-
-RUN yum install -y epel-release
-RUN yum install -y nginx
-
-COPY nginx.conf /nginx.conf
-
-CMD ["nginx", "-c", "/nginx.conf", "-g", "daemon off;"]
-
-EXPOSE 80
-
diff --git a/SAS/TMSS/docker/tmss-nginxenv/tmss_testenv_Dockerfile b/SAS/TMSS/docker/tmss-nginxenv/tmss_testenv_Dockerfile
deleted file mode 100644
index a392bc4eec2324cec518443d97ef9601c9559c81..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-nginxenv/tmss_testenv_Dockerfile
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# This sets up a Docker image that runs tmss for testing
-#
-FROM centos:7
-
-EXPOSE 8000
-
-RUN yum -y groupinstall 'Development Tools' && \
-    yum -y install epel-release readline-devel && \
-    yum -y install cmake log4cplus-devel python3 python3-devel python3-pip nodejs npm java && \
-    yum install -y cmake gcc-c++ make log4cplus log4cplus-devel python3 python3-libs python3-devel boost readline-devel boost-devel binutils-devel boost-python36 boost-python36-devel gettext which openldap-devel npm nodejs git java-11-openjdk && \
-    npm install -g npx && \
-    npm install -g n && \
-    n stable && \
-    npm install -g serve
-
-RUN echo "Installing packages for TMSS..." && \
-yum erase -y postgresql postgresql-server postgresql-devel
-RUN yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
-RUN yum install -y postgresql96 postgresql96-server postgresql96-devel
-
-ENV PATH=$PATH:/usr/pgsql-9.6/bin/
-
-RUN pip3 install django-filter django-auth-ldap coreapi python-ldap-test django-jsonforms django-json-widget "git+git://github.com/nnseva/django-jsoneditor.git" psycopg2-binary ldap3 drf-yasg flex swagger-spec-validator testing.postgresql mozilla_django_oidc
-RUN pip3 install cython kombu lxml requests pygcn xmljson mysql-connector-python python-dateutil django djangorestframework djangorestframework-xml ldap==1.0.2 flask fabric coverage python-qpid-proton PyGreSQL numpy h5py psycopg2 testing.postgresql Flask-Testing scipy Markdown django-filter python-ldap python-ldap-test ldap3 djangorestframework django-jsonforms django-json-widget django-jsoneditor drf-yasg flex swagger-spec-validator django-auth-ldap mozilla-django-oidc jsonschema
-RUN pip3 install gunicorn
-
-USER postgres
-
-RUN echo "Checking out code base" && \
-    whoami && \
-    cd /tmp && \
-    git clone https://git.astron.nl/ro/lofar.git && \
-    cd lofar && \
-    git checkout TMSS-175
-
-USER root
-
-RUN  mkdir /staticfiles; chown -R postgres:postgres /staticfiles
-
-ENV VARIANT gnucxx11_opt
-ENV PACKAGE TMSS
-
-RUN mv /tmp/lofar /lofar && \
-    cd /lofar && \
-    . CMake/gen_LofarPackageList_cmake.sh && \
-    echo "Building $PACKAGE..."  && \
-    mkdir -p build/$VARIANT
-
-RUN cd /lofar/build/$VARIANT && \
-    cmake -DBUILD_PACKAGES=$PACKAGE ../..  && \
-    make  && \
-    make install && \
-    chown -R postgres:postgres .
-
-
-USER postgres
-
-# Hot patches
-RUN echo -e "\n" >> /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/tmss/settings.py
-# Allow Django HTTP access
-RUN echo  -e "ALLOWED_HOSTS=['*']\n" >> /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/tmss/settings.py
-
-RUN echo -e "STATIC_URL = '/static/'\n"  >> /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/tmss/settings.py
-RUN echo -e "STATIC_ROOT = '/staticfiles/'\n" >> /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/tmss/settings.py
-RUN echo -e "STATICFILES_DIRS = ['/lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/frontend/frontend_poc/build/static/']\n" >> /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/tmss/settings.py
-
-
-ENV POSTGRES_PORT=5444
-ENV POSTGRES_DB=test
-ENV POSTGRES_PASSWORD=test
-ENV POSTGRES_USER=test_tmss_user
-ENV POSTGRES_HOST=localhost
-
-RUN echo "Cleaning static file"
-RUN /bin/bash -c 'source /lofar/build/$VARIANT/lofarinit.sh; /usr/bin/python3 /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/manage.py collectstatic --clear'
-
-#RUN echo "Collecting static file"
-#RUN /bin/bash -c 'source /lofar/build/$VARIANT/lofarinit.sh; /usr/bin/python3 /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/manage.py collectstatic --noinput'
-
-
-ENTRYPOINT /bin/bash -c ' source /lofar/build/$VARIANT/lofarinit.sh;\
-        tmss_test_database & \
-        sleep 15 && \
-        cd /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/ && gunicorn --bind 0.0.0.0:8000 tmss.wsgi && \
-        echo "Collecting static file" &&   \
-        source /lofar/build/$VARIANT/lofarinit.sh; /usr/bin/python3 /lofar/build/$VARIANT/installed/lib64/python3.6/site-packages/lofar/sas/tmss/manage.py collectstatic --noinput'
-
diff --git a/SAS/TMSS/docker/tmss-postgres/Dockerfile b/SAS/TMSS/docker/tmss-postgres/Dockerfile
deleted file mode 100644
index 7626c70899231474956bb81d762678156a6f9b5e..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-postgres/Dockerfile
+++ /dev/null
@@ -1,2 +0,0 @@
-FROM library/postgres
-COPY init.sql /docker-entrypoint-initdb.d/
diff --git a/SAS/TMSS/docker/tmss-postgres/init.sql b/SAS/TMSS/docker/tmss-postgres/init.sql
deleted file mode 100644
index 8496c38eea2c2d99b02504c47948cee87c9d5994..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-postgres/init.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-CREATE USER tmss WITH SUPERUSER PASSWORD 'tmss';
-CREATE DATABASE tmss;
-GRANT ALL PRIVILEGES ON DATABASE tmss TO tmss;
diff --git a/SAS/TMSS/docker/tmss-testenv/docker-compose.yml b/SAS/TMSS/docker/tmss-testenv/docker-compose.yml
deleted file mode 100644
index 2aeb413ed581870c6ef1943e7425fc1e1df9bf61..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-testenv/docker-compose.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-version: "2"
-services:
-  tmss_test:
-    build:
-      context: .
-      dockerfile: tmss_testenv_Dockerfile
-    container_name: tmss_test
-    ports:
-      - "8008:8008"
-      - "3003:3003"
-    networks:
-      - "tmss"
-    environment:
-      - OIDC_ENDPOINT_HOST=172.25.0.10
-      - OIDC_RP_CLIENT_ID=1
-  tmss_test_nginx:
-    build:
-      context: .
-      dockerfile: tmss_nginx_Dockerfile
-    container_name: tmss_test_nginx
-    ports:
-      - "5005:5005"
-    networks:
-      - "tmss"
-  tmss_test_oidc:
-    build:
-      context: ../../test/oidc/docker-test-mozilla-django-oidc/
-      dockerfile: dockerfiles/oidc_testprovider
-    container_name: tmss_test_oidc
-    ports:
-      - "8088:8088"
-    networks:
-      tmss:
-        ipv4_address: 172.25.0.10
-networks:
-  tmss:
-    driver: bridge
-    ipam:
-      driver: default
-      config:
-        - subnet: 172.25.0.0/16
-          gateway: 172.25.0.1
diff --git a/SAS/TMSS/docker/tmss-testenv/nginx.conf b/SAS/TMSS/docker/tmss-testenv/nginx.conf
deleted file mode 100644
index 2bf331144da5267e98697b7e033f5d9476d8c4cc..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-testenv/nginx.conf
+++ /dev/null
@@ -1,48 +0,0 @@
-events {}
-http {
-  server {
-
-    listen 5005;
-
-    proxy_http_version 1.1;
-    proxy_set_header  Host  $http_host;
-    proxy_set_header Upgrade $http_upgrade;
-    proxy_set_header Connection "upgrade";
-    proxy_set_header X-Real-IP $remote_addr;
-    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    proxy_set_header X-Forwarded-Proto $scheme;
-    proxy_redirect off;
-
-    location /static/ {
-      try_files $uri $uri/ @api_proxy;
-    }
-
-    location @api_proxy {
-      proxy_pass http://tmss_test:8008$uri;
-      proxy_intercept_errors on;
-	  recursive_error_pages on;
-	  error_page 404 = @frontend_proxy;
-    }
-
-    location @frontend_proxy {
-      proxy_pass http://tmss_test:3003$uri;
-    }
-
-    location /api/ {
-      proxy_pass http://tmss_test:8008;
-    }
-
-    location /frontend/ {
-      proxy_pass http://tmss_test:3003;
-    }
-
-    location /oidc/ {
-      proxy_pass http://tmss_test:8008;
-    }
-
-    location /openid/ {
-      proxy_pass http://tmss_test_oidc:8088;
-    }
-
-  }
-}
\ No newline at end of file
diff --git a/SAS/TMSS/docker/tmss-testenv/tmss_frontend_Dockerfile b/SAS/TMSS/docker/tmss-testenv/tmss_frontend_Dockerfile
deleted file mode 100644
index 496f41036a2186cb1cdc1aee50c93dba54cb5400..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-testenv/tmss_frontend_Dockerfile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# This sets up a Docker image that runs the tmss frontend for testing
-#
-FROM centos:7
-
-RUN yum install -y nginx
diff --git a/SAS/TMSS/docker/tmss-testenv/tmss_nginx_Dockerfile b/SAS/TMSS/docker/tmss-testenv/tmss_nginx_Dockerfile
deleted file mode 100644
index e352793767ac76501e099cf529e48363e0ebde75..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-testenv/tmss_nginx_Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# This sets up a Docker image that runs an nginx proxy for tmss fronend testing
-# Both the frontend as well as the API have to be served from the same origin (unless TMSS serves appropriate CORS headers).
-#
-FROM centos:7
-
-RUN yum install -y epel-release
-RUN yum install -y nginx
-
-COPY nginx.conf /nginx.conf
-
-CMD ["nginx", "-c", "/nginx.conf", "-g", "daemon off;"]
-
-EXPOSE 80
-
diff --git a/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile b/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile
deleted file mode 100644
index 9cae5d88efee529ae430467edaf06152298cd6ef..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# This sets up a Docker image that runs tmss for testing
-#
-FROM centos:7
-
-RUN yum -y groupinstall 'Development Tools' && \
-    yum -y install epel-release && \
-    yum -y install cmake log4cplus-devel python3 python3-devel python3-pip nodejs npm java && \
-    npm install -g npx && \
-    npm install -g n && \
-    n stable && \
-    npm install -g serve
-
-RUN echo "Installing packages for TMSS..." && \
-    yum -y install https://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-7-x86_64/pgdg-centos94-9.4-3.noarch.rpm && \
-    yum -y install postgresql94-devel openldap-devel postgresql94-server which && \
-    pip3 install django-filter django-auth-ldap coreapi python-ldap-test django-jsonforms django-json-widget "git+git://github.com/nnseva/django-jsoneditor.git" psycopg2-binary ldap3 drf-yasg flex swagger-spec-validator testing.postgresql mozilla_django_oidc
-
-ENV PATH=$PATH:/usr/pgsql-9.4/bin/
-
-RUN echo "Checking out code base" && \
-    git clone https://git.astron.nl/ro/lofar.git && \
-    cd lofar && \
-    git checkout TMSS-146 && \
-    . CMake/gen_LofarPackageList_cmake.sh && \
-    PACKAGE=TMSS  && \
-    VARIANT=gnucxx11_opt  && \
-    echo "Building $PACKAGE..."  && \
-    mkdir -p build/$VARIANT  && \
-    cd build/$VARIANT  && \
-    cmake -DBUILD_PACKAGES=$PACKAGE ../..  && \
-    make  && \
-    make install && \
-    chown -R postgres:postgres .
-
-USER postgres
-RUN mkdir -p ~postgres/.lofar/dbcredentials/ && \
-    echo -e '[database:tmss_ldap_test]\n\
-         host=localhost\n\
-         user=tmssldap\n\
-         password=tmssldap\n\
-         type=unknown\n\
-         port=3389\n\
-         database=tmss_ldap_test' > ~postgres/.lofar/dbcredentials/tmss_ldap_test.ini  && \
-    echo -e '[database:tmss]\n\
-         type = postgresql\n\
-         host = localhost\n\
-         database = tmss\n\
-         port = 5432\n\
-         user = tmssdb\n\
-         password = tmssdb\n' > ~postgres/.lofar/dbcredentials/tmss.ini
-
-ENV TMSS_DBCREDENTIALS=tmss
-ENV TMSS_LDAPCREDENTIALS=tmss_ldap_test
-
-ENTRYPOINT /bin/bash -c 'export VARIANT=gnucxx11_opt; \
-           source /lofar/build/$VARIANT/lofarinit.sh; \
-           cat /var/lib/pgsql/.lofar/dbcredentials/tmss.ini; \
-           cat /var/lib/pgsql/.lofar/dbcredentials/tmss_ldap_test.ini; \
-           tmss_testldap & \
-           tmss_testdatabase & \
-           sleep 15 && \
-           tmss & \
-           cd /lofar/build/gnucxx11_opt/installed/share/www && \
-           serve -s . -p 3003'
-
-# It also works to serve the dev server for interactive development as such:
-# cd /lofar/build/gnucxx11_opt/SAS/TMSS/frontend/frontend_poc && \
-# npm start
diff --git a/SAS/TMSS/docker/tmss/dbcreds.ini b/SAS/TMSS/docker/tmss/dbcreds.ini
deleted file mode 100644
index 21fc8fef512365f858587de26b8d0c81b8e37672..0000000000000000000000000000000000000000
--- a/SAS/TMSS/docker/tmss/dbcreds.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[database:tmss]
-host=postgres
-user=tmss
-password=tmss
-database=tmss