OpenMTC/create-app-structure
2018-10-14 17:03:08 +02:00

544 lines
14 KiB
Bash
Executable File

#!/usr/bin/env bash
# OS relevant options
case "${OSTYPE}" in
"linux-gnu")
MD5_PROG="md5sum"
;;
"darwin")
MD5_PROG="md5 -r"
;;
*)
echo "OS type '${OSTYPE}' not supported. Exiting now!"
exit 1
;;
esac
print_help () {
cat <<EOM
Usage: $0 [-w] [-d] [-i] [-a <APP_SCRIPT>] APP_NAME
APP_NAME Name of the app, used as folder and class name.
-a <APP_SCRIPT> If not provided, it will be created automatically by
converting the APP_NAME from camel case to snake case.
If APP_NAME or APP_SCRIPT ends with IPE or similar, it
will be assumed as IPE and will be created under ipes.
-w if true, FlaskRunner is used and basic index.html is
created
-i if true, IN-AE is expected and default endpoint is
configured to backend
-d if true, no setup file and docker files will be created
EOM
}
optspec=":wdia:"
WEB_APP="false"
IN_AE="false"
NO_DOCKER="false"
while getopts "${optspec}" optchar; do
case "${optchar}" in
w)
WEB_APP="true"
;;
i)
IN_AE="true"
;;
d)
NO_DOCKER="true"
;;
a)
if [[ ${OPTARG} == -* ]]; then
print_help
exit 1
fi
APP_SCRIPT=${OPTARG}
;;
\?|:)
print_help
exit 1
esac
done
shift $((OPTIND-1))
if [ $# -ne 1 ]; then
print_help
exit 1
fi
# set variables
APP_NAME="$1"
APP_SCRIPT=${APP_SCRIPT-$(printf "${APP_NAME}" | \
perl -p -e 's/([a-z0-9])([A-Z]+)/\1-\L\2/g' | \
perl -p -e 's/^([A-Z])/\l$1/g')}
MOD_NAME=$(printf "${APP_SCRIPT}" | tr "-" "_" | sed 's/.*/\L&/g')
PKG_NAME=$(printf "${APP_SCRIPT}" | tr -d "-" | sed 's/.*/\L&/g')
if [[ ${PKG_NAME} == *"ipe" ]]; then
APPS_FOLDER="ipes"
else
APPS_FOLDER="apps"
fi
APP_FOLDER="${APPS_FOLDER}/${APP_NAME}"
# check if existing
if [ -e "${APP_FOLDER}" ]; then
printf "App folder already existing. Aborting.\n"
exit 1
fi
# check if APP_NAME and APP_SCRIPT are the same. Testing lowercase for case-insensitive filesystems
if [ "${APP_NAME,,}" == "${APP_SCRIPT,,}" ]; then
echo "APP_NAME and APP_SCRIPT shouldn't be the same, specially in case-insensitive systems. Aborting\n"
exit 1
fi
# change to root folder
cd "$(dirname ${0})"
# set port suffix
APP_PORT_SUFFIX=$(printf %04d $((0x$(${MD5_PROG} <<< "${APP_NAME}" | cut -c1-4) % 10000)))
################################################################################
# creating module files
mkdir -p "${APP_FOLDER}"
SRC_FOLDER="${APP_FOLDER}/src/${PKG_NAME}"
mkdir -p "${SRC_FOLDER}"
# init file
cat > "${SRC_FOLDER}/__init__.py" << EOF
"""
TODO: Add description here
"""
__version__ = "ADD-VERSION-HERE"
__description__ = "${APP_NAME}"
__author_name__ = "ADD_AUTHOR_HERE"
__author_mail__ = "ADD_MAIL_HERE"
__requires__ = []
EOF
# main file
MAIN_MODULE="${SRC_FOLDER}/__main__.py"
cat > "${MAIN_MODULE}" << EOF
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
from openmtc_app.util import prepare_app, get_value
from openmtc_app.flask_runner import FlaskRunner as Runner
from .${MOD_NAME} import ${APP_NAME}
# defaults
default_name = "${APP_NAME}"
default_ep = "http://localhost:8000"
# args parser
parser = ArgumentParser(
description="An IPE called ${APP_NAME}",
prog="${APP_NAME}",
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument("-n", "--name", help="Name used for the AE.")
parser.add_argument("-s", "--ep", help="URL of the local Endpoint.")
# args, config and logging
args, config = prepare_app(parser, __loader__, __name__, "config.json")
# variables
nm = get_value("name", (unicode, str), default_name, args, config)
cb = config.get("cse_base", "onem2m")
ep = get_value("ep", (unicode, str), default_ep, args, config)
poas = config.get("poas", ["http://auto:2${APP_PORT_SUFFIX}"])
originator_pre = config.get("originator_pre", "//openmtc.org/mn-cse-1")
ssl_certs = config.get("ssl_certs", {})
port = int(config.get("port", 1${APP_PORT_SUFFIX}))
# start
app = ${APP_NAME}(
name=nm, cse_base=cb, poas=poas,
originator_pre=originator_pre, **ssl_certs
)
Runner(app, port=port).run(ep)
print ("Exiting....")
EOF
if [ ${WEB_APP} == "false" ]; then
perl -i -p -e 's/flask_runner/runner/' "${MAIN_MODULE}"
perl -i -p -e 's/FlaskRunner/AppRunner/' "${MAIN_MODULE}"
perl -i -p -e 's/app, port=port/app/' "${MAIN_MODULE}"
perl -i -n -e 'print unless /port = int\(/' "${MAIN_MODULE}"
fi
if [ ${IN_AE} == "true" ]; then
perl -i -p -e 's/mn-cse-1/in-cse-1/' "${MAIN_MODULE}"
perl -i -p -e 's/localhost:8000/localhost:18000/' "${MAIN_MODULE}"
fi
# main module
cat > "${SRC_FOLDER}/${MOD_NAME}.py" << EOF
from openmtc_app.onem2m import XAE
class ${APP_NAME}(XAE):
interval = 10
def _on_register(self):
# start endless loop
self.run_forever(self.interval)
EOF
# index html if web app
if [ ${WEB_APP} == "true" ]; then
mkdir -p "${SRC_FOLDER}/static"
cat > "${SRC_FOLDER}/static/index.html" << EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Hello World!
</body>
</html>
EOF
fi
################################################################################
# creating config files
mkdir -p "${APP_FOLDER}/etc/conf"
# main config
MAIN_CONFIG="${APP_FOLDER}/config.json"
cat > "${MAIN_CONFIG}" << EOF
{
"name": "${APP_NAME}",
"ep": "http://localhost:8000",
"cse_base": "onem2m",
"poas": [
"http://auto:2${APP_PORT_SUFFIX}"
],
"originator_pre": "//openmtc.org/mn-cse-1",
"ssl_certs": {
"cert_file": null,
"key_file": null,
"ca_certs": null
},
"port": 1${APP_PORT_SUFFIX},
"logging": {
"level": "ERROR",
"file": null
}
}
EOF
# dist config
DIST_CONFIG="${APP_FOLDER}/etc/conf/config.json.dist"
cat > "${DIST_CONFIG}" << EOF
{
"name": "${APP_NAME}",
"ep": "http://localhost:8000",
"cse_base": "onem2m",
"poas": [
"http://auto:2${APP_PORT_SUFFIX}"
],
"originator_pre": "//openmtc.org/mn-cse-1",
"ssl_certs": {
"cert_file": "/etc/openmtc/certs/${PKG_NAME}.cert.pem",
"key_file": "/etc/openmtc/certs/${PKG_NAME}.key.pem",
"ca_certs": "/etc/openmtc/certs/ca-chain.cert.pem"
},
"port": 1${APP_PORT_SUFFIX},
"logging": {
"level": "INFO",
"file": "/var/log/openmtc/${PKG_NAME}.log"
}
}
EOF
if [ ${WEB_APP} == "false" ]; then
perl -i -n -e 'print unless /"port": 1/' "${MAIN_CONFIG}"
perl -i -n -e 'print unless /"port": 1/' "${DIST_CONFIG}"
fi
if [ ${IN_AE} == "true" ]; then
perl -i -p -e 's/mn-cse-1/in-cse-1/' "${MAIN_CONFIG}"
perl -i -p -e 's/localhost:8000/localhost:18000/' "${MAIN_CONFIG}"
perl -i -p -e 's/mn-cse-1/in-cse-1/' "${DIST_CONFIG}"
perl -i -p -e 's/localhost:8000/localhost:18000/' "${DIST_CONFIG}"
fi
################################################################################
# create start script
START_SCRIPT="${APPS_FOLDER}/${APP_SCRIPT}"
cat > "${START_SCRIPT}" << EOF
#!/usr/bin/env bash
cd \$(dirname \${0})
. ./prep-env.sh
cd ${APP_NAME}
PYTHONPATH=\${PYTHONPATH}:src exec python3 -m ${PKG_NAME} \$@
EOF
chmod +x "${START_SCRIPT}"
################################################################################
# create bin script
mkdir -p "${APP_FOLDER}/bin"
BIN_SCRIPT="${APP_FOLDER}/bin/openmtc-${APP_SCRIPT}"
cat > "${BIN_SCRIPT}" << EOF
#!/usr/bin/env bash
exec python3 -m ${PKG_NAME} \$@
EOF
chmod +x "${BIN_SCRIPT}"
################################################################################
# create systemd unit file
SYSTEMD_FOLDER="${APP_FOLDER}/etc/systemd/system"
mkdir -p ${SYSTEMD_FOLDER}
cat > "${SYSTEMD_FOLDER}/openmtc-${PKG_NAME}.service" << EOF
[Unit]
Description=OpenMTC ${APP_NAME}
After=network.target
Wants=ntp.service
[Service]
ExecStart=/usr/local/bin/${APP_SCRIPT}
[Install]
WantedBy=multi-user.target
EOF
################################################################################
# return here if docker is not needed
if [ ${NO_DOCKER} == "true" ]; then
exit 0
fi
################################################################################
# create setup file
SETUP_FILE="${APP_FOLDER}/setup-${PKG_NAME}.py"
cat > "${SETUP_FILE}" << EOF
#!/usr/bin/env python3
from setuptools import setup
from distutils.core import setup
from glob import glob
import sys
from utils import get_packages, get_pkg_files, OpenMTCSdist, move_config_files
# name and dir
NAME = "${PKG_NAME}"
BASE_DIR = "."
# import pkg
sys.path.append(BASE_DIR + "/src")
pkg = __import__(NAME)
# setup name and version
SETUP_NAME = "openmtc-" + NAME
SETUP_VERSION = pkg.__version__
SETUP_DESCRIPTION = pkg.__description__
# meta
SETUP_AUTHOR = pkg.__author_name__
SETUP_AUTHOR_EMAIL = pkg.__author_mail__
SETUP_URL = "http://www.openmtc.org"
SETUP_LICENSE = "Fraunhofer FOKUS proprietary"
# requirements
SETUP_REQUIRES = pkg.__requires__
SETUP_INSTALL_REQUIRES = pkg.__requires__
# packages
PACKAGES = [NAME]
PACKAGE_DIR = {"": BASE_DIR + "/src"}
all_packages = []
for package in PACKAGES:
all_packages.extend(get_packages(package, PACKAGE_DIR))
# scripts
SETUP_SCRIPTS = glob(BASE_DIR + "/bin/*")
# package data
PACKAGE_DATA = {NAME: get_pkg_files(BASE_DIR, NAME)}
# data files
CONFIG_FILES = ("config.json",)
CONFIG_DIR = "/etc/openmtc/" + NAME
CONFIG_DIST_FILES = (BASE_DIR + "/etc/conf/config.json.dist",)
DATA_FILES = [(CONFIG_DIR, CONFIG_DIST_FILES)]
# cmd class
CMD_CLASS = {'sdist': OpenMTCSdist}
if __name__ == "__main__":
if 'bdist_wheel' in sys.argv:
raise RuntimeError("This setup.py does not support wheels")
############################################################################
# setup
setup(name=SETUP_NAME,
version=SETUP_VERSION,
description=SETUP_DESCRIPTION,
author=SETUP_AUTHOR,
author_email=SETUP_AUTHOR_EMAIL,
url=SETUP_URL,
license=SETUP_LICENSE,
requires=SETUP_REQUIRES,
install_requires=SETUP_INSTALL_REQUIRES,
package_dir=PACKAGE_DIR,
packages=all_packages,
scripts=SETUP_SCRIPTS,
package_data=PACKAGE_DATA,
data_files=DATA_FILES,
cmdclass=CMD_CLASS
)
############################################################################
# install
if "install" in sys.argv:
# only do this during install
move_config_files(CONFIG_DIR, CONFIG_FILES)
EOF
chmod +x "${SETUP_FILE}"
# copy needed helper files
cp MANIFEST.in utils.py "${APP_FOLDER}/."
################################################################################
# create docker files
DOCKER_FOLDER="${APP_FOLDER}/docker"
mkdir -p ${DOCKER_FOLDER}
# create configure script
DOCKER_SCRIPT="${DOCKER_FOLDER}/configure-${PKG_NAME}-and-start"
cat > "${DOCKER_SCRIPT}" << EOF
#!/usr/bin/env bash
CONFIG_FILE="/etc/openmtc/${PKG_NAME}/config.json"
NAME=\${NAME-"${APP_NAME}"}
EP=\${EP-"http://localhost:8000"}
CSE_BASE=\${CSE_BASE-"onem2m"}
POAS=\${POAS-'["http://auto:2${APP_PORT_SUFFIX}"]'}
ORIGINATOR_PRE=\${ORIGINATOR_PRE-"//openmtc.org/mn-cse-1"}
SSL_CRT=\${SSL_CRT-"/etc/openmtc/certs/${PKG_NAME}.cert.pem"}
SSL_KEY=\${SSL_KEY-"/etc/openmtc/certs/${PKG_NAME}.key.pem"}
SSL_CA=\${SSL_CA-"/etc/openmtc/certs/ca-chain.cert.pem"}
PORT=\${PORT-"1${APP_PORT_SUFFIX}"}
# defaults logging
LOGGING_FILE=\${LOGGING_FILE-"/var/log/openmtc/${PKG_NAME}.log"}
LOGGING_LEVEL=\${LOGGING_LEVEL-"ERROR"}
# ensure correct level
case \${LOGGING_LEVEL} in
FATAL|ERROR|WARN|INFO|DEBUG)
;;
*)
LOGGING_LEVEL="ERROR"
;;
esac
# local ip
LOCAL_IP=\$(ip r get 8.8.8.8 | awk 'NR==1 {print \$NF}')
# set hostname
HOST_NAME=\${EXTERNAL_IP-\${LOCAL_IP}}
# Configuration of the service.
CONFIG_TEMP=\${CONFIG_FILE}".tmp"
echo -n "Configuring M2M ${PKG_NAME}..."
JQ_STRING='.'
# basics
JQ_STRING=\${JQ_STRING}' |
.name = "'\${NAME}'" |
.ep = "'\${EP}'" |
.cse_base = "'\${CSE_BASE}'" |
.poas = '\${POAS}' |
.originator_pre = "'\${ORIGINATOR_PRE}'" |
.ssl_certs.cert_file = "'\${SSL_CRT}'" |
.ssl_certs.key_file = "'\${SSL_KEY}'" |
.ssl_certs.ca_certs = "'\${SSL_CA}'" |
.port = "'\${PORT}'" |
.logging.file |= "'\${LOGGING_FILE}'" |
.logging.level |= "'\${LOGGING_LEVEL}'"
'
cat \${CONFIG_FILE} | jq -M "\${JQ_STRING}"> \${CONFIG_TEMP}
mv \${CONFIG_TEMP} \${CONFIG_FILE}
echo "done"
exec python3 -m ${PKG_NAME} \$@
EOF
if [ ${WEB_APP} == "false" ]; then
perl -i -n -e 'print unless /PORT=/' "${DOCKER_SCRIPT}"
perl -i -n -e 'print unless /.port =/' "${DOCKER_SCRIPT}"
fi
if [ ${IN_AE} == "true" ]; then
perl -i -p -e 's/mn-cse-1/in-cse-1/' "${DOCKER_SCRIPT}"
perl -i -p -e 's/localhost:8000/localhost:18000/' "${DOCKER_SCRIPT}"
fi
chmod +x "${DOCKER_SCRIPT}"
# create docker files
DOCKER_FILE_AMD64="${DOCKER_FOLDER}/${PKG_NAME}-amd64"
DOCKER_FILE_ARM="${DOCKER_FOLDER}/${PKG_NAME}-arm"
cat > "${DOCKER_FILE_AMD64}" << EOF
############################################################
# Dockerfile to run openmtc ${PKG_NAME} binary
############################################################
# Set the base image to use openmtc/sdk
FROM openmtc/sdk-amd64:latest
ENV MOD_NAME=${PKG_NAME}
# Set the file maintainer
MAINTAINER rst
# install openmtc dependencies
COPY tmp/\$MOD_NAME-dependencies.txt /tmp/requirements.txt
RUN pip install --upgrade --requirement /tmp/requirements.txt
# install openmtc-${PKG_NAME}
COPY tmp/openmtc-\$MOD_NAME.tar.gz /tmp/openmtc-\$MOD_NAME.tar.gz
RUN tar xzf /tmp/openmtc-\$MOD_NAME.tar.gz -C / \\
--owner root --group root --no-same-owner --no-overwrite-dir \\
--transform 's/json\.dist/json/' --show-transformed
RUN mkdir -p /var/log/openmtc
# add change config
COPY configure-\$MOD_NAME-and-start /usr/local/bin/configure-and-start
# entry point
ENTRYPOINT ["/usr/local/bin/configure-and-start"]
CMD [""]
EOF
cat "${DOCKER_FILE_AMD64}" | sed 's/-amd64/-arm/g' > "${DOCKER_FILE_ARM}"