Add simulator enhancements. 64/3664/2
authorAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Mon, 11 May 2020 09:49:32 +0000 (12:49 +0300)
committerAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Mon, 11 May 2020 11:11:45 +0000 (14:11 +0300)
Add configurable number of SSH and TLS connections.

Add IPv6 support.

Add K8S deployment support.

Issue-ID: SIM-26
Change-Id: If010ce3cf4e2d4de1d55db1fd29fef83d9d27839
Signed-off-by: Alex Stancu <alexandru.stancu@highstreet-technologies.com>
26 files changed:
ntsimulator/README.md
ntsimulator/deploy/nts-manager/Dockerfile
ntsimulator/deploy/nts-manager/container-tag.yaml
ntsimulator/deploy/nts-manager/docker_stats.sh [new file with mode: 0755]
ntsimulator/deploy/o-ran-sc/o-ran-ru/Dockerfile
ntsimulator/deploy/o-ran-sc/o-ran-ru/container-tag.yaml
ntsimulator/deploy/o-ran-sc/o-ran-ru/stock_config.xml [deleted file]
ntsimulator/deploy/o-ran/ru-fh/Dockerfile
ntsimulator/deploy/o-ran/ru-fh/container-tag.yaml
ntsimulator/deploy/o-ran/ru-fh/stock_config.xml [deleted file]
ntsimulator/deploy/o-ran/ru-fh/supervisord.conf
ntsimulator/deploy/tls/enable_connections.sh [new file with mode: 0755]
ntsimulator/deploy/tls/enable_tls.sh
ntsimulator/deploy/tls/set_NTS_IP.sh [new file with mode: 0755]
ntsimulator/deploy/x-ran/Dockerfile
ntsimulator/deploy/x-ran/container-tag.yaml
ntsimulator/deploy/x-ran/stock_config.xml [deleted file]
ntsimulator/inc/utils/utils.h
ntsimulator/src/ntsimulator-manager/ntsimulator-manager.c
ntsimulator/src/ntsimulator-manager/simulator-operations.c
ntsimulator/src/ntsimulator-manager/simulator-operations.h
ntsimulator/src/o-ran-notifications/o-ran-notifications.c
ntsimulator/src/utils/utils.c
ntsimulator/src/ves-messages/heartbeat.c
ntsimulator/yang/nts-manager/network-topology-simulator.xml
ntsimulator/yang/nts-manager/network-topology-simulator.yang

index a1c8d01..5ae5319 100644 (file)
@@ -29,8 +29,10 @@ module: network-topology-simulator
   +--rw simulator-config
   |  +--rw simulated-devices?      uint32
   |  +--rw mounted-devices?        uint32
+  |  +--rw ssh-connections?        uint32
+  |  +--rw tls-connections?        uint32
   |  +--rw notification-config
-  |  |  +--rw fault-notification-delay-period?   uint32
+  |  |  +--rw fault-notification-delay-period*   uint32
   |  |  +--rw ves-heartbeat-period?              uint32
   |  |  +--rw is-netconf-available?              boolean
   |  |  +--rw is-ves-available?                  boolean
@@ -54,12 +56,38 @@ module: network-topology-simulator
      |  +--ro base-netconf-port?           uint32
      |  +--ro cpu-usage?                   percent
      |  +--ro mem-usage?                   uint32
+     +--ro notification-count
+     |  +--ro total-ves-notifications
+     |  |  +--ro normal?     uint32
+     |  |  +--ro warning?    uint32
+     |  |  +--ro minor?      uint32
+     |  |  +--ro major?      uint32
+     |  |  +--ro critical?   uint32
+     |  +--ro total-netconf-notifications
+     |     +--ro normal?     uint32
+     |     +--ro warning?    uint32
+     |     +--ro minor?      uint32
+     |     +--ro major?      uint32
+     |     +--ro critical?   uint32
      +--ro simulated-devices-list* [uuid]
-        +--ro uuid                 string
-        +--ro device-ip?           string
-        +--ro device-port*         uint32
-        +--ro is-mounted?          boolean
-        +--ro operational-state?   operational-state-type
+        +--ro uuid                  string
+        +--ro device-ip?            string
+        +--ro device-port*          uint32
+        +--ro is-mounted?           boolean
+        +--ro operational-state?    operational-state-type
+        +--ro notification-count
+           +--ro ves-notifications
+           |  +--ro normal?     uint32
+           |  +--ro warning?    uint32
+           |  +--ro minor?      uint32
+           |  +--ro major?      uint32
+           |  +--ro critical?   uint32
+           +--ro netconf-notifications
+              +--ro normal?     uint32
+              +--ro warning?    uint32
+              +--ro minor?      uint32
+              +--ro major?      uint32
+              +--ro critical?   uint32
 
   rpcs:
     +---x restart-simulation
@@ -71,9 +99,11 @@ module: network-topology-simulator
 ##### Configuration
 
 * **simulated-devices** - represents the number of simulated devices. The default value is 0, meaning that when the NTS is started, there are no simulated devices. When this value is increased to **n**, the NTS Manager starts docker containers in order to reach **n** simulated devices. If the value is decreased to **k**, the NTS Manager will remove docker containers, until the number of simulated devices reaches **k**;
-* **mounted-devices** - represents the number of devices to be mounted to an ODL based SDN Controller. The same phylosophy as in the case of the previous leaf applies. If this number is increased, the number of ODL mountpoints increases. Else, the simulated devices are being unmounted from ODL. The number of mounted devices cannot exceed the number of simulated devices. The details about the ODL controller where to mount/unmount are given by the **controller-details** container; **Please note that this cannot be set to a value > 0 if the *ves-registration* leaf is set to 'True'**; For each simulated device, 10 NETCONF endpoints will be mounted (7 SSH + 3 TLS). See **NETCONF Endpoints** section for more details.
+* **mounted-devices** - represents the number of devices to be mounted to an ODL based SDN Controller. The same phylosophy as in the case of the previous leaf applies. If this number is increased, the number of ODL mountpoints increases. Else, the simulated devices are being unmounted from ODL. The number of mounted devices cannot exceed the number of simulated devices. The details about the ODL controller where to mount/unmount are given by the **controller-details** container; **Please note that this cannot be set to a value > 0 if the *ves-registration* leaf is set to 'True'**; For each simulated device, a number of NETCONF endpoints will be mounted, according to the **ssh-connections** and **tls-connections** leafs. See **NETCONF Endpoints** section for more details;
+* **ssh-connections** - represents the number of SSH endpoints to be exposed by each of the simulated devices. **Please note that the total number of SSH and TLS connections cannot exceed 100.** The default value is 1. **The value can only be changed when simulated-devices is 0**.
+* **tls-connectioons** - represents the number of TLS endpoints to be exposed by each of the simulated devices. **Please note that the total number of SSH and TLS connections cannot exceed 100.** The default value is 0. **The value can only be changed when simulated-devices is 0**.
 *  **notification-config** - this container groups the configuration about fault notification generation of each simulated device;
-* **fault-notification-delay-period** - the amount of seconds between two generated fault notifications. For example, if this has a value of *10*, each simulated device will generate a **random** fault notification every *10* seconds;
+* **fault-notification-delay-period** - the amount of seconds between two generated fault notifications. For example, if this has a value of *10*, each simulated device will generate a **random** fault notification every *10* seconds; **when this is set to 0, it will reset the notification counters for the VES and NETCONF notifications, which are exposed in the simulator-status**;
 * **ves-heartbeat-period** - the amount of seconds between VES heartbeat messages that can be generated by each simulated device. The details about the VES connection endpoint are given in the **ves-endpoint-details** container;
 * **is-netconf-available** - if set to 'True', NETCONF notifications will be sent when a random fault notification is generated, The NETCONF notification that is being sent is currently *o-ran-fm:alarm-notif*; if set to 'False', NETCONF notifications are not being sent out;
 * **is-ves-available** - if set to 'True', VES *faultNotification* messages will be sent when a random fault notification is generated; if set to 'False', VES *faultNotification* messages are not generated;
@@ -93,7 +123,7 @@ module: network-topology-simulator
 * **ves-endpoint-username** - the username to be used when authenticating to the VES endpoint;
 * **ves-endpoint-password** - the password to be used when authenticating to the VES endpoint;
 * **ves-endpoint-certificate** - the certificate to be used when authenticating to the VES endpoint;
-* **ves-registration** - if this is set to 'True' **when simulated devices are starting**, each simulated device will send out *pnfRegistration* VES messages to the configured VES endpoint; if this is set to 'False', *pnfRegistration* VES messages will not be sent out. **Please note that this cannot be set to 'True' is simulated devices are already mounted to ODL based SDN controller (mounted-devices leaf > 0)**; For each simulated device, 10 pnfRegistration VES messages will be sent out (7 SSH + 3 TLS). See **NETCONF Endpoints** section for more details.
+* **ves-registration** - if this is set to 'True' **when simulated devices are starting**, each simulated device will send out *pnfRegistration* VES messages to the configured VES endpoint; if this is set to 'False', *pnfRegistration* VES messages will not be sent out. **Please note that this cannot be set to 'True' is simulated devices are already mounted to ODL based SDN controller (mounted-devices leaf > 0)**; For each simulated device, **ssh-connections + tls-connections** pnfRegistration VES messages will be sent out. See **NETCONF Endpoints** section for more details.
 
 ##### Status
 
@@ -103,12 +133,18 @@ module: network-topology-simulator
 * **base-netconf-port** - the port that was used as a base when craeting simulated devices;
 * **cpu-usage** - the percentage of the CPU used currently by the simulation framework;
 * **mem-usage** - the amount of RAM used (in MB) currently by the simulation framework;
+* **notification-count** - this container groups the details about the total number of notifications that were generated by the simulated devices;
+* **total-ves-notifications** - this container groups the details about the total number of VES notifications that were generated by the simulated devices, grouped by severity;
+* **total-netcnof-notifications** - this container groups the details about the total number of NETCONF notifications that were generated by the simulated devices - grouped by severity;
 * **simulated-devices-list** - this list contains the details about each simulated devices that is currently running;
 * **uuid** - the Universally Unique ID of the simulated device;
 * **device-ip** - the IP address of the simulated device;
 * **device-port** - the port of the simulated device, where the NETCONF connection is exposed;
 * **is-mounted** - boolean to show whether the device is currently mounted to an ODL based SDN controller;
-* **operational-state** - the operational state of the current simulated device; it can be either *not-specified*, *created*, *running* or *exited*.
+* **operational-state** - the operational state of the current simulated device; it can be either *not-specified*, *created*, *running* or *exited*;
+* **notification-count** - this container groups the details about the number of notifications that were generated by this particular simulated device;
+* **ves-notifications** - this container groups the details about the number of VES notifications that were generated by this simulated device, grouped by severity;
+* **netconf-notifications** - this container groups the details about the number of NETCONF notifications that were generated by this simulated device - grouped by severity.
 
 ##### RPCs
 
@@ -121,19 +157,29 @@ Each simulated device is represented as a docker container, inside which the NET
 
 #### NETCONF Endpoints
 
-Each simulated device exposes **10 NETCONF endpoints**, on 10 consecutive ports. The first simulated device uses the 10 ports starting from the **NETCONF_BASE** environment variable used when starting the NTST Manager, while the nextt one uses the next 10 ports and so on and so forth. E.g. if the **NETCONF_BASE=50000** the first simulated device will expose ports from *50000* to *50009*, the second simulated device will expose ports from *50010* to *50019* etc.
+Each simulated device exposes a number of NETCONF endpoints which represented by the sum of the **ssh-connections** and **tls-connections** leafs, on consecutive ports. The first simulated device uses the ports starting from the **NETCONF_BASE** environment variable used when starting the NTS Manager, while the next one uses the next ports and so on and so forth. E.g. if the **NETCONF_BASE=50000** and **ssh-connections=5** and **tls-connections=3**, the first simulated device will expose ports from *50000* to *50007*, the second simulated device will expose ports from *5008* to *50015* etc.
 
