Dockerize rest API for ICE tests 91/35791/3
authorMickael JEZEQUEL <mickael.jezequel@orange.com>
Fri, 9 Mar 2018 16:44:34 +0000 (17:44 +0100)
committerMickael JEZEQUEL <mickael.jezequel@orange.com>
Thu, 15 Mar 2018 12:45:50 +0000 (13:45 +0100)
Change-Id: I8928203bb76a20fb7d10fd05d06151e2c6b7a934
Issue-ID: VNFSDK-214
Signed-off-by: Mickael JEZEQUEL <mickael.jezequel@orange.com>
12 files changed:
docker/README.MD [new file with mode: 0644]
docker/pom.xml [new file with mode: 0644]
docker/src/main/docker/Dockerfile [new file with mode: 0644]
docker/src/main/docker/prod_settings.cfg [new file with mode: 0644]
docker/src/main/docker/run.sh [new file with mode: 0644]
ice-server/heat_test/app.py
ice-server/heat_test/default_settings.cfg [new file with mode: 0644]
ice-server/heat_test/default_settings.py [deleted file]
ice-server/heat_test/heat_validator.py
ice-server/heat_test/test/fixture/heat_template_empty.zip [moved from ice-server/heat_test/test/fixture/test.zip with 100% similarity]
ice-server/heat_test/test/fixture/heat_template_ok.zip [new file with mode: 0644]
pom.xml

