Skip to content

Application Type - Generic

Generic type means that you can run any process in operating system you want. You just need to provide command that can be executed. Additionally it is required to provide commands to stop and terminate the process. It can be a script, command or any other option in operating system. It is possible also to add aditional commands that you can execute over API remotly.

Example configuration

app:
  name: 'python-app'
  version: '1.0.0'
  appType: 'standard'
  procType: 'native'
  processProvider:
    name: 'GenericOsProcessProviderImpl'
    version: '1.0.0'
    executable:
      start:
        command: 'python3 ${application-instance-path}/bin/main.py --port ${application-instance-port-1} --log_dir ${application-instance-logs-path}'
        cpus: null
        memory: null
        successLine: 'Application started.'
        before: []
        after: []
        path: null
        getPid: null
        pidFilePath: null
        readStreamsWaitTimeInMillis: 90000
      stop:
        command: "pkill -SIGTERM -F ${application-instance-logs-path}/ONTEON_PID"
      terminate:
        command: "pkill -SIGKILL -F ${application-instance-logs-path}/ONTEON_PID"
      custom_command_name:
        command: "./run_my_custom_command"
  placeHolder:
    name: 'PlaceHolderManagerImpl'
    version: '1.0.0'
    filesToReplace: []
    variables: {}
  serviceRepository:
    healthCheckUrl: 'http://${address}:${application-instance-port-1}'
    entities:
      - entity:
          priority: 1
          port: ${application-instance-port-1}
          protocol:
            type: 'HTTP'
            version: '1.1'
          isExternal: true
          isInternal: true

Configuration keys

app.name

Name of application.

app:
  name: 'application-name'

app.version

Version of application.

app:
  version: '1.0.0'

app.type

Application type. It should be set to standard.

Possible values:

  • standard - Standard application.
  • embedded - Application used for internal purposes, such as edge balancer.
  • unknown - Unknown application.
    app:
      appType: 'standard'
    

app.procType

Process type. It should be set to native.

Possible values:

  • native - Native application.
  • docker - Docker application.
  • unknown - Unknown application.
    app:
      procType: 'native'
    

app.processProvider.name

Name of process provider. It should be set to GenericOsProcessProviderImpl.

Possible values:

  • GenericOsProcessProviderImpl - for native processes.
  • JVMOsProcessProviderImpl - for native JVM processes.
  • DockerOsProcessProviderImpl - for docker processes.
    app:
      processProvider:
        name: 'GenericOsProcessProviderImpl'
    

app.processProvider.version

Version of process provider. It should be set to 1.0.0.

app:
  processProvider:
    version: '1.0.0'

app.processProvider.executable.(action).command

Command that executes specific action.

app:
  processProvider:
    executable:
      start:
        command: '${application-instance-path}/bin/bin/start.sh --port ${application-instance-port-1}'

app.processProvider.executable.start.successLine

Log line that will determine that the application has started. If you do not specify success line, Onteon node will wait 90 seconds. Wait time can be changed here.

app:
  processProvider:
    executable:
      start:
        successLine: 'Application started...'

app.processProvider.executable.start.cpus

CPUs limit for process.

app:
  processProvider:
    executable:
      start:
        cpus: null

app.processProvider.executable.start.memory

Memory limit for process.

app:
  processProvider:
    executable:
      start:
        memory: null

app.processProvider.executable.start.before

List of actions (defined on executable list) to run before running start command.

app:
  processProvider:
    executable:
      start:
        before: []

app.processProvider.executable.start.after

List of actions (defined on executable list) to run after running start command.

app:
  processProvider:
    executable:
      start:
        after: []

app.processProvider.executable.start.path

Path to directory with executable.

app:
  processProvider:
    executable:
      start:
        memory: null
        path: null

app.processProvider.executable.start.getPid

Command to retrieve application's process ID.

app:
  processProvider:
    executable:
      start:
        getPid: null

app.processProvider.executable.start.pidFilePath

Path to file that contains application's process ID.

app:
  processProvider:
    executable:
      start:
        pidFilePath: null

app.processProvider.executable.start.readStreamsWaitTimeInMillis

Time in milliseconds that Onteon Node Manager will wait for the application's success line to occur. If success line it not defined, then it is a time in milliseconds, after which Onteon Node Manager will assume that the application is started and check if it's running using application's PID.

app.placeHolder.name

Placeholder name.

app:
  placeHolder:
    name: 'PlaceHolderManagerImpl'