-The first 7 connections exposed by a simulated device are **SSH** based. A NETCONF client can connect to the exposed endpoint using one of the SSH ports (e.g. 50000 to 50006) and the **username/password**: *netconf/netconf*.
+The first **ssh-connections** ports exposed by a simulated device are **SSH** based. A NETCONF client can connect to the exposed endpoint using one of the SSH ports (e.g. 50000 to 50007, considering the previous example) and the **username/password**: *netconf/netconf*.
 
-The last 3 connections exposed by a simulated device are **TLS** based. A NETCONF client can connect to the exposed endpoint using one of the TLS ports (e.g. 50007 to 50009), using a valid certificate and the **username**: *netconf*. 
+The last **tls-connections** ports exposed by a simulated device are **TLS** based. A NETCONF client can connect to the exposed endpoint using one of the TLS ports (e.g. 50006 to 50008, considering the previous example), using a valid certificate and the **username**: *netconf*. 
 
 ## Usage
 
 ### Building the images
 
-The `docker-build-manager.sh` script can be used to built the docker image associated with the NTS Manager. This will create a docker image named *ntsim_manager*, which will be used to start the simulation framework. Inside the docker image, port 830 will wait for connections for the NETCONF/YANG management interface.
+The `docker-build-nts-manager.sh` script can be used to built the docker image associated with the NTS Manager. This will create a docker image named *ntsim_manager_light*, which will be used to start the simulation framework. Inside the docker image, port 830 will wait for connections for the NETCONF/YANG management interface.
 
-The `docker-build-model.sh` script can be used to build the docker image associated with a simulated device. Currently, this will create a docker image named *ntsim_oran*, which will be used by the manager to start the docker containers for each simulated device.
+The `docker-build-onf-core-model-1-2.sh` script can be used to build the docker image associated with a simulated device, exposing the ONF CoreModel version 1.2.
+
+The `docker-build-onf-core-model-1-4.sh` script can be used to build the docker image associated with a simulated device, exposing the ONF CoreModel version 1.4.
+
+The `docker-build-openroadm.sh` script can be used to build the docker image associated with a simulated device, exposing the OpenROADM models.
+
+The `docker-build-o-ran-device.sh` script can be used to build the docker image associated with a simulated device, exposing the O-RAN models.
+
+The `docker-build-o-ran-sc-o-ran-ru.sh` script can be used to build the docker image associated with a simulated device, exposing the O-RAN-SC models.
+
+The `docker-build-x-ran-device.sh*` script can be used to build the docker image associated with a simulated device, exposing the X-RAN models.
 
 ### Starting the NTS Manager
 
@@ -146,10 +192,10 @@ services:
     image: "ntsim_manager:latest"
     container_name: NTS_Manager
     ports:
-     - "172.17.0.1:8300:830"
+     - "8300:830"
     volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
-     - "/path/to/simulator/folder/ntsimulator/scripts:/opt/dev/scripts"
+     - "/var/tmp/NTS_Manager:/opt/dev/scripts"
      - "/usr/bin/docker:/usr/bin/docker"
     labels:
       "NTS-manager": ""
@@ -158,17 +204,26 @@ services:
       NETCONF_BASE: 50000
       DOCKER_ENGINE_VERSION: "1.40"
       MODELS_IMAGE: "ntsim_oran"
+      VesHeartbeatPeriod: 0
+      IsVesAvailable: "true"
+      IsNetconfAvailable: "true"
+      VesRegistration: "false"
+      VesEndpointPort: 8080
+      VesEndpointIp: "172.17.0.1"
+      SshConnections: 1
+      TlsConnections: 0
+      K8S_DEPLOYMENT: "false"
 ```
 
 
 * Port mapping:
-    * `"172.17.0.1:8300:830"` - this maps the *830* port from inside the docker container of the NTS Manager to the port *8300* from the host, and binds it to the docker IP address *172.17.0.1*:
+    * `"8300:830"` - this maps the *830* port from inside the docker container of the NTS Manager to the port *8300* from the host, and binds it to any IP address on the host:
     
 * Volumes - these map 3 important things:
     * the docker socket from the host is mapped inside the docker container:
         `/var/run/docker.sock:/var/run/docker.sock` - **please do not modify the path inside the container!**;
-    * the **scripts** folder from the cloned repository needs to be mapped inside the container:
-        `/path/to/simulator/folder/ntsimulator/scripts:/opt/dev/scripts` - **please do not modify the path inside the container!**;
+    * any folder from the host can be mapped to inside the docker container into othe **/opt/dev/scripts** folder:
+        `/var/tmp/NTS_Manager:/opt/dev/scripts` - **please do not modify the path inside the container!**;
     * the path to the docker executable needs to be mapped inside the container:
         `/usr/bin/docker:/usr/bin/docker` - **please do not modify the path inside the container!**;
         
@@ -178,6 +233,15 @@ services:
     * **NETCONF_BASE** - this is the starting port used to expose NETCONF endpoints. Starting from this, each device will use 10 consecutive ports for its endpoints;
     * **DOCKER_ENGINE_VERSION** - this is the version of the *docker engine* installed currently on the host. This can be verified using `docker version` command in the host, and looking to the `API version:      #.##` variable from the Server details.
     * **MODELS_IMAGE** - this represents the name of the docker image that represents the simulated device. The NTS Manager will start containers using this image, when starting simulated devices.
+    * **VesHeartbeatPeriod** - this can change the default value of the **ves-heartbeat-period** leaf used by the NTS Manager.
+    * **IsVesAvailable** - this can change the default value of the **is-ves-available** leaf used by the NTS Manager.
+    * **IsNetconfAvailable** - this can change the default value of the **is-netconf-available** leaf used by the NTS Manager.
+    * **VesRegistration** - this can change the default value of the **ves-registration** leaf used by the NTS Manager.
+    * **VesEndpointPort** - this can change the default value of the **ves-endpoint-port** leaf used by the NTS Manager.
+    * **VesEndpointIp** - this can change the default value of the **ves-endpoint-ip** leaf used by the NTS Manager.
+    * **SshConnections** - this can change the default value of the **ssh-connections** leaf used by the NTS Manager.
+    * **TlsConnections** - this can change the default value of the **tls-connections** leaf used by the NTS Manager.
+    * **K8S_DEPLOYMENT** - this value can be set to `true` when the user wants to the NTS Framework in a Kubernetes deployment. The default is `false`.
     
 After modifying the `docker-compose.yml` file with values specific to your host, the NTS Manager can be started by running the command `docker-compose up` from the **scripts** folder.
 
@@ -186,10 +250,10 @@ After the NTS Manager is started, it will wait for connections on its NETCONF/YA
 Example of `docker ps` command result, after the NTS Manager was started:
 
 ```
-7ff723b7f794        ntsim_manager:latest   "sh -c '/usr/bin/sup…"   5 days ago          Up 5 days           172.17.0.1:8300->830/tcp       NTS_Manager
+7ff723b7f794        ntsim_manager:latest   "sh -c '/usr/bin/sup…"   5 days ago          Up 5 days           0.0.0.0:8300->830/tcp       NTS_Manager
 ```
 
-### Using the NTST Manager
+### Using the NTS Manager
 
 When the NTS Manager is started, its default configuration looks like this:
 
@@ -197,6 +261,8 @@ When the NTS Manager is started, its default configuration looks like this:
 <simulator-config xmlns="urn:onf:params:xml:ns:yang:network-topology-simulator">
        <simulated-devices>0</simulated-devices>
        <mounted-devices>0</mounted-devices>
+    <ssh-connections>1</ssh-connections>
+    <tls-connections>0</tls-connections>
        <notification-config>
                <fault-notification-delay-period>0</fault-notification-delay-period>
                <ves-heartbeat-period>0</ves-heartbeat-period>
@@ -222,7 +288,27 @@ This configuration can be altered by connecting to the NTS Manager with a NETCON
 
 ### Starting a simulated device
 
-Example of starting **one** simulated device:
+Example RPC for starting **one** simulated device:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="">
+  <edit-config>
+    <target>
+      <running/>
+    </target>
+    <config>
+      <simulator-config xmlns="urn:onf:params:xml:ns:yang:network-topology-simulator">
+        <simulated-devices>1</simulated-devices>
+        <!--We need to delete the ssh-connections and tls-connections leafs when configuring simulated-devices > 0 -->
+        <ssh-connections xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xc:operation="delete"/>
+        <tls-connections xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xc:operation="delete"/>
+      </simulator-config>
+    </config>
+  </edit-config>
+</rpc>
+```
+
 
 If the leaf `<simulated-devices>1</simulated-devices>` will be set to a value of **1**, the NTS Manager will start a new docker container. We can verify that this was successfull by running the `docker ps` command. The results will look like this:
 
@@ -230,8 +316,6 @@ If the leaf `<simulated-devices>1</simulated-devices>` will be set to a value of
 c18eb7a362f5        ntsim_oran             "sh -c '/usr/bin/sup…"   4 days ago          Up 4 days           172.17.0.1:50000->830/tcp, 172.17.0.1:50001->831/tcp, 172.17.0.1:50002->832/tcp, 172.17.0.1:50003->833/tcp, 172.17.0.1:50004->834/tcp, 172.17.0.1:50005->835/tcp, 172.17.0.1:50006->836/tcp, 172.17.0.1:50007->837/tcp, 172.17.0.1:50008->838/tcp, 172.17.0.1:50009->839/tcp   reverent_bhabha
 ```
 
-We can see that the simulated device has 10 NETCONF Endpoints listening for connections. The first 7 (50000 to 50006) are SSH connections, while the last 3 (50007 to 50009) are TLS connections.
-
 
 ## Troubleshooting
 
@@ -242,7 +326,7 @@ If, after setting the leaf `<simulated-devices>1</simulated-devices>` to a value
 Example of a result of such a command:
 
 ```
-ntsim_oran       latest           57b065de4458     4 days ago     785MB
+ntsim_oran_light       latest           57b065de4458     4 days ago     186MB
 ```
 
-This means that `MODELS_IMAGE: "ntsim_oran:latest"` can be used as an environment variable when starting the NTS Manager.
\ No newline at end of file
+This means that `MODELS_IMAGE: "ntsim_oran_light:latest"` can be used as an environment variable when starting the NTS Manager.
\ No newline at end of file
index bff4bd8..2396a5d 100644 (file)
@@ -2,12 +2,6 @@ FROM ubuntu:18.04 AS builder
 
 LABEL maintainer="alexandru.stancu@highstreet-technologies.com"
 
-ENV NETCONF_BASE=40000
-ENV NTS_IP="127.0.0.1"
-ENV SCRIPTS_DIR=/opt/dev/scripts
-ENV DOCKER_ENGINE_VERSION="1.40"
-ENV MODELS_IMAGE="ntsim_oran"
-
 RUN \
       apt-get update && apt-get install -y \
       # general tools
@@ -43,12 +37,15 @@ RUN \
       echo "netconf:netconf" | chpasswd
 
 # generate ssh keys for netconf user
+USER netconf
 RUN \
       mkdir -p /home/netconf/.ssh && \
       ssh-keygen -A && \
       ssh-keygen -t dsa -P '' -f /home/netconf/.ssh/id_dsa && \