diff --git a/docker/README.MD b/docker/README.MD
new file mode 100644 (file)
index 0000000..26a793b
--- /dev/null
@@ -0,0 +1,24 @@
+Introduction:
+=============
+This document provides the required steps for :
+- generating the docker image of the heat validation rest service
+- running the rest server.
+
+Installation steps:
+====================
+Install following software:
+- maven
+- docker
+
+Configuration steps:
+====================
+you can override the defaults settings (declared in default_settings.cfg and prod_settings.cfg)
+by setting the env variable with the appropriate values (see Dockerfile for available ENV vars)
+
+How to run?
+===========
+- make sure that the MSB is running
+- build the image : 
+- ``$ mvn -P docker clean package``
+- run the server in DEBUG mode:
+- ``$ docker run --rm --name vnfsdk-ice -d -p 5000:5000 -e DEBUG=True -e MSB_ADDR=<MSB ADDR> -e MSB_PORT=80 onap/vnfsdk/ice``
diff --git a/docker/pom.xml b/docker/pom.xml
new file mode 100644 (file)
index 0000000..ad876b4
--- /dev/null
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2018 Orange. All rights reserved.
+
+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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+         http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.oparent</groupId>
+        <artifactId>oparent</artifactId>
+        <version>0.1.1</version>
+        <relativePath>../../oparent</relativePath>
+    </parent>
+
+    <groupId>org.onap.vnfsdk.ice</groupId>
+    <artifactId>vnf-sdk-ice-docker</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <name>ice docker image builder</name>
+    <description>heat validation docker image builder</description>
+    <packaging>pom</packaging>
+
+    <properties>
+        <maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
+        <docker.push.registry></docker.push.registry>
+        <skip.docker.build>true</skip.docker.build>
+        <skip.docker.tag>true</skip.docker.tag>
+        <skip.docker.push>true</skip.docker.push>
+        <docker.skip>false</docker.skip>
+        <docker.skip.build>false</docker.skip.build>
+    </properties>
+    <profiles>
+        <profile>
+            <id>docker</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>io.fabric8</groupId>
+                        <artifactId>docker-maven-plugin</artifactId>
+                        <version>0.16.7</version>
+                        <configuration>
+                            <verbose>true</verbose>
+                            <apiVersion>1.23</apiVersion>
+                            <skipDocker>${docker.skip}</skipDocker>
+                            <images>
+                                <image>
+                                    <name>onap/vnfsdk/ice</name>
+                                    <alias>ice</alias>
+                                    <build>
+                                        <cleanup>try</cleanup>
+                                        <dockerFileDir>${project.basedir}/src/main/docker</dockerFileDir>
+                                        <assembly>
+                                            <mode>dir</mode>
+                                            <inline xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+                                                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                                                    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+                                                <id>middleware-rest</id>
+                                                <fileSet>
+                                                    <directory>${project.basedir}/../ice-server</directory>
+                                                    <includes>
+                                                        <include>requirements.txt</include>
+                                                        <include>README.MD</include>
+                                                    </includes>
+                                                    <outputDirectory>ice-server</outputDirectory>
+                                                </fileSet>
+                                                <fileSet>
+                                                    <directory>${project.basedir}/../ice-server/heat_test</directory>
+                                                    <excludes>
+                                                        <exclude>**/*.pyc</exclude>
+                                                        <exclude>**/__pycache__</exclude>
+                                                    </excludes>
+                                                    <outputDirectory>ice-server/heat_test</outputDirectory>
+                                                </fileSet>
+                                                <fileSet>
+                                                    <directory>${project.basedir}/../validation-scripts</directory>
+                                                    <includes>
+                                                        <include>requirements.txt</include>
+                                                        <include>README.MD</include>
+                                                    </includes>
+                                                    <outputDirectory>validation-scripts</outputDirectory>
+                                                </fileSet>
+                                                <fileSet>
+                                                    <directory>${project.basedir}/../validation-scripts/ice_validator</directory>
+                                                    <excludes>
+                                                        <exclude>**/*.pyc</exclude>
+                                                        <exclude>**/__pycache__</exclude>
+                                                    </excludes>
+                                                    <outputDirectory>validation-scripts/ice_validator</outputDirectory>
+                                                </fileSet>
+                                            </inline>
+                                        </assembly>
+                                    </build>
+                                </image>
+                            </images>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>clean-images</id>
+                                <phase>pre-clean</phase>
+                                <goals>
+                                    <goal>remove</goal>
+                                </goals>
+                                <configuration>
+                                    <removeAll>true</removeAll>
+                                    <image>onap/vnfsdk/ice</image>
+                                </configuration>
+                            </execution>
+
+                            <execution>
+                                <id>generate-images</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>build</goal>
+                                </goals>
+                                <configuration>
+                                    <skipDockerBuild>${docker.skip.build}</skipDockerBuild>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>push-images</id>
+                                <phase>deploy</phase>
+                                <goals>
+                                    <goal>build</goal>
+                                    <goal>push</goal>
+                                </goals>
+                                <configuration>
+                                    <image>onap/vnfsdk/ice</image>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/docker/src/main/docker/Dockerfile b/docker/src/main/docker/Dockerfile
new file mode 100644 (file)
index 0000000..7b3f033
--- /dev/null
@@ -0,0 +1,29 @@
+FROM python:3.6.1
+
+ENV ICE_SETTINGS /opt/ice/ice-server/heat_test/prod_settings.cfg
+ENV DEBUG False
+ENV MSB_ADDR "127.0.0.1"
+ENV MSB_PORT 80
+
+# add application
+COPY maven/ /opt/ice
+COPY prod_settings.cfg /opt/ice/ice-server/heat_test/
+COPY run.sh /opt/ice/ice-server/heat_test/
+
+EXPOSE 5000
+
+# install requirements
+# Create the group and user to be used in this container
+RUN pip install -r /opt/ice/ice-server/requirements.txt &&\
+    pip install -r /opt/ice/validation-scripts/requirements.txt &&\
+    pip install dumb-init &&\
+    groupadd flaskgroup && useradd -m -g flaskgroup -s /bin/bash flask &&\
+    chown -R flask:flaskgroup /opt/ice &&\
+    chmod +x /opt/ice/ice-server/heat_test/*.sh
+
+USER flask
+WORKDIR /opt/ice/ice-server/heat_test
+# use dumb-init to translate SIGTERM to SIGINT
+# this is needed to gracefully stop flask (and unregister service properly)
+ENTRYPOINT ["dumb-init", "--rewrite", "15:2", "--"]
+CMD ["./run.sh"]
diff --git a/docker/src/main/docker/prod_settings.cfg b/docker/src/main/docker/prod_settings.cfg
new file mode 100644 (file)
index 0000000..f623d76
--- /dev/null
@@ -0,0 +1,8 @@
+# ICE production settings
+DEBUG = False
+
+# MSB production settings
+MSB_ADDR = "127.0.0.1"
+MSB_PORT = "80"
+MSB_URL = "http://%s:%s/api/microservices/v1/services" % (MSB_ADDR, MSB_PORT)
+
diff --git a/docker/src/main/docker/run.sh b/docker/src/main/docker/run.sh
new file mode 100644 (file)
index 0000000..662c8cf
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sed -i "s/DEBUG =.*/DEBUG = ${DEBUG}/g" ${ICE_SETTINGS}
+sed -i "s/MSB_ADDR =.*/MSB_ADDR = \"${MSB_ADDR}\"/g" ${ICE_SETTINGS}
+sed -i "s/MSB_PORT =.*/MSB_PORT = \"${MSB_PORT}\"/g" ${ICE_SETTINGS}
+
+/usr/local/bin/python app.py
\ No newline at end of file
index c61150a..97c32a9 100644 (file)
@@ -1,18 +1,19 @@
 #!flask/bin/python
-import argparse
+import atexit
 import logging
-import requests
 
 import connexion
+import requests
 from connexion.resolver import RestyResolver
 
+config = ''
 
 def create_app():
     logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
     app = connexion.App(__name__, specification_dir='swagger/')
 
     # load default config
-    app.app.config.from_object("default_settings")
+    app.app.config.from_pyfile("default_settings.cfg")
     app.app.config.from_envvar('ICE_SETTINGS', silent=True)
     app.add_api('ice_api.yaml', swagger_ui=app.app.config['DEBUG'], resolver=RestyResolver('ice_validator'))
 
@@ -32,15 +33,51 @@ def start_app(app):
     logging.info("######################################")
     logging.info("starting server")
     logging.info("######################################")