app.placeHolder.version

Placeholder version.

app:
  placeHolder:
    version: '1.0.0'

app.placeHolder.filesToReplace

List of files that will have placeholder replaced.

app:
  placeHolder:
    filesToReplace: []

app.placeHolder.variables

Placeholders variables in key-value format.

app:
  placeHolder:
    variables: {}

app.serviceRepository.healthCheckUrl

Url that will determine if application is alive.

app:
  serviceRepository:
    healthCheckUrl: 'http://${address}:${application-instance-port-1}/isAlive/'

app.serviceRepository.entities

List of service repository entities.

app:
  serviceRepository:
    entities:
      - entity:
          priority: 1
          port: ${application-instance-port-1} # entity port
          protocol:
            type: 'HTTP'      # entity protocol
            version: '1.1'    # entity protocol version
          isExternal: true    # if true, application will be available in edge balancer
          isInternal: true    # if true, application will be available in inner balancer

Additional embedded application configuration keys

Besides base configuration keys listed above, applications with appType: 'embedded' have additional keys.

app:
  name: 'python-app'
  version: '1.0.0'
  appType: 'embedded'
  procType: 'native'
  itShouldBeStartedOnNodeManagerStartup: true
  startupIndex: 1
  isItRequiredForSystemConsistency: true
  processProvider:
    name: 'GenericOsProcessProviderImpl'
    version: '1.0.0'
    executable:
      start:
        command: 'python3 ${application-instance-path}/bin/main.py --port ${application-instance-port-1} --log_dir ${application-instance-logs-path}'
        cpus: null
        memory: null
        successLine: 'Application started.'
        before: []
        after: []
        path: null
        getPid: null
        pidFilePath: null
        readStreamsWaitTimeInMillis: 90000
      stop:
        command: "pkill -SIGTERM -F ${application-instance-logs-path}/ONTEON_PID"
      terminate:
        command: "pkill -SIGKILL -F ${application-instance-logs-path}/ONTEON_PID"
      custom_command_name:
        command: "./run_my_custom_command"
  placeHolder:
    name: 'PlaceHolderManagerImpl'
    version: '1.0.0'
    filesToReplace: []
    variables: {}
  serviceRepository:
    healthCheckUrl: 'http://${address}:${application-instance-port-1}'
    entities:
      - entity:
          priority: 1
          port: ${application-instance-port-1}
          protocol:
            type: 'HTTP'
            version: '1.1'
          isExternal: true
          isInternal: true

app.itShouldBeStartedOnNodeManagerStartup

Defines if application should be started on Node Manager startup.

Possible values:

  • true
  • false
 app:
   itShouldBeStartedOnNodeManagerStartup: true

app.startupIndex

Specifies the order in which the application should start during startup sequence.

 app:
   startupIndex: 1

app.isItRequiredForSystemConsistency

Defines if node manager requires this application to start (if the application start fails, then node manager does not start) to work properly.

Possible values:

  • true
  • false
 app:
   isItRequiredForSystemConsistency: true

Docker containers under the Generic app type

PID detection under Docker

When the docker run or docker start command is used, then that dockerized application PID will not be the same as the docker command that was executed. In such case automatically detected PID will disappear and that will in turn cause the application instance to be considered as stopped.

Because of this, when the Generic app type is used to run Docker containers, then there is a need to create a custom getPid script. Such getPid script should reach out to Docker engine and provide the application PID as it is visible to the operating system (outside of a given container).

To extract the Docker container instance PID as it is visible to the operating system use the following command:

docker inspect -f '{{.State.Pid}}' CONTAINER-NAME-OR-ID

Example getPid script for Docker apps

Example getPid script for Docker apps is as follows (be sure to replace APP-NAME):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

exec docker inspect -f '{{.State.Pid}}' APP-NAME

Be sure to also point start.getPid value the the correct script path. For example:

app:
  processProvider:
    executable:
      start:
        getPid: "bash ${application-instance-path}/bin/bash-scripts/getPid.sh"

Instance ID and Docker

In case there needs to be more than one instance of a dockerized app running, then setup is a bit more complicated. Because each container must have a unique name, scripts have to use a special instance id variable called ${application-instance-id}.

Place this variable inside a env.bash file and source it inside start, getPid and stop scripts.

Example usage of application-instance-id

Conf (conf/conf.yml):

app:
  placeHolder:
    name: "PlaceHolderManagerImpl"
    version: "1.0.0"
    filesToReplace:
      - "${application-instance-path}/bin/environment/env.bash"

