#!/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 <] APP_NAME APP_NAME Name of the app, used as folder and class name. -a 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 Title Hello World! 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}"