+    global config
+    config = app.app.config
+    msb_register()
+    atexit.register(msb_unregister)
     app.run(port=app.app.config['ICE_PORT'], debug=app.app.config['DEBUG'])
 
-    # register service in MSB
+
+def msb_register():
+    try:
+        msb_url = config['MSB_URL']
+        ice_json = {
+            "serviceName": config['ICE_SERVICE_NAME'],
+            "version": config['ICE_VERSION'],
+            "url": "/onapapi/ice/v1",
+            "protocol": "REST",
+            "visualRange": "1",
+            "nodes": [
+                {
+                    "ip": config['ICE_ADDR'],
+                    "port": config['ICE_PORT'],
+                    "ttl": 0
+                }
+            ]
+        }
+        resp = requests.post(msb_url, json=ice_json)
+        if resp.status_code == 201:
+            global registered
+            registered = True
+            logging.info("registration to '%s' done", msb_url)
+        else:
+            logging.info("registration to '%s' failed; status_code = '%s'", msb_url, resp.status_code)
+    except:
+        logging.info("registration to '%s' failed", msb_url)
+
+
+def msb_unregister():
     try:
-        msb_url = app.app.config['MSB_URL']
-        requests.get(msb_url)
-        logging.info("registration to %s done", msb_url)
+        msb_url = "%s/%s/version/%s" % (config['MSB_URL'], config['ICE_SERVICE_NAME'], config['ICE_VERSION'])
+        resp = requests.delete(msb_url)
+        if resp.status_code == 200:
+            logging.info("unregistration from '%s' done", msb_url)
+        else:
+            logging.info("unregistration from '%s' failed; status_code = '%s'", msb_url, resp.status_code)
     except:
-        logging.info("registration to %s failed", msb_url)
+        logging.info("unregistration from '%s' failed", msb_url)
 
 
 if __name__ == '__main__':
diff --git a/ice-server/heat_test/default_settings.cfg b/ice-server/heat_test/default_settings.cfg
new file mode 100644 (file)
index 0000000..3721bbf
--- /dev/null
@@ -0,0 +1,13 @@
+# ICE settings
+DEBUG = True
+ICE_ADDR = "127.0.0.1"
+ICE_PORT = 5000
+ICE_SCRIPT_PATH = '../../validation-scripts/ice_validator'
+ICE_VERSION = "v1"
+ICE_SERVICE_NAME = "vnfsdk-ice"
+
+# MSB settings
+MSB_ADDR = "127.0.0.1"
+MSB_PORT = "80"
+MSB_URL = "http://%s:%s/api/microservices/v1/services" % (MSB_ADDR, MSB_PORT)
+
diff --git a/ice-server/heat_test/default_settings.py b/ice-server/heat_test/default_settings.py
deleted file mode 100644 (file)
index d32d039..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# ICE settings
-DEBUG = True
-ICE_PORT = 5000
-
-# MSB settings
-MSB_IP = "127.0.0.1"
-MSB_PORT = "80"
-MSB_URL = "http://"+MSB_IP+':'+MSB_PORT+"/api/microservices/v1/services"
-
index 0cc32a1..d76d275 100644 (file)
@@ -7,7 +7,7 @@ import zipfile
 from io import StringIO
 
 import pytest
-from flask import (request, jsonify, abort)
+from flask import (request, jsonify, abort, current_app)
 
 
 class HeatValidator(object):
@@ -49,7 +49,8 @@ class HeatValidator(object):
                 original_output = sys.stdout
                 # Assign StringIO so the output is not sent anymore to the console
                 sys.stdout = StringIO()
-            exit_code = pytest.main(['../../validation-scripts/ice_validator',
+            script_path = current_app.config['ICE_SCRIPT_PATH']
+            exit_code = pytest.main([script_path,
                                      '--resultlog=' + tmp_dir + '/result.txt',
                                      '--template-dir', tmp_dir])
             with open(tmp_dir + '/result.txt', 'r') as result_file:
@@ -62,7 +63,7 @@ class HeatValidator(object):
         except zipfile.BadZipFile:
             logging.exception("invalid file")
             abort(422, {'status': 4, 'message': 'invalid file'})
-        except:
+        except Exception as e:
             logging.exception("server error on file")
             abort(500, {'status': 3, 'message': 'server error'})
         finally:
diff --git a/ice-server/heat_test/test/fixture/heat_template_ok.zip b/ice-server/heat_test/test/fixture/heat_template_ok.zip
new file mode 100644 (file)
index 0000000..4e89aba
Binary files /dev/null and b/ice-server/heat_test/test/fixture/heat_template_ok.zip differ
diff --git a/pom.xml b/pom.xml
index 0a941ea..f15eca9 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@ under the License.
     <parent>
         <groupId>org.onap.oparent</groupId>
         <artifactId>oparent</artifactId>
-        <version>1.0.0-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../oparent</relativePath>
     </parent>
 
@@ -33,5 +33,6 @@ under the License.
     <modules>
         <module>validation-scripts</module>
         <module>ice-server</module>
+       <module>docker</module>
     </modules>
 </project>