Env (bin/environment/env.bash):

#!/usr/bin/env bash

INSTANCE="${application-instance-id}"

Start (bin/bash-scripts/start.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker run --detach --restart="no" --name="APP-NAME-${INSTANCE}" \
    CONTAINER-NAME

echo "Successfully started"

Stop (bin/bash-scripts/stop.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker stop "APP-NAME-${INSTANCE}"

Port bind under Docker

Similarly to instance names, ports will also clash. Thus application-instance-port-n has to be used just like it was done with ${application-instance-id}. application-instance-port-n name is generated and n is substituted with generated port indexes. We will use one port and so the variable name will be ${application-instance-port-1}.

Example usage of application-instance-port-1

Conf (conf/conf.yml):

app:
  placeHolder:
    name: "PlaceHolderManagerImpl"
    version: "1.0.0"
    filesToReplace:
      - "${application-instance-path}/bin/environment/env.bash"
  serviceRepository:
    entities:
      - entity:
          priority: 1
          port: ${application-instance-port-1}
          protocol:
            type: "HTTP"
            version: "1.1"
          isExternal: true
          isInternal: true

Env (bin/environment/env.bash):

#!/usr/bin/env bash

INSTANCE="${application-instance-id}"
PORT_1="${application-instance-port-1}"

Start (bin/bash-scripts/start.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker run --detach --restart="no" --name="APP-NAME-${INSTANCE}" \
    -p "${PORT_1}:APP-PORT" CONTAINER-NAME

echo "Successfully started"

Putting it all together for dockerized applications

Lets take a look at using Docker inside Onteon for a nginx container.

Conf (conf/conf.yml):

---
app:
  name: "nginx"
  version: "1.26.3"
  appType: "standard"
  procType: "native"
  processProvider:
    name: "GenericOsProcessProviderImpl"
    version: "1.0.0"
    executable:
      start:
        command: "bash ${application-instance-path}/bin/bash-scripts/start.bash"
        successLine: "Successfully started"
        getPid: "bash ${application-instance-path}/bin/bash-scripts/getPid.bash"
      stop:
        command: "bash ${application-instance-path}/bin/bash-scripts/stop.bash"
      terminate:
        command: "bash ${application-instance-path}/bin/bash-scripts/terminate.bash"
  placeHolder:
    name: "PlaceHolderManagerImpl"
    version: "1.0.0"
    filesToReplace:
      - "${application-instance-path}/bin/environment/env.bash"
  serviceRepository:
    entities:
      - entity:
          priority: 1
          port: ${application-instance-port-1}
          protocol:
            type: "HTTP"
            version: "1.1"
          isExternal: true
          isInternal: true

Env (bin/environment/env.bash):

#!/usr/bin/env bash

INSTANCE="${application-instance-id}"
PORT_1="${application-instance-port-1}"

APP="nginx"
VERSION="1.26.3"
CONTAINER_PORT_1="80"

Start will run Nginx using special Onteon-generated port and instance name.

Start (bin/bash-scripts/start.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker run --detach --restart="no" --name="${APP}-${INSTANCE}" \
    -p "${PORT_1}:${CONTAINER_PORT_1}" "${APP}:${VERSION}"

echo "Successfully started"

GetPid extracts real container PID as discussed above.

getPid (bin/bash-scripts/getPid.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

exec docker inspect -f '{{.State.Pid}}' "${APP}-${INSTANCE}"

Stop will stop Nginx Docker container with docker stop.

Stop (bin/bash-scripts/stop.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker stop "${APP}-${INSTANCE}"

Terminate will kill Nginx Docker container with docker kill.

Terminate (bin/bash-scripts/terminate.bash):

#!/usr/bin/env bash

trap "exit 128" INT
set -eu

SOURCE="${BASH_SOURCE[0]}"
while [[ -h "${SOURCE}" ]] ; do
    DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"
    SOURCE="$(readlink "${SOURCE}")"
    [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
SCRIPT_DIR="$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)"

cd "${SCRIPT_DIR}"
source ../environment/env.bash

docker kill "${APP}-${INSTANCE}"

If everything works correctly, then in the docker ps -a command output there should be an app instance that has a random hash at the end of its name and also it should be possible to send requests to the dockerized nginx app on both internal and external load balancer, for example:

curl "http://127.0.0.1:8020/_by_name/nginx/"