-      cat /home/netconf/.ssh/id_dsa.pub > /home/netconf/.ssh/authorized_keys && \
+      cat /home/netconf/.ssh/id_dsa.pub > /home/netconf/.ssh/authorized_keys
 #echo "Host *\n    StrictHostKeyChecking accept-new" >> /home/netconf/.ssh/config
+USER root
+RUN \
       echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config && \
       mkdir -p /root/.ssh && \
       cat /home/netconf/.ssh/id_dsa.pub > /root/.ssh/authorized_keys
@@ -136,20 +133,35 @@ ENV NTS_IP="127.0.0.1"
 ENV SCRIPTS_DIR=/opt/dev/scripts
 ENV DOCKER_ENGINE_VERSION="1.40"
 ENV MODELS_IMAGE="ntsim_oran"
+ENV VesHeartbeatPeriod=0
+ENV IsVesAvailable=true
+ENV IsNetconfAvailable=true
+ENV VesRegistration=false
+ENV VesEndpointPort=8080
+ENV VesEndpointIp="172.17.0.1"
+ENV SshConnections=1
+ENV TlsConnections=0
+ENV K8S_DEPLOYMENT=false
+ENV CONTAINER_NAME="ntsim"
 
 RUN \
-      apt-get update && apt-get install -y supervisor
+      apt-get update && apt-get install -y supervisor bc
 
 # add netconf user
 RUN \
       adduser --system netconf && \
       echo "netconf:netconf" | chpasswd
 
+USER netconf
 # generate ssh keys for netconf user
 RUN \
       mkdir -p /home/netconf/.ssh
 
 COPY --from=builder /home/netconf/.ssh /home/netconf/.ssh
+
+USER root
+COPY --from=builder /etc/ssh /etc/ssh
+COPY --from=builder /root/.ssh /root/.ssh
 COPY --from=builder /usr/local/lib /usr/local/lib
 COPY --from=builder /usr/local/bin /usr/local/bin
 COPY --from=builder /usr/local/include /usr/local/include
@@ -202,6 +214,8 @@ COPY --from=builder /usr/local/share/libnetconf2 /usr/local/share/libnetconf2
 RUN ldconfig
 
 COPY ./deploy/nts-manager/supervisord.conf /etc/supervisord.conf
+
+COPY ./deploy/nts-manager/docker_stats.sh /opt/dev/docker_stats.sh
          
 ARG BUILD_DATE
 LABEL build-date=$BUILD_DATE
diff --git a/ntsimulator/deploy/nts-manager/docker_stats.sh b/ntsimulator/deploy/nts-manager/docker_stats.sh
new file mode 100755 (executable)
index 0000000..317d3ce
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/bash
+################################################################################
+#
+# Copyright 2020 highstreet technologies GmbH and others
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+# This script is used to complete the output of the docker stats command.
+# The docker stats command does not compute the total amount of resources (RAM or CPU)
+
+# Get the output of the docker stat command. Will be displayed at the end
+# Without modifying the special variable IFS the ouput of the docker stats command won't have
+
+CPU_CORES=`nproc`
+# the new lines thus resulting in a failure when using awk to process each line
+IFS=;
+mapfile -t DOCKER_PS_RESULT < <(/usr/bin/docker ps --all --format "{{.ID}}" --filter "label=NTS_Manager=$1")
+
+CONTAINERS=""
+
+if [ ${#DOCKER_PS_RESULT[@]} -gt 0 ]
+then
+
+       for container in "${DOCKER_PS_RESULT[@]}"
+       do
+               CONTAINERS="$CONTAINERS $container"
+       done
+fi
+
+if [ -z "$CONTAINERS" ]
+then
+       CPU_SCALED=0
+       SUM_RAM=0
+else
+       DOCKER_STATS_COMMAND="/usr/bin/docker stats --no-stream --format \"table {{.CPUPerc}}\t{{.MemUsage}}\" ${CONTAINERS}"
+       DOCKER_STATS_COMMAND_RESULT=$(eval "$DOCKER_STATS_COMMAND")
+
+       SUM_CPU=`echo $DOCKER_STATS_COMMAND_RESULT | tail -n +2 | sed "s/%//g" | awk '{s+=$1} END {print s}'`
+       SUM_RAM=`echo $DOCKER_STATS_COMMAND_RESULT | tail -n +2 | sed "s/%//g" | awk '{s+=$2} END {print s}'`
+
+       CPU_SCALED=$(echo "scale=2; $SUM_CPU/$CPU_CORES" | bc)
+fi
+
+# Output the result
+echo -e "CPU=${CPU_SCALED}%;RAM=${SUM_RAM}MiB"
\ No newline at end of file
index e70a0a6..ff4c008 100644 (file)
@@ -107,8 +107,6 @@ RUN \
       make install && \
       ldconfig
 
-# overwrite number of endpoints exposed by the NETCONF server
-COPY ./deploy/o-ran-sc/o-ran-ru/stock_config.xml /opt/dev/Netopeer2/server/stock_config.xml
 # netopeer2
 RUN \
       cd /opt/dev/Netopeer2/server && mkdir build && cd build && \
@@ -205,7 +203,8 @@ RUN ldconfig
 
 WORKDIR /tmp
 RUN apt-get install -yqq wget \
-    openssh-client
+    openssh-client \
+    jq
 
 RUN mkdir py_install && cd py_install && \
     wget https://files.pythonhosted.org/packages/b9/9a/3e9da40ea28b8210dd6504d3fe9fe7e013b62bf45902b458d1cdc3c34ed9/ipaddress-1.0.23.tar.gz && \
@@ -237,6 +236,6 @@ ARG BUILD_DATE
 LABEL build-date=$BUILD_DATE
          
 ENV EDITOR vim
-EXPOSE 830-839
+EXPOSE 830-929
 
 CMD ["sh", "-c", "/usr/bin/supervisord -c /etc/supervisord.conf"]
diff --git a/ntsimulator/deploy/o-ran-sc/o-ran-ru/stock_config.xml b/ntsimulator/deploy/o-ran-sc/o-ran-ru/stock_config.xml
deleted file mode 100644 (file)
index 014c840..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
-  <listen>
-    <endpoint>
-      <name>MNG0</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>830</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG1</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>831</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG2</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>832</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG3</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>833</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG4</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>834</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG5</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>835</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG6</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>836</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-  </listen>
-</netconf-server>
index a969262..e711258 100644 (file)
@@ -107,8 +107,6 @@ RUN \
       make install && \
       ldconfig
 
-# overwrite number of endpoints exposed by the NETCONF server
-COPY ./deploy/o-ran/ru-fh/stock_config.xml /opt/dev/Netopeer2/server/stock_config.xml
 # netopeer2
 RUN \
       cd /opt/dev/Netopeer2/server && mkdir build && cd build && \
@@ -205,7 +203,8 @@ RUN ldconfig
 
 WORKDIR /tmp
 RUN apt-get install -yqq wget \
-    openssh-client
+    openssh-client \
+    jq
 
 RUN mkdir py_install && cd py_install && \
     wget https://files.pythonhosted.org/packages/b9/9a/3e9da40ea28b8210dd6504d3fe9fe7e013b62bf45902b458d1cdc3c34ed9/ipaddress-1.0.23.tar.gz && \
@@ -246,6 +245,6 @@ ARG BUILD_DATE
 LABEL build-date=$BUILD_DATE
          
 ENV EDITOR vim
-EXPOSE 830-839
+EXPOSE 830-929
 
 CMD ["sh", "-c", "/usr/bin/supervisord -c /etc/supervisord.conf"]
diff --git a/ntsimulator/deploy/o-ran/ru-fh/stock_config.xml b/ntsimulator/deploy/o-ran/ru-fh/stock_config.xml
deleted file mode 100644 (file)
index 014c840..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
-  <listen>
-    <endpoint>
-      <name>MNG0</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>830</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG1</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>831</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG2</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>832</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG3</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>833</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG4</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>834</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG5</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>835</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG6</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>836</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-  </listen>
-</netconf-server>
index 886a5f9..e9f3e2f 100644 (file)
@@ -37,6 +37,14 @@ autorestart=false
 redirect_stderr=false
 priority=5
 
+[program:set-nts-ip-script]
+directory=/home/netconf/.ssh
+command=/home/netconf/.ssh/set_NTS_IP.sh
+startsecs=0
+autorestart=false
+redirect_stderr=false
+priority=5
+
 [program:sysrepo-config-load]
 directory=/opt/dev/yang
 command=/opt/dev/yang/sysrepo-configuration-load.sh
diff --git a/ntsimulator/deploy/tls/enable_connections.sh b/ntsimulator/deploy/tls/enable_connections.sh
new file mode 100755 (executable)
index 0000000..ff51e27
--- /dev/null
@@ -0,0 +1,64 @@
+#! /bin/bash
+################################################################################
+#
+# Copyright 2020 highstreet technologies GmbH and others
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+
+int_re='^[0-9]+$'
+
+ssh_conn=`jq '.["ssh-connections"]' /opt/dev/scripts/configuration.json`
+tls_conn=`jq '.["tls-connections"]' /opt/dev/scripts/configuration.json`
+
+echo "Enabling $ssh_conn SSH connections and $tls_conn TLS connections in device..."
+
+# if [ "$#" -ne 2 ]; then
+#   echo "Usage: $0 NUM_SSH_CONNECTIONS NUM_TLS_CONNECTIONS" >&2
+#   exit 1
+# fi
+
+if ! [[ $ssh_conn =~ $int_re ]] ; then
+   echo "error: Argument '$ssh_conn' is not a number" >&2
+   exit 1
+fi
+
+if ! [[ $tls_conn =~ $int_re ]] ; then
+   echo "error: Argument '$tls_conn' is not a number" >&2
+   exit 1
+fi
+
+netconf_port=830
+
+echo '<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server"><listen>' > connections.xml
+
+for (( ssh_counter=0; ssh_counter<$ssh_conn; ssh_counter++ ))
+do
+  echo "<endpoint><name>MNG$ssh_counter</name><ssh><address>::</address><port>$netconf_port</port><host-keys><host-key><name>imported SSH key</name><public-key>ssh_host_rsa_key</public-key></host-key></host-keys></ssh></endpoint>" >> connections.xml
+  ((netconf_port++))
+done
+
+for (( tls_counter=0; tls_counter<$tls_conn; tls_counter++ ))
+do
+  echo "<endpoint><name>MNGTLS$tls_counter</name><tls><address>::</address><port>$netconf_port</port><certificates><certificate><name>melacon_server_cert</name></certificate></certificates><client-auth><trusted-ca-certs>trusted_ca_list</trusted-ca-certs><cert-maps><cert-to-name><id>1</id><fingerprint>02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3</fingerprint><map-type xmlns:x509c2n=\"urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name\">x509c2n:specified</map-type><name>netconf</name></cert-to-name></cert-maps></client-auth></tls></endpoint>" >> connections.xml
+  ((netconf_port++))
+done
+
+echo '</listen></netconf-server>' >> connections.xml
+
+sysrepocfg --import=connections.xml --format=xml ietf-netconf-server
+rm connections.xml
+
+echo 'Done'
+exit 0
\ No newline at end of file
index 97b539d..11fbb3d 100755 (executable)
@@ -50,14 +50,8 @@ echo '<certificate>'"$CA_CERT"'</certificate></trusted-certificate></trusted-cer
 sysrepocfg --merge=load_server_certs.xml --format=xml ietf-keystore
 rm load_server_certs.xml
 
-echo '<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server"><listen>' >> tls_endpoints.xml
-echo '<endpoint><name>MNG_TLS_1</name><tls><address>0.0.0.0</address><port>837</port><certificates><certificate><name>melacon_server_cert</name></certificate></certificates><client-auth><trusted-ca-certs>trusted_ca_list</trusted-ca-certs><cert-maps><cert-to-name><id>1</id><fingerprint>02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3</fingerprint><map-type xmlns:x509c2n="urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name">x509c2n:specified</map-type><name>netconf</name></cert-to-name></cert-maps></client-auth></tls></endpoint>' >> tls_endpoints.xml
-echo '<endpoint><name>MNG_TLS_2</name><tls><address>0.0.0.0</address><port>838</port><certificates><certificate><name>melacon_server_cert</name></certificate></certificates><client-auth><trusted-ca-certs>trusted_ca_list</trusted-ca-certs><cert-maps><cert-to-name><id>1</id><fingerprint>02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3</fingerprint><map-type xmlns:x509c2n="urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name">x509c2n:specified</map-type><name>netconf</name></cert-to-name></cert-maps></client-auth></tls></endpoint>' >> tls_endpoints.xml
-echo '<endpoint><name>MNG_TLS_3</name><tls><address>0.0.0.0</address><port>839</port><certificates><certificate><name>melacon_server_cert</name></certificate></certificates><client-auth><trusted-ca-certs>trusted_ca_list</trusted-ca-certs><cert-maps><cert-to-name><id>1</id><fingerprint>02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3</fingerprint><map-type xmlns:x509c2n="urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name">x509c2n:specified</map-type><name>netconf</name></cert-to-name></cert-maps></client-auth></tls></endpoint>' >> tls_endpoints.xml
-echo '</listen></netconf-server>' >> tls_endpoints.xml
-
-sysrepocfg --merge=tls_endpoints.xml --format=xml ietf-netconf-server
-rm tls_endpoints.xml
+# enable the SSH and TLS connections, according to the configuration file
+./enable_connections.sh
 
 echo 'Done'
 exit 0
\ No newline at end of file
diff --git a/ntsimulator/deploy/tls/set_NTS_IP.sh b/ntsimulator/deploy/tls/set_NTS_IP.sh
new file mode 100755 (executable)
index 0000000..151e996
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+################################################################################
+#
+# Copyright 2020 highstreet technologies GmbH and others
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+
+sleep 30
+
+if [ "$K8S_DEPLOYMENT" = "true" ]; then
+   NTS_IP=""
+   while true
+    do
+        echo "Trying to set the NTS_IP env var..."
+        if [ -z "$NTS_IP" ]; then
+            s=$HOSTNAME
+            count="$(cut -d'-' -f2 <<<"$s")"
+            id="NTSIM_${count}_SERVICE_HOST"
+            export NTS_IP=$(echo ${!id})
+            echo "NTS_IP=$NTS_IP"
+        else
+            echo "export NTS_IP=$NTS_IP" >> /root/.bashrc
+            source /root/.bashrc
+        fi
+        sleep 10
+    done
+else
+  echo "Non k8s deployment, not doing anything for the NTS_IP..."
+fi
+
+exit 0
index 0ecd983..b1577d7 100644 (file)
@@ -107,8 +107,6 @@ RUN \
       make install && \
       ldconfig
 
-# overwrite number of endpoints exposed by the NETCONF server
-COPY ./deploy/x-ran/stock_config.xml /opt/dev/Netopeer2/server/stock_config.xml
 # netopeer2
 RUN \
       cd /opt/dev/Netopeer2/server && mkdir build && cd build && \
@@ -205,7 +203,8 @@ RUN ldconfig
 
 WORKDIR /tmp
 RUN apt-get install -yqq wget \
-    openssh-client
+    openssh-client \
+    jq
 
 RUN mkdir py_install && cd py_install && \
     wget https://files.pythonhosted.org/packages/b9/9a/3e9da40ea28b8210dd6504d3fe9fe7e013b62bf45902b458d1cdc3c34ed9/ipaddress-1.0.23.tar.gz && \
@@ -246,6 +245,6 @@ ARG BUILD_DATE
 LABEL build-date=$BUILD_DATE
          
 ENV EDITOR vim
-EXPOSE 830-839
+EXPOSE 830-929
 
 CMD ["sh", "-c", "/usr/bin/supervisord -c /etc/supervisord.conf"]
diff --git a/ntsimulator/deploy/x-ran/stock_config.xml b/ntsimulator/deploy/x-ran/stock_config.xml
deleted file mode 100644 (file)
index 014c840..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
-  <listen>
-    <endpoint>
-      <name>MNG0</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>830</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG1</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>831</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG2</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>832</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG3</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>833</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG4</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>834</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG5</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>835</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-    <endpoint>
-      <name>MNG6</name>
-      <ssh>
-        <address>0.0.0.0</address>
-        <port>836</port>
-        <host-keys>
-          <host-key>
-            <name>imported SSH key</name>
-            <public-key>ssh_host_rsa_key</public-key>
-          </host-key>
-        </host-keys>
-      </ssh>
-    </endpoint>
-  </listen>
-</netconf-server>
index 6208600..c046509 100644 (file)
@@ -31,7 +31,9 @@
 #define TRUE 1
 #define FALSE 0
 
-#define NETCONF_CONNECTIONS_PER_DEVICE 10
+#define NETCONF_CONNECTIONS_PER_DEVICE (getSshConnectionsFromConfigJson() + getTlsConnectionsFromConfigJson())
+#define SSH_CONNECTIONS_PER_DEVICE getSshConnectionsFromConfigJson()
+#define TLS_CONNECTIONS_PER_DEVICE getTlsConnectionsFromConfigJson()
 
 #define PREPARE_ADD_NEW_VALUE(v, num)  {\
                                                                                num++;\
@@ -72,6 +74,7 @@ cJSON*        vesCreateFaultFields(char *alarm_condition, char *alarm_object, char *sev
 
 char*  readConfigFileInString(void);
 void   writeConfigFile(char *config);
+int    writeSkeletonConfigFile(void);
 
 int    getFaultNotificationDelayPeriodFromConfigJson(int *period_array, int *count);
 int    getVesHeartbeatPeriodFromConfigJson(void);
@@ -81,6 +84,8 @@ int   getVesPortFromConfigJson(void);
 int    getVesRegistrationFromConfigJson(void);
 int    getNetconfAvailableFromConfigJson(void);
 int    getVesAvailableFromConfigJson(void);
+int     getSshConnectionsFromConfigJson(void);
+int     getTlsConnectionsFromConfigJson(void);
 
 void   generateRandomMacAddress(char *mac_address);
 
@@ -95,4 +100,6 @@ cJSON*  getDeviceListFromStatusFile(void);
 int     compute_notifications_count(counterAlarms *ves_counter, counterAlarms *netconf_counter);
 int     getDeviceCounters(char *containerId, counterAlarms *ves_counter, counterAlarms *netconf_counter);
 
+int     getIntFromString(char *string, int def_value);
+
 #endif /* EXAMPLES_NTSIMULATOR_UTILS_H_ */
index ea120c7..165e7bb 100644 (file)
@@ -84,11 +84,23 @@ print_current_config(sr_session_ctx_t *session, const char *module_name)
         }
     }
 
+    char *ipv6 = strchr(odl_ip->data.string_val, ':');
+    char odl_ip_string[URL_AND_CREDENTIALS_MAX_LEN];
+    if (ipv6 != NULL)
+    {
+        sprintf(odl_ip_string, "[%s]", odl_ip->data.string_val);
+    }
+    else
+    {
+        sprintf(odl_ip_string, "%s", odl_ip->data.string_val);
+    }
+
+
     //URL used for mounting/unmounting a device; the device name needs to be appended
    char url[URL_AND_CREDENTIALS_MAX_LEN];
    sprintf(url, "http://%s:%d/restconf/config/network-topology:network-topology/topology/"
                 "topology-netconf/node/",
-                odl_ip->data.string_val, odl_port->data.uint32_val);
+                odl_ip_string, odl_port->data.uint32_val);
 
    char credentials[URL_AND_CREDENTIALS_MAX_LEN];
    sprintf(credentials, "%s:%s", odl_username->data.string_val, odl_password->data.string_val);
@@ -96,15 +108,15 @@ print_current_config(sr_session_ctx_t *session, const char *module_name)
    //URLs used for adding key pair to ODL, for TLS connections
    char url_for_keystore_add[URL_AND_CREDENTIALS_MAX_LEN];
    sprintf(url_for_keystore_add, "http://%s:%d/restconf/operations/netconf-keystore:add-keystore-entry",
-                        odl_ip->data.string_val, odl_port->data.uint32_val);
+                        odl_ip_string, odl_port->data.uint32_val);
 
    char url_for_private_key_add[URL_AND_CREDENTIALS_MAX_LEN];
    sprintf(url_for_private_key_add, "http://%s:%d/restconf/operations/netconf-keystore:add-private-key",
-                        odl_ip->data.string_val, odl_port->data.uint32_val);
+                        odl_ip_string, odl_port->data.uint32_val);
 
    char url_for_trusted_ca_add[URL_AND_CREDENTIALS_MAX_LEN];
    sprintf(url_for_trusted_ca_add, "http://%s:%d/restconf/operations/netconf-keystore:add-trusted-certificate",
-                        odl_ip->data.string_val, odl_port->data.uint32_val);
+                        odl_ip_string, odl_port->data.uint32_val);
 
    strcpy(controller_details.url, url);
    strcpy(controller_details.credentials, credentials);
@@ -126,6 +138,20 @@ static int simulated_devices_changed(int new_value)
 {
        int rc = SR_ERR_OK;
 
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        if (new_value != simulated_devices_config)
+        {
+            simulated_devices_config = new_value;
+            rc = send_k8s_scale(new_value);
+            if (rc != SR_ERR_OK)
+            {
+                printf("Could not send new_scale=%d to k8s cluster.\n", new_value);
+            }
+        }
+        return SR_ERR_OK;
+    }
+
     if (simulated_devices_config > new_value)
     {
        //we are configuring less elements that currently
@@ -140,6 +166,10 @@ static int simulated_devices_changed(int new_value)
        for (int i = 0; i < new_value - simulated_devices_config; ++i)
        {
                rc = start_device(device_list);
+            if (rc != SR_ERR_OK)
+            {
+                printf("ERROR: Could not start simulated device. Ignoring, trying with the next simulated device, if any...\n");
+            }
        }
     }
 
@@ -324,6 +354,56 @@ simulator_config_change_cb(sr_session_ctx_t *session, const char *module_name, s
        sr_free_val(val);
        val = NULL;
 
+    /* get the value from sysrepo, we do not care if the value did not change in our case */
+    rc = sr_get_item(session, "/network-topology-simulator:simulator-config/ssh-connections", &val);
+    if (rc != SR_ERR_OK) {
+        printf("NTS Manager /network-topology-simulator:simulator-config/ssh-connections object not available, ignoring..");
+    }
+    else
+    {
+        rc = ssh_connections_changed(val->data.uint32_val);
+        if (rc != SR_ERR_OK) {
+            goto sr_error;
+        }
+
+        if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+        {
+            rc = send_k8s_extend_port();
+            if (rc != SR_ERR_OK)
+            {
+                printf("Could not send the extended port to k8s cluster.\n");
+            }
+        }
+    }
+
+    sr_free_val(val);
+       val = NULL;
+
+    /* get the value from sysrepo, we do not care if the value did not change in our case */
+    rc = sr_get_item(session, "/network-topology-simulator:simulator-config/tls-connections", &val);
+    if (rc != SR_ERR_OK) {
+        printf("NTS Manager /network-topology-simulator:simulator-config/tls-connections object not available, ignoring..");
+    }
+    else
+    {
+        rc = tls_connections_changed(val->data.uint32_val);
+        if (rc != SR_ERR_OK) {
+            goto sr_error;
+        }
+
+        if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+        {
+            rc = send_k8s_extend_port();
+            if (rc != SR_ERR_OK)
+            {
+                printf("Could not send the extended port to k8s cluster.\n");
+            }
+        }
+    }
+
+    sr_free_val(val);
+       val = NULL;
+
     return SR_ERR_OK;
 
 sr_error:
@@ -351,7 +431,8 @@ simulator_status_cb(const char *xpath, sr_val_t **values, size_t *values_cnt,
         printf("Could not compute the total number of notification count.\n");
     }
 
-       if (sr_xpath_node_name_eq(xpath, "simulated-devices-list")) {
+       if (sr_xpath_node_name_eq(xpath, "simulated-devices-list")) 
+    {
                sr_val_t *v;
                size_t current_num_of_values= 0;
 
@@ -654,6 +735,12 @@ main(int argc, char **argv)
 
     setbuf(stdout, NULL);
 
+    rc = _init_curl_k8s();
+    if (rc != SR_ERR_OK)
+    {
+        fprintf(stderr, "Could not initialize cURL for K8S connection: %s\n", sr_strerror(rc));
+    }
+
     device_list = new_device_stack();
     rc = _init_curl();
     if (rc != SR_ERR_OK)
@@ -661,6 +748,12 @@ main(int argc, char **argv)
         fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc));
     }
 
+    rc = writeSkeletonConfigFile();
+    if (rc != SR_ERR_OK)
+    {
+        fprintf(stderr, "Could not initialize configuration JSON file: %s\n", sr_strerror(rc));
+    }
+
     /* connect to sysrepo */
     rc = sr_connect("network-topology-simulator", SR_CONN_DEFAULT, &connection);
     if (SR_ERR_OK != rc) {
@@ -675,6 +768,177 @@ main(int argc, char **argv)
         goto cleanup;
     }
 
+    // setting the values that come in an ENV variable as defaults - ves-heartbeat-period
+    int vesHeartbeatPeriod = getIntFromString(getenv("VesHeartbeatPeriod"), 0);
+
+    sr_val_t value = { 0 };
+    value.type = SR_UINT32_T;
+    value.data.uint32_val = vesHeartbeatPeriod;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/ves-heartbeat-period", 
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = ves_heartbeat_period_changed(vesHeartbeatPeriod);
+    if (SR_ERR_OK != rc) {
+        printf("Error by ves_heartbeat_period_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - is-netconf-available
+
+    int isNetconfAvailable = 1;
+
+    char *isNetconfAvailablString = getenv("IsNetconfAvailable");
+    if (isNetconfAvailablString != NULL)
+    {
+        if (strcmp(isNetconfAvailablString, "false") == 0)
+        {
+            isNetconfAvailable = 0;
+        }
+    }
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_BOOL_T;
+    value.data.bool_val = isNetconfAvailable;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-netconf-available", 
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = is_netconf_available_changed(isNetconfAvailable);
+    if (SR_ERR_OK != rc) {
+        printf("Error by is_netconf_available_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - is-ves-available
+
+    int isVesAvailable = 1;
+
+    char *isVesAvailablString = getenv("IsVesAvailable");
+    if (isVesAvailablString != NULL)
+    {
+        if (strcmp(isVesAvailablString, "false") == 0)
+        {
+            isVesAvailable = 0;
+        }
+    }
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_BOOL_T;
+    value.data.bool_val = isVesAvailable;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/notification-config/is-ves-available", 
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = is_ves_available_changed(isVesAvailable);
+    if (SR_ERR_OK != rc) {
+        printf("Error by is_ves_available_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - ves-endpoint-port
+
+    int vesEndpointPort = getIntFromString(getenv("VesEndpointPort"), 8080);
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_UINT16_T;
+    value.data.uint16_val = vesEndpointPort;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-port", 
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = ves_port_changed(vesEndpointPort);
+    if (SR_ERR_OK != rc) {
+        printf("Error by ves_port_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - ves-endpoint-ip
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_STRING_T;
+    value.data.string_val = getenv("VesEndpointIp");
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ves-endpoint-details/ves-endpoint-ip", 
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = ves_ip_changed(getenv("VesEndpointIp"));
+    if (SR_ERR_OK != rc) {
+        printf("Error by ves_ip_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - ssh-connections
+
+    int sshConnections = getIntFromString(getenv("SshConnections"), 1);
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_UINT32_T;
+    value.data.uint32_val = sshConnections;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/ssh-connections",
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = ssh_connections_changed(sshConnections);
+    if (SR_ERR_OK != rc) {
+        printf("Error by ssh_connections_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    // setting the values that come in an ENV variable as defaults - tls-connections
+
+    int tlsConnections = getIntFromString(getenv("TlsConnections"), 0);
+
+    value = (const sr_val_t) { 0 };
+    value.type = SR_UINT32_T;
+    value.data.uint32_val = tlsConnections;
+    rc = sr_set_item(session, "/network-topology-simulator:simulator-config/tls-connections",
+            &value, SR_EDIT_DEFAULT);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_set_item: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    rc = tls_connections_changed(tlsConnections);
+    if (SR_ERR_OK != rc) {
+        printf("Error by tls_connections_changed: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        rc = send_k8s_extend_port();
+        if (rc != SR_ERR_OK)
+        {
+            printf("Could not send the number of ports to k8s cluster\n");
+        }
+    }
+
+    //commit the changes that we have done until now
+    rc = sr_commit(session);
+    if (SR_ERR_OK != rc) {
+        printf("Error by sr_commit: %s\n", sr_strerror(rc));
+        goto cleanup;
+    }
+
        /* read startup config */
        printf("\n\n ========== READING STARTUP CONFIG network-topology-simulator: ==========\n\n");
        print_current_config(session, "network-topology-simulator");
@@ -743,12 +1007,18 @@ cleanup:
     clean_current_docker_configuration();
     rc = cleanup_curl();
     rc = cleanup_curl_odl();
+    rc = cleanup_curl_k8s();
 
     return rc;
 }
 
 static void clean_current_docker_configuration(void)
 {
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
+    {
+        return;
+    }
+
        printf("Cleaning docker containers...\n");
 
        if (device_list == NULL)
index f734307..81736c3 100644 (file)
 
 static         CURL *curl; //share the same curl connection for communicating with the Docker Engine API
 static         CURL *curl_odl; //share the same curl connection for mounting servers in ODL
+static         CURL *curl_k8s; //share the same curl connection for communicating with the K8S cluster
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
+*/
 
 static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
 {
@@ -51,35 +56,49 @@ static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, voi
 
 static void set_curl_common_info()
 {
-       struct curl_slist *chunk = NULL;
-       chunk = curl_slist_append(chunk, "Content-Type: application/json");
-       chunk = curl_slist_append(chunk, "Accept: application/json");
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/json");
+    chunk = curl_slist_append(chunk, "Accept: application/json");
 
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
 
-       curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
+    curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
 
-       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
-    curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
-    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
 
     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
 }
 
 static void set_curl_common_info_odl()
 {
-       struct curl_slist *chunk = NULL;
-       chunk = curl_slist_append(chunk, "Content-Type: application/xml");
-       chunk = curl_slist_append(chunk, "Accept: application/xml");
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/xml");
+    chunk = curl_slist_append(chunk, "Accept: application/xml");
 
     curl_easy_setopt(curl_odl, CURLOPT_HTTPHEADER, chunk);
 
     curl_easy_setopt(curl_odl, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
-    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 5L); //seconds timeout for an operation
+    curl_easy_setopt(curl_odl, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
 
     curl_easy_setopt(curl_odl, CURLOPT_VERBOSE, 1L);
 }
 
+static void set_curl_common_info_k8s()
+{
+    struct curl_slist *chunk = NULL;
+    chunk = curl_slist_append(chunk, "Content-Type: application/json");
+    chunk = curl_slist_append(chunk, "Accept: application/json");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_HTTPHEADER, chunk);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_CONNECTTIMEOUT, 2L); // seconds timeout for a connection
+    curl_easy_setopt(curl_k8s, CURLOPT_TIMEOUT, 10L); //seconds timeout for an operation
+
+    curl_easy_setopt(curl_k8s, CURLOPT_VERBOSE, 1L);
+}
+
 static cJSON* get_docker_container_bindings(void)
 {
        struct MemoryStruct curl_response_mem;
@@ -146,14 +165,87 @@ static cJSON* get_docker_container_bindings(void)
        return NULL;
 }
 
-static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds)
+static cJSON* get_docker_container_network_node(void)
 {
-       if (managerBinds == NULL)
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char url[200];
+    sprintf(url, "http:/v%s/containers/%s/json", getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        return NULL;
+    }
+    else
+    {
+        cJSON *json_response = cJSON_Parse(curl_response_mem.memory);
+
+        printf("%lu bytes retrieved\n", (unsigned long)curl_response_mem.size);
+
+        if (json_response == NULL)
+        {
+            printf("Could not parse JSON response for url=\"%s\"\n", url);
+            return NULL;
+        }
+
+        cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
+
+        if (hostConfig == NULL)
+        {
+            printf("Could not get HostConfig object\n");
+            return NULL;
+        }
+
+        cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
+
+        if (networkMode == NULL)
+        {
+            printf("Could not get NetworkMode object\n");
+            return NULL;
+        }
+
+        cJSON *networkCopy = cJSON_Duplicate(networkMode, 1);
+
+        cJSON_Delete(json_response);
+
+        return networkCopy;
+    }
+
+    return NULL;
+}
+
+static char* create_docker_container_curl(int base_netconf_port, cJSON* managerBinds, cJSON* networkMode)
+{
+    if (managerBinds == NULL)
+    {
+        printf("Could not retrieve JSON object: Binds\n");
+        return NULL;
+    }
+    cJSON *binds = cJSON_Duplicate(managerBinds, 1);
+
+    if (networkMode == NULL)
        {
-               printf("Could not retrieve JSON object: Binds\n");
+               printf("Could not retrieve JSON object: NetworkMode\n");
                return NULL;
        }
-       cJSON *binds = cJSON_Duplicate(managerBinds, 1);
+       cJSON *netMode = cJSON_Duplicate(networkMode, 1);
 
        struct MemoryStruct curl_response_mem;
 
@@ -288,18 +380,30 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
        }
     cJSON_AddItemToArray(env_variables_array, env_var_obj_2);
 
-       char scripts_dir[200];
-       sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
-       cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
-       if (env_var_obj_3 == NULL)
-       {
-               printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
-               return NULL;
-       }
-       cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
+    char scripts_dir[200];
+    sprintf(scripts_dir, "SCRIPTS_DIR=%s", getenv("SCRIPTS_DIR"));
+    cJSON *env_var_obj_3 = cJSON_CreateString(scripts_dir);
+    if (env_var_obj_3 == NULL)
+    {
+        printf("Could not create JSON object: Env array object SCRIPTS_DIR\n");
+        return NULL;
+    }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_3);
+
+    char k8s_deployment[50];
+    sprintf(k8s_deployment, "K8S_DEPLOYMENT=%s", getenv("K8S_DEPLOYMENT"));
+    cJSON *env_var_obj_4 = cJSON_CreateString(k8s_deployment);
+    if (env_var_obj_4 == NULL)
+    {
+        printf("Could not create JSON object: Env array object K8S_DEPLOYMENT\n");
+        return NULL;
+    }
+    cJSON_AddItemToArray(env_variables_array, env_var_obj_4);
 
     cJSON_AddItemToObject(hostConfig, "Binds", binds);
 
+    cJSON_AddItemToObject(hostConfig, "NetworkMode", netMode);
+
     char *post_data_string = NULL;
 
     post_data_string = cJSON_PrintUnformatted(postDataJson);
@@ -317,6 +421,11 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
 
        res = curl_easy_perform(curl);
 
+    if (post_data_string != NULL)
+    {
+        free(post_data_string);
+    }
+
        if (res != CURLE_OK)
        {
                return NULL;
@@ -353,37 +462,76 @@ static char* create_docker_container_curl(int base_netconf_port, cJSON* managerB
 
 static int start_docker_container_curl(char *container_id)
 {
-       struct MemoryStruct curl_response_mem;
+    struct MemoryStruct curl_response_mem;
 
-       curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
-       curl_response_mem.size = 0;    /* no data at this point */
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
 
-       CURLcode res;
+    CURLcode res;
 
-       curl_easy_reset(curl);
-       set_curl_common_info();
+    curl_easy_reset(curl);
+    set_curl_common_info();
 
-       char url[100];
-       sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
+    char url[100];
+    sprintf(url, "http:/v%s/containers/%s/start", getenv("DOCKER_ENGINE_VERSION"), container_id);
 
-       curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_URL, url);
 
     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
 
-       curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
 
-       res = curl_easy_perform(curl);
+    res = curl_easy_perform(curl);
 
-       if (res != CURLE_OK)
-       {
-               return SR_ERR_OPERATION_FAILED;
-       }
-       else
-       {
-               printf("Container %s started successfully!\n", container_id);
-       }
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        printf("Container %s started successfully!\n", container_id);
+    }
 
-       return SR_ERR_OK;
+    return SR_ERR_OK;
+}
+
+static int rename_docker_container_curl(char *container_id, int device_number)
+{
+    struct MemoryStruct curl_response_mem;
+
+    curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
+    curl_response_mem.size = 0;    /* no data at this point */
+
+    CURLcode res;
+
+    curl_easy_reset(curl);
+    set_curl_common_info();
+
+    char device_name[100];
+    sprintf(device_name, "%s-%d", getenv("CONTAINER_NAME"), device_number);
+
+    char url[100];
+    sprintf(url, "http:/v%s/containers/%s/rename?name=%s", getenv("DOCKER_ENGINE_VERSION"), container_id,
+                device_name);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&curl_response_mem);
+
+    res = curl_easy_perform(curl);
+
+    if (res != CURLE_OK)
+    {
+        return SR_ERR_OPERATION_FAILED;
+    }
+    else
+    {
+        printf("Container %s renamed successfully to %s!\n", container_id, device_name);
+    }
+
+    return SR_ERR_OK;
 }
 
 static int kill_and_remove_docker_container_curl(char *container_id)
@@ -437,20 +585,20 @@ static int send_mount_device_instance_ssh(char *url, char *credentials, char *de
        char post_data_xml[1500];
 
        sprintf(post_data_xml,
-                       "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
-                       "<node-id>%s_%d</node-id>"
-                       "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
-                       "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
-                       "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
-                       "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
-                       "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
-                       "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
-                       "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
-                       "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
-                       "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
-                       "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
-                       "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
-                       "</node>",
+            "<node xmlns=\"urn:TBD:params:xml:ns:yang:network-topology\">"
+            "<node-id>%s_%d</node-id>"
+            "<host xmlns=\"urn:opendaylight:netconf-node-topology\">%s</host>"
+            "<port xmlns=\"urn:opendaylight:netconf-node-topology\">%d</port>"
+            "<username xmlns=\"urn:opendaylight:netconf-node-topology\">%s</username>"
+            "<password xmlns=\"urn:opendaylight:netconf-node-topology\">%s</password>"
+            "<tcp-only xmlns=\"urn:opendaylight:netconf-node-topology\">false</tcp-only>"
+            "<keepalive-delay xmlns=\"urn:opendaylight:netconf-node-topology\">120</keepalive-delay>"
+            "<reconnect-on-changed-schema xmlns=\"urn:opendaylight:netconf-node-topology\">false</reconnect-on-changed-schema>"
+            "<sleep-factor xmlns=\"urn:opendaylight:netconf-node-topology\">1.5</sleep-factor>"
+            "<connection-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">20000</connection-timeout-millis>"
+            "<max-connection-attempts xmlns=\"urn:opendaylight:netconf-node-topology\">100</max-connection-attempts>"
+            "<between-attempts-timeout-millis xmlns=\"urn:opendaylight:netconf-node-topology\">2000</between-attempts-timeout-millis>"
+            "</node>",
                        device_name, device_port, getenv("NTS_IP"), device_port, "netconf", "netconf");
 
        printf("Post data:\n%s\n", post_data_xml);
@@ -586,9 +734,10 @@ static int send_mount_device(device_t *current_device, controller_t controller_d
 {
        int rc = SR_ERR_OK;
        bool is_mounted = true;
+    int port = 0;
 
        //This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
-       for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE - 3; ++port)
+       for (int i = 0; i < SSH_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
                rc = send_mount_device_instance_ssh(controller_details.url, controller_details.credentials,
                                current_device->device_id, current_device->netconf_port + port);
@@ -597,7 +746,7 @@ static int send_mount_device(device_t *current_device, controller_t controller_d
                        is_mounted = false;
                }
        }
-       for (int port = NETCONF_CONNECTIONS_PER_DEVICE - 3; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
+       for (int i = 0; i < TLS_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
                rc = send_mount_device_instance_tls(controller_details.url, controller_details.credentials,
                                current_device->device_id, current_device->netconf_port + port);
@@ -642,13 +791,14 @@ device_stack_t *new_device_stack(void)
        return stack;
 }
 
-void push_device(device_stack_t *theStack, char *dev_id, int port)
+void push_device(device_stack_t *theStack, char *dev_id, int port, int dev_num)
 {
        device_t *new_dev = malloc(sizeof(*new_dev));
 
        if (new_dev) {
                new_dev->device_id = strdup(dev_id);
                new_dev->netconf_port = port;
+        new_dev->device_number = dev_num;
                new_dev->is_mounted = false;
                new_dev->operational_state = strdup("not-specified");
 
@@ -674,39 +824,38 @@ void pop_device(device_stack_t *theStack)
 
 int get_netconf_port_next(device_stack_t *theStack)
 {
-       if (theStack && theStack->stack_size > 0) {
-               return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
-       }
+    if (theStack && theStack->stack_size > 0) {
+        return theStack->head->netconf_port + NETCONF_CONNECTIONS_PER_DEVICE;
+    }
 
-       return get_netconf_port_base();
+    return get_netconf_port_base();
 }
 
 int get_netconf_port_base()
 {
-       int netconf_port_base = 0, rc;
+    int netconf_port_base;
 
-       char *netconf_base_string = getenv("NETCONF_BASE");
+    netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 50000);
 
-       if (netconf_base_string != NULL)
-       {
-               rc = sscanf(netconf_base_string, "%d", &netconf_port_base);
-               if (rc != 1)
-               {
-                       printf("Could not get the NETCONF_BASE port! Using the default 30.000...\n");
-                       netconf_port_base = 30000;
-               }
-       }
-
-       return netconf_port_base;
+    return netconf_port_base;
 }
 
+// we start numbering the containers from 0
+int get_device_number_next(device_stack_t *theStack)
+{
+    if (theStack && theStack->stack_size > 0) {
+        return theStack->head->device_number + 1;
+    }
+
+    return 0;
+}
 
 char *get_id_last_device(device_stack_t *theStack)
 {
-       if (theStack && theStack->head) {
-               return theStack->head->device_id;
-       }
-       return NULL;
+    if (theStack && theStack->head) {
+        return theStack->head->device_id;
+    }
+    return NULL;
 }
 
 int get_current_number_of_mounted_devices(device_stack_t *theStack)
@@ -732,6 +881,12 @@ int get_current_number_of_mounted_devices(device_stack_t *theStack)
 
 int get_current_number_of_devices(device_stack_t *theStack)
 {
+    //TODO implement function for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        return 0;
+    }
+
        struct MemoryStruct curl_response_mem;
 
        curl_response_mem.memory = malloc(1);  /* will be grown as needed by the realloc above */
@@ -743,8 +898,8 @@ int get_current_number_of_devices(device_stack_t *theStack)
        set_curl_common_info();
 
        char url[100];
-       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"],\"status\":[\"running\"]}",
-                       getenv("DOCKER_ENGINE_VERSION"));
+       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"],\"status\":[\"running\"]}",
+                       getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
 
        curl_easy_setopt(curl, CURLOPT_URL, url);
 
@@ -827,18 +982,29 @@ char* get_docker_container_operational_state(device_stack_t *theStack, char *con
 int start_device(device_stack_t *theStack)
 {
        int rc = SR_ERR_OK;
-       static cJSON* managerBindings = NULL;
+       static cJSON *managerBindings = NULL, *networkMode = NULL;
 
-       if (managerBindings == NULL)
+    if (managerBindings == NULL)
+    {
+        managerBindings = get_docker_container_bindings();
+    }
+
+    if (networkMode == NULL)
        {
-               managerBindings = get_docker_container_bindings();
+               networkMode = get_docker_container_network_node();
        }
 
        int netconf_base = get_netconf_port_next(theStack);
+    int device_number = get_device_number_next(theStack);
 
-       char *dev_id = create_docker_container_curl(netconf_base, managerBindings);
+       char *dev_id = create_docker_container_curl(netconf_base, managerBindings, networkMode);
+    if (dev_id == NULL)
+    {
+        printf("ERROR: Could not create docker container!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
 
-       push_device(theStack, dev_id, netconf_base);
+       push_device(theStack, dev_id, netconf_base, device_number);
 
        rc = start_docker_container_curl(dev_id);
        if (rc != SR_ERR_OK)
@@ -846,6 +1012,12 @@ int start_device(device_stack_t *theStack)
                printf("Could not start device with device_id=\"%s\"\n", dev_id);
        }
 
+    rc = rename_docker_container_curl(dev_id, device_number);
+       if (rc != SR_ERR_OK)
+       {
+               printf("Could not rename device with device_id=\"%s\"\n", dev_id);
+       }
+
        if (dev_id) {
                free(dev_id);
        }
@@ -897,6 +1069,28 @@ int cleanup_curl_odl()
        return SR_ERR_OK;
 }
 
+int _init_curl_k8s()
+{
+    curl_k8s = curl_easy_init();
+
+    if (curl_k8s == NULL) {
+        printf("cURL initialization error! Aborting call!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
+
+int cleanup_curl_k8s()
+{
+    if (curl_k8s != NULL)
+    {
+        curl_easy_cleanup(curl_k8s);
+    }
+
+    return SR_ERR_OK;
+}
+
 int stop_device(device_stack_t *theStack)
 {
        int rc = SR_ERR_OK;
@@ -975,6 +1169,13 @@ int unmount_device(device_stack_t *theStack, controller_t controller_list)
 
 int get_docker_containers_operational_state_curl(device_stack_t *theStack)
 {
+
+    //TODO implement function for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true") == 0)
+    {
+        return SR_ERR_OK;
+    }
+
        int rc = SR_ERR_OK;
        struct MemoryStruct curl_response_mem;
 
@@ -987,7 +1188,8 @@ int get_docker_containers_operational_state_curl(device_stack_t *theStack)
        set_curl_common_info();
 
        char url[100];
-       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS\"]}", getenv("DOCKER_ENGINE_VERSION"));
+       sprintf(url, "http:/v%s/containers/json?all=true&filters={\"label\":[\"NTS_Manager=%s\"]}", 
+    getenv("DOCKER_ENGINE_VERSION"), getenv("HOSTNAME"));
 
        curl_easy_setopt(curl, CURLOPT_URL, url);
 
@@ -1047,13 +1249,19 @@ int get_docker_containers_operational_state_curl(device_stack_t *theStack)
 
 char* get_docker_container_resource_stats(device_stack_t *theStack)
 {
+    //TOD need to implement this for k8s deployment
+    if (strcmp(getenv("K8S_DEPLOYMENT"), "true"))
+    {
+        return strdup("CPU=0%;RAM=0MiB");
+    }
+
        char line[LINE_BUFSIZE];
        int linenr;
        FILE *pipe;
 
        /* Get a pipe where the output from the scripts comes in */
        char script[200];
-       sprintf(script, "%s/docker_stats.sh", getenv("SCRIPTS_DIR"));
+       sprintf(script, "/opt/dev/docker_stats.sh %s", getenv("HOSTNAME"));
 
        pipe = popen(script, "r");
        if (pipe == NULL) {  /* check for errors */
@@ -1158,6 +1366,12 @@ int notification_delay_period_changed(sr_val_t *val, size_t count)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1211,6 +1425,12 @@ int ves_heartbeat_period_changed(int period)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1462,6 +1682,12 @@ int ves_ip_changed(char *new_ip)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1515,6 +1741,12 @@ int ves_port_changed(int new_port)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1568,6 +1800,12 @@ int ves_registration_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1621,6 +1859,12 @@ int is_netconf_available_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
@@ -1674,7 +1918,211 @@ int is_ves_available_changed(cJSON_bool new_bool)
        stringConfiguration = cJSON_Print(jsonConfig);
        writeConfigFile(stringConfiguration);
 
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
        cJSON_Delete(jsonConfig);
 
        return SR_ERR_OK;
 }
+
+    int ssh_connections_changed(int number)
+    {
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *sshConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ssh-connections");
+    if (!cJSON_IsNumber(sshConnections))
+    {
+        printf("Configuration JSON is not as expected: ssh-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the ssh-connections object
+    cJSON_SetNumberValue(sshConnections, number);
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+int tls_connections_changed(int number)
+    {
+    char *stringConfiguration = readConfigFileInString();
+
+    if (stringConfiguration == NULL)
+    {
+        printf("Could not read configuration file!\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfiguration);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfiguration);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfiguration);
+    stringConfiguration = NULL;
+
+    cJSON *tlsConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "tls-connections");
+    if (!cJSON_IsNumber(tlsConnections))
+    {
+        printf("Configuration JSON is not as expected: tls-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //we set the value of the tls-connections object
+    cJSON_SetNumberValue(tlsConnections, number);
+
+    //writing the new JSON to the configuration file
+    stringConfiguration = cJSON_Print(jsonConfig);
+    writeConfigFile(stringConfiguration);
+
+    if (stringConfiguration != NULL)
+    {
+        free(stringConfiguration);
+        stringConfiguration = NULL;
+    }
+
+    cJSON_Delete(jsonConfig);
+
+    return SR_ERR_OK;
+}
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/extend-ports --data '{"number-of-ports":12}'
+*/
+int send_k8s_extend_port(void)
+{
+    int num_of_ports = getSshConnectionsFromConfigJson() + getTlsConnectionsFromConfigJson();
+
+    CURLcode res;
+
+    curl_easy_reset(curl_k8s);
+    set_curl_common_info_k8s();
+
+    char url_for_curl[100];
+    sprintf(url_for_curl, "http://localhost:5000/extend-ports");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
+
+    char post_data_json[1500];
+
+    sprintf(post_data_json,
+            "{\"number-of-ports\":%d}",
+            num_of_ports);
+
+    printf("Post data:\n%s\n", post_data_json);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
+    curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
+
+    res = curl_easy_perform(curl_k8s);
+    if (res != CURLE_OK)
+    {
+        printf("cURL failed to url=%s\n", url_for_curl);
+    }
+
+    long http_response_code = 0;
+    curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
+    if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
+    {
+        printf("cURL succeeded to url=%s\n", url_for_curl);
+    }
+    else
+    {
+        printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
+
+/*
+curl -X POST -H 'Content-Type: application/json' -i http://localhost:5000/scale --data '{"simulatedDevices":2}'
+*/
+int send_k8s_scale(int number_of_devices)
+{
+    CURLcode res;
+
+    curl_easy_reset(curl_k8s);
+    set_curl_common_info_k8s();
+
+    char url_for_curl[100];
+    sprintf(url_for_curl, "http://localhost:5000/scale");
+
+    curl_easy_setopt(curl_k8s, CURLOPT_URL, url_for_curl);
+
+    char post_data_json[1500];
+
+    sprintf(post_data_json,
+            "{\"simulatedDevices\":%d}",
+            number_of_devices);
+
+    printf("Post data:\n%s\n", post_data_json);
+
+    curl_easy_setopt(curl_k8s, CURLOPT_POSTFIELDS, post_data_json);
+    curl_easy_setopt(curl_k8s, CURLOPT_CUSTOMREQUEST, "POST");
+
+    res = curl_easy_perform(curl_k8s);
+    if (res != CURLE_OK)
+    {
+        printf("cURL failed to url=%s\n", url_for_curl);
+    }
+
+    long http_response_code = 0;
+    curl_easy_getinfo (curl_k8s, CURLINFO_RESPONSE_CODE, &http_response_code);
+    if (http_response_code >= 200 && http_response_code <= 226 && http_response_code != CURLE_ABORTED_BY_CALLBACK)
+    {
+        printf("cURL succeeded to url=%s\n", url_for_curl);
+    }
+    else
+    {
+        printf("cURL to url=%s failed with code=%ld\n", url_for_curl, http_response_code);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    return SR_ERR_OK;
+}
\ No newline at end of file
index 3b93e48..3540eb3 100644 (file)
@@ -38,6 +38,7 @@
 typedef struct device {
        char *device_id;
        int netconf_port;
+    int device_number;
        bool is_mounted;
        char *operational_state;
        struct device *next;
@@ -61,10 +62,11 @@ typedef struct controller
 
 
 device_stack_t *new_device_stack(void);
-void push_device(device_stack_t *theStack, char *dev_id, int port);
+void push_device(device_stack_t *theStack, char *dev_id, int port, int dev_num);
 void pop_device(device_stack_t *theStack);
 int get_netconf_port_next(device_stack_t *theStack);
 int get_netconf_port_base(void);
+int get_device_number_next(device_stack_t *theStack);
 char *get_id_last_device(device_stack_t *theStack);
 int get_current_number_of_devices(device_stack_t *theStack);
 int get_current_number_of_mounted_devices(device_stack_t *theStack);
@@ -85,6 +87,9 @@ int cleanup_curl(void);
 int _init_curl_odl(void);
 int cleanup_curl_odl(void);
 
+int _init_curl_k8s(void);
+int cleanup_curl_k8s(void);
+
 int start_device(device_stack_t *theStack);
 int stop_device(device_stack_t *theStack);
 
@@ -103,10 +108,13 @@ int ves_port_changed(int new_port);
 int ves_registration_changed(cJSON_bool new_bool);
 int is_netconf_available_changed(cJSON_bool new_bool);
 int is_ves_available_changed(cJSON_bool new_bool);
-
+int ssh_connections_changed(int number);
+int tls_connections_changed(int number);
 
 
 int add_key_pair_to_odl(controller_t *controller_list, int controller_list_size);
 
+int send_k8s_scale(int number_of_devices);
+int send_k8s_extend_port(void);
 
 #endif /* SRC_NTSIMULATOR_MANAGER_SIMULATOR_OPERATIONS_H_ */
index a46ae04..3699e28 100644 (file)
@@ -24,6 +24,7 @@
 #include <math.h>
 #include <sys/time.h>
 #include <cjson/cJSON.h>
+#include <string.h>
 
 #include "sysrepo.h"
 #include "sysrepo/values.h"
@@ -99,7 +100,6 @@ static int cleanup_curl()
 
 static int send_fault_ves_message(char *alarm_condition, char *alarm_object, char *severity, char *date_time, char *specific_problem, int port)
 {
-       int rc = SR_ERR_OK;
        CURLcode res;
        static int sequence_id = 0;
        int netconf_port_base = 0;
@@ -112,23 +112,14 @@ static int send_fault_ves_message(char *alarm_condition, char *alarm_object, cha
        if (event == NULL)
        {
                printf("Could not create JSON object: event\n");
-               return 1;
+               return SR_ERR_OPERATION_FAILED;
        }
        cJSON_AddItemToObject(postDataJson, "event", event);
 
        char *hostname = getenv("HOSTNAME");
-       char *netconf_base_string = getenv("NETCONF_BASE");
 
-       if (netconf_base_string != NULL)
-       {
-               rc = sscanf(netconf_base_string, "%d", &netconf_port_base);
-               if (rc != 1)
-               {
-                       printf("Could not find the NETCONF base port, aborting the PNF registration...\n");
-                       return 1;
-               }
-               netconf_port_base += port;
-       }
+    netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 1);
+    netconf_port_base += port;
 
        char source_name[100];
        sprintf(source_name, "%s_%d", hostname, netconf_port_base);
@@ -137,7 +128,7 @@ static int send_fault_ves_message(char *alarm_condition, char *alarm_object, cha
        if (commonEventHeader == NULL)
        {
                printf("Could not create JSON object: commonEventHeader\n");
-               return 1;
+               return SR_ERR_OPERATION_FAILED;
        }
        cJSON_AddItemToObject(event, "commonEventHeader", commonEventHeader);
 
@@ -149,7 +140,7 @@ static int send_fault_ves_message(char *alarm_condition, char *alarm_object, cha
                {
                        cJSON_Delete(postDataJson);
                }
-               return 1;
+               return SR_ERR_OPERATION_FAILED;
        }
        cJSON_AddItemToObject(event, "faultFields", faultFields);
 
@@ -360,7 +351,6 @@ main(int argc, char **argv)
     sr_session_ctx_t *session = NULL;
     sr_subscription_ctx_t *subscription = NULL;
     int rc = SR_ERR_OK;
-    int notification_delay_period = 0; //seconds
 
     setbuf(stdout, NULL);
 
index 15bb426..d98dac0 100644 (file)
@@ -455,7 +455,6 @@ void        writeConfigFile(char *config)
 int getFaultNotificationDelayPeriodFromConfigJson(int *period_array, int *count)
 {
        char *stringConfig = readConfigFileInString();
-       int notificationDelay = 0;
 
        if (stringConfig == NULL)
        {
@@ -1304,6 +1303,17 @@ int      writeSkeletonStatusFile()
 
     writeStatusFile(status_string);
 
+    if (status_string != NULL)
+    {
+        free(status_string);
+        status_string = NULL;
+    }
+
+    if (statusObject != NULL)
+    {
+           cJSON_Delete(statusObject);
+    }
+
     return SR_ERR_OK;
 }
 
@@ -1534,7 +1544,16 @@ int writeStatusNotificationCounters(counterAlarms ves_counter, counterAlarms net
        char *stringStatus = cJSON_PrintUnformatted(jsonStatus);
        writeStatusFile(stringStatus);
 
-       cJSON_Delete(jsonStatus);
+    if (stringStatus != NULL)
+    {
+        free(stringStatus);
+        stringStatus = NULL;
+    }
+
+    if (jsonStatus != NULL)
+    {
+           cJSON_Delete(jsonStatus);
+    }
 
        return SR_ERR_OK;
 }
@@ -1590,7 +1609,16 @@ int removeDeviceEntryFromStatusFile(char *containerId)
        char *stringStatus = cJSON_PrintUnformatted(jsonStatus);
        writeStatusFile(stringStatus);
 
-       cJSON_Delete(jsonStatus);
+    if (stringStatus != NULL)
+    {
+        free(stringStatus);
+        stringStatus = NULL;
+    }
+
+    if (jsonStatus != NULL)
+    {
+        cJSON_Delete(jsonStatus);
+    }
 
        return SR_ERR_OK;
 }
@@ -1757,6 +1785,9 @@ int getDeviceCounters(char *containerId, counterAlarms *ves_counter, counterAlar
 
     int array_size = cJSON_GetArraySize(deviceList);
 
+    ves_counter->critical = ves_counter->major = ves_counter->minor = ves_counter->warning = ves_counter->normal = 0;
+    netconf_counter->critical = netconf_counter->major = netconf_counter->minor = netconf_counter->warning = netconf_counter->normal = 0;
+
     for (int i=0; i<array_size; ++i)
     {
         cJSON *deviceListEntry = cJSON_GetArrayItem(deviceList, i);
@@ -1896,4 +1927,248 @@ int getDeviceCounters(char *containerId, counterAlarms *ves_counter, counterAlar
     cJSON_Delete(jsonStatus);
 
     return SR_ERR_OK;
-}
\ No newline at end of file
+}
+
+int writeSkeletonConfigFile()
+{
+    cJSON *configObject = cJSON_CreateObject();
+    if (configObject == NULL)
+    {
+        printf("Could not create JSON object: configObject\n");
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *notificationConfig = cJSON_CreateObject();
+    if (notificationConfig == NULL)
+    {
+        printf("Could not create JSON object: notificationConfig\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+    cJSON_AddItemToObject(configObject, "notification-config", notificationConfig);
+
+    if (cJSON_AddNumberToObject(notificationConfig, "ves-heartbeat-period", 0) == NULL)
+    {
+        printf("Could not create JSON object: ves-heartbeat-period\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddTrueToObject(notificationConfig, "is-netconf-available") == NULL)
+    {
+        printf("Could not create JSON object: is-netconf-available\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddTrueToObject(notificationConfig, "is-ves-available") == NULL)
+    {
+        printf("Could not create JSON object: is-ves-available\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    cJSON *faultNotificationDelayPeriod = cJSON_CreateArray();
+    if (faultNotificationDelayPeriod == NULL)
+    {
+        printf("Could not create JSON object: faultNotificationDelayPeriod\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+       }
+    cJSON_AddItemToObject(notificationConfig, "fault-notification-delay-period", faultNotificationDelayPeriod);
+
+    cJSON *arrayItem = cJSON_CreateNumber(0);
+    if (arrayItem == NULL)
+    {
+        printf("Could not create JSON object: arrayItem\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+       }
+    cJSON_AddItemToArray(faultNotificationDelayPeriod, arrayItem);
+
+    cJSON *vesEndPointDetails = cJSON_CreateObject();
+    if (vesEndPointDetails == NULL)
+    {
+        printf("Could not create JSON object: vesEndPointDetails\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+    cJSON_AddItemToObject(configObject, "ves-endpoint-details", vesEndPointDetails);
+
+    if (cJSON_AddStringToObject(vesEndPointDetails, "ves-endpoint-ip", "172.17.0.1") == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-ip\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddNumberToObject(vesEndPointDetails, "ves-endpoint-port", 30007) == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-port\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddStringToObject(vesEndPointDetails, "ves-endpoint-auth-method", "no-auth") == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-auth-method\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddStringToObject(vesEndPointDetails, "ves-endpoint-username", "") == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-username\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddStringToObject(vesEndPointDetails, "ves-endpoint-password", "") == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-password\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddStringToObject(vesEndPointDetails, "ves-endpoint-certificate", "") == NULL)
+    {
+        printf("Could not create JSON object: ves-endpoint-certificate\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddFalseToObject(vesEndPointDetails, "ves-registration") == NULL)
+    {
+        printf("Could not create JSON object: ves-registration\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddNumberToObject(configObject, "ssh-connections", 1) == NULL)
+    {
+        printf("Could not create JSON object: ssh-connections\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    if (cJSON_AddNumberToObject(configObject, "tls-connections", 0) == NULL)
+    {
+        printf("Could not create JSON object: tls-connections\n");
+        cJSON_Delete(configObject);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    char *config_string = NULL;
+
+    config_string = cJSON_PrintUnformatted(configObject);
+
+    writeConfigFile(config_string);
+
+    if (config_string != NULL)
+    {
+        free(config_string);
+        config_string = NULL;
+    }
+
+    if (configObject != NULL)
+    {
+        cJSON_Delete(configObject);
+    }
+
+    return SR_ERR_OK;
+}
+
+int getIntFromString(char *string, int def_value)
+{
+    int rc, value = def_value;
+    if (string != NULL)
+    {
+        rc = sscanf(string, "%d", &value);
+        if (rc != 1)
+        {
+            printf("Could not get the %s! Using the default 0...\n", string);
+            value = def_value;
+        }
+    }
+    return value;
+}
+
+int     getSshConnectionsFromConfigJson(void)
+{
+    char *stringConfig = readConfigFileInString();
+
+    if (stringConfig == NULL)
+    {
+        printf("Could not read JSON configuration file in string.");
+        return 0;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfig);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfig);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfig);
+    stringConfig = NULL;
+
+    cJSON *sshConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "ssh-connections");
+    if (!cJSON_IsNumber(sshConnections))
+    {
+        printf("Configuration JSON is not as expected: ssh-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    int num_of_ssh = (int)(sshConnections->valuedouble);
+
+    cJSON_Delete(jsonConfig);
+
+    return num_of_ssh;
+}
+
+int     getTlsConnectionsFromConfigJson(void)
+{
+    char *stringConfig = readConfigFileInString();
+
+    if (stringConfig == NULL)
+    {
+        printf("Could not read JSON configuration file in string.");
+        return 0;
+    }
+
+    cJSON *jsonConfig = cJSON_Parse(stringConfig);
+    if (jsonConfig == NULL)
+    {
+        free(stringConfig);
+        const char *error_ptr = cJSON_GetErrorPtr();
+        if (error_ptr != NULL)
+        {
+            fprintf(stderr, "Could not parse JSON configuration! Error before: %s\n", error_ptr);
+        }
+        return SR_ERR_OPERATION_FAILED;
+    }
+    //we don't need the string anymore
+    free(stringConfig);
+    stringConfig = NULL;
+
+    cJSON *tlsConnections = cJSON_GetObjectItemCaseSensitive(jsonConfig, "tls-connections");
+    if (!cJSON_IsNumber(tlsConnections))
+    {
+        printf("Configuration JSON is not as expected: ssh-connections is not an object");
+        cJSON_Delete(jsonConfig);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    int num_of_tls = (int)(tlsConnections->valuedouble);
+
+    cJSON_Delete(jsonConfig);
+
+    return num_of_tls;
+}
index 29d69f8..09d7e02 100644 (file)
@@ -241,7 +241,7 @@ static int send_pnf_registration_instance(char *hostname, int port, bool is_tls)
        return SR_ERR_OK;
 }
 
-static void pnf_registration(void)
+static void *pnf_registration(void *arg)
 {
        // delay the PNF Registration VES message, until anything else is initialized
        printf("delay the PNF Registration VES message, until anything else is initialized");
@@ -253,25 +253,17 @@ static void pnf_registration(void)
        {
                //ves-registration object is set to False, we do not make an automatic PNF registration
                printf("ves-registration object is set to False, we do not make an automatic PNF registration");
-               return;
+               return NULL;
        }
 
        int rc = SR_ERR_OK, netconf_port_base = 0;
-       char *netconf_base_string = getenv("NETCONF_BASE");
        char *hostname_string = getenv("HOSTNAME");
+    int port = 0;
 
-       if (netconf_base_string != NULL)
-       {
-               rc = sscanf(netconf_base_string, "%d", &netconf_port_base);
-               if (rc != 1)
-               {
-                       printf("Could not find the NETCONF base port, aborting the PNF registration...\n");
-                       return;
-               }
-       }
+    netconf_port_base = getIntFromString(getenv("NETCONF_BASE"), 0);
 
        //TODO This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections
-       for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE - 3; ++port)
+       for (int i = 0; i < SSH_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
                pthread_mutex_lock(&lock);
                rc = send_pnf_registration_instance(hostname_string, netconf_port_base + port, FALSE);
@@ -281,7 +273,7 @@ static void pnf_registration(void)
                }
                pthread_mutex_unlock(&lock);
        }
-       for (int port = NETCONF_CONNECTIONS_PER_DEVICE - 3; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port)
+       for (int i = 0; port < TLS_CONNECTIONS_PER_DEVICE; ++port, ++i)
        {
                pthread_mutex_lock(&lock);
                rc = send_pnf_registration_instance(hostname_string, netconf_port_base + port, TRUE);
@@ -292,7 +284,7 @@ static void pnf_registration(void)
                }
        }
 
-       return;
+       return NULL;
 }
 
 int
index 5f1b481..46fa4de 100644 (file)
@@ -1,6 +1,8 @@
 <simulator-config xmlns="urn:onf:params:xml:ns:yang:network-topology-simulator">
        <simulated-devices>0</simulated-devices>
        <mounted-devices>0</mounted-devices>
+    <ssh-connections>1</ssh-connections>
+    <tls-connections>0</tls-connections>
        <notification-config>
                <fault-notification-delay-period>0</fault-notification-delay-period>
                <ves-heartbeat-period>0</ves-heartbeat-period>
index 1bc43cb..766a3ef 100644 (file)
@@ -16,6 +16,12 @@ module network-topology-simulator {
   description
     "This module contains a collection of YANG definitions for managing the Network Topology Simulator.";
 
+  revision 2020-04-22 {
+    description
+      "Add configuration for number of SSH and TLS connections exposed by each simulated device.";
+    reference
+      "O-RAN SC SIM project";
+  }
   revision 2020-04-13 {
     description
       "Change fault-notification-delay-period to leaf-list.";
@@ -188,6 +194,10 @@ module network-topology-simulator {
   }
 
   container simulator-config {
+    must "./ssh-connections + ./tls-connections <= 100" {
+      error-message "The total number of connections (SSH + TLS) needs to be less than or equal with 100.";
+    }
+    // presence "Enables NTS configuration.";
     description
       "Configuration container of the simulator.";
     leaf simulated-devices {
@@ -198,10 +208,27 @@ module network-topology-simulator {
     }
     leaf mounted-devices {
       type uint32;
+      must ". <= ../simulated-devices" {
+          error-message "The number of mounted devices cannot be greater that the number of simulated devices";
+      }
       default "0";
       description
         "The number of devices to be mounted in ODL. The configured number should not exceed the number of mounted devices.";
     }
+    leaf ssh-connections {
+      when "../simulated-devices = 0";
+      type uint32;
+      default "1";
+      description
+        "The number of SSH connections to be exposed by each simulated device.";
+    }
+    leaf tls-connections {
+    when "../simulated-devices = 0";
+      type uint32;
+      default "0";
+      description
+        "The number of TLS connections to be exposed by each simulated device.";
+    }
     container notification-config {
       leaf-list fault-notification-delay-period {
         type uint32;