Skip to content

Commit

Permalink
#20 package Cortex with rpm, deb and docker
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed May 2, 2017
1 parent 1c635f3 commit 8cfa56b
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 163 deletions.
157 changes: 92 additions & 65 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ libraryDependencies ++= Seq(

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

releaseVersionUIFile := baseDirectory.value / "ui" / "package.json"
Release.releaseVersionUIFile := baseDirectory.value / "ui" / "package.json"

changelogFile := baseDirectory.value / "CHANGELOG.md"
Release.changelogFile := baseDirectory.value / "CHANGELOG.md"

publishArtifact in (Compile, packageDoc) := false

Expand All @@ -30,83 +30,110 @@ run := {
(run in Compile).evaluated
frontendDev.value
}

mappings in packageBin in Assets ++= frontendFiles.value

// Install files //

mappings in Universal ++= {
val dir = baseDirectory.value / "install"
(dir.***) pair relativeTo(dir.getParentFile)
mappings in Universal ~= {
_.flatMap {
case (file, "conf/application.conf") => Nil
case (file, "conf/apllication.sample") => Seq(file -> "conf/application.conf")
case other => Seq(other)
} ++ Seq(
file("install/cortex.service") -> "install/cortex.service",
file("install/cortex.conf") -> "install/cortex.conf",
file("install/cortex") -> "install/cortex"
)
}

// Release //
import ReleaseTransformations._

import Release._

bintrayOrganization := Some("cert-bdf")

bintrayRepository := "cortex"

publish := {
publishRelease.value
publishLatest.value
// Package //
maintainer := "Thomas Franco <[email protected]"
packageSummary := "-"
packageDescription := """--""".stripMargin
defaultLinuxInstallLocation := "/opt"
linuxPackageMappings ~= { _.map { pm =>
val mappings = pm.mappings.filterNot {
case (file, path) => path.startsWith("/opt/cortex/install") || path.startsWith("/opt/cortex/conf")
}
com.typesafe.sbt.packager.linux.LinuxPackageMapping(mappings, pm.fileData).withConfig()
} :+ packageMapping(
file("install/cortex.service") -> "/etc/systemd/system/cortex.service",
file("install/cortex.conf") -> "/etc/init/cortex.conf",
file("install/cortex") -> "/etc/init.d/cortex",
file("conf/application.sample") -> "/etc/cortex/application.conf",
file("conf/logback.xml") -> "/etc/cortex/logback.xml"
).withConfig()
}

releaseProcess := Seq[ReleaseStep](
checkUncommittedChanges,
checkSnapshotDependencies,
getVersionFromBranch,
runTest,
releaseMerge,
checkoutMaster,
setReleaseVersion,
setReleaseUIVersion,
generateChangelog,
commitChanges,
tagRelease,
publishArtifacts,
checkoutDevelop,
setNextVersion,
setNextUIVersion,
commitChanges,
//commitNextVersion,
pushChanges)

packageBin := {
(packageBin in Universal).value
(packageBin in Debian).value
//(packageBin in Rpm).value
}
// DEB //
//debianPackageRecommends := Seq("elasticsearch")
debianPackageDependencies += "java8-runtime-headless | java8-runtime"
maintainerScripts in Debian := maintainerScriptsFromDirectory(
baseDirectory.value / "install" / "debian",
Seq(DebianConstants.Postinst, DebianConstants.Prerm, DebianConstants.Postrm)
)
linuxEtcDefaultTemplate in Debian := (baseDirectory.value / "install" / "etc_default_cortex").asURL
linuxMakeStartScript in Debian := None

// RPM //
rpmRelease := "8"
rpmVendor in Rpm := "TheHive Project"
rpmUrl := Some("http://thehive-project.org/")
rpmLicense := Some("AGPL")
rpmRequirements += "java-1.8.0-openjdk-headless"
maintainerScripts in Rpm := maintainerScriptsFromDirectory(
baseDirectory.value / "install" / "rpm",
Seq(RpmConstants.Pre, RpmConstants.Preun, RpmConstants.Postun)
)
linuxPackageSymlinks in Rpm := Nil
rpmPrefix := Some(defaultLinuxInstallLocation.value)
linuxEtcDefaultTemplate in Rpm := (baseDirectory.value / "install" / "etc_default_cortex").asURL

// DOCKER //
import com.typesafe.sbt.packager.docker.{ Cmd, ExecCmd }

dockerBaseImage := "certbdf/thehive:latest"

packageName in Docker := "thehive-cortex"

defaultLinuxInstallLocation in Docker := "/opt/cortex"
dockerRepository := Some("certbdf")

dockerUpdateLatest := true

mappings in Universal += file("docker/entrypoint") -> "bin/entrypoint"

mappings in Universal ~= { _.filterNot {
case (_, name) => name.startsWith("conf/") && name != "conf/keepme"
}}
import com.typesafe.sbt.packager.docker.{ ExecCmd, Cmd }

dockerCommands := dockerCommands.value.map {
case ExecCmd("ENTRYPOINT", _*) => ExecCmd("ENTRYPOINT", "bin/entrypoint")
case cmd => cmd
dockerEntrypoint := Seq("/opt/cortex/entrypoint")
dockerExposedPorts := Seq(9000)
mappings in Docker ++= Seq(
file("install/docker/entrypoint") -> "/opt/cortex/entrypoint",
file("conf/logback.xml") -> "/etc/cortex/logback.xml",
file("install/empty") -> "/var/log/cortex/application.log")
mappings in Docker ~= (_.filterNot {
case (_, filepath) => filepath == "/opt/cortex/conf/application.conf"
})

dockerCommands ~= { dc =>
val (dockerInitCmds, dockerTailCmds) = dc.splitAt(4)
dockerInitCmds ++
Seq(
Cmd("USER", "root"),
ExecCmd("RUN", "bash", "-c",
"apt-get update && " +
"apt-get install -y --no-install-recommends python-pip python2.7-dev ssdeep libfuzzy-dev libfuzzy2 libimage-exiftool-perl libmagic1 build-essential git && " +
"cd /opt && " +
"git clone -b develop https://github.com/CERT-BDF/Cortex-Analyzers.git && " +
"pip install $(cat Cortex-Analyzers/analyzers/*/requirements.txt | grep -v hashlib | sort -u)"),
Cmd("ADD", "var", "/var"),
Cmd("ADD", "etc", "/etc"),
ExecCmd("RUN", "chown", "-R", "daemon:daemon", "/var/log/cortex")) ++
dockerTailCmds
}

dockerCommands := dockerCommands.value.head +:
Cmd("USER", "root") +:
ExecCmd("RUN", "bash", "-c",
"apt-get update && " +
"apt-get install -y --no-install-recommends python-pip python2.7-dev ssdeep libfuzzy-dev libfuzzy2 libimage-exiftool-perl libmagic1 build-essential git && " +
"cd /opt && " +
"git clone https://github.com/CERT-BDF/Cortex-Analyzers.git && " +
"pip install $(cat Cortex-Analyzers/analyzers/*/requirements.txt | grep -v hashlib | sort -u)") +:
Cmd("EXPOSE", "9001") +:
dockerCommands.value.tail
// Bintray //
bintrayOrganization := Some("cert-bdf")
bintrayRepository := "cortex"
publish := {
(publish in Docker).value
PublishToBinTray.publishRelease.value
PublishToBinTray.publishLatest.value
}

// Scalariform //
import scalariform.formatter.preferences._
Expand Down
39 changes: 39 additions & 0 deletions conf/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

<conversionRule conversionWord="coloredLevel"
converterClass="play.api.libs.logback.ColoredLevel" />

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/var/log/cortex/application.log</file>
<encoder>
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}
</pattern>
</encoder>
</appender>

<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>

<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="STDOUT" />
</appender>

<logger name="play" level="INFO" />
<logger name="application" level="INFO" />

<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />

<root level="INFO">
<appender-ref ref="ASYNCFILE" />
<appender-ref ref="ASYNCSTDOUT" />
</root>

</configuration>
116 changes: 72 additions & 44 deletions install/cortex
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,101 @@
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Cortex: a FOSS Information Security Incident Management Platform
# Short-Description: cortex: Powerful Observable Analysis Engine
### END INIT INFO

NAME=cortex
DAEMONDIR=/opt/cortex
DAEMON=$DAEMONDIR/bin/cortex
PIDDIR=/var/run/cortex
PIDFILE=$PIDDIR/pid
DAEMONUSER=cortex
CONFIGFILE=/etc/cortex/application.conf
LISTENPORT=9000
DAEMON_OPTS=
DAEMON=/opt/cortex/bin/cortex
PIDFILE=/var/run/cortex/pid
DAEMON_USER=cortex
DAEMON_ARGS="-Dconfig.file=/etc/cortex/application.conf -Dlogger.file=/etc/cortex/logback.xml -Dpidfile.path=/dev/null"
PATH=/sbin:/bin:/usr/sbin:/usr/bin

test -x $DAEMON || exit 0
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

if test -f /etc/default/$NAME
then
. /etc/default/$NAME
fi
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start() {
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --user $DAEMON_USER --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --user $DAEMON_USER --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
}

#
# Function that stops the daemon/service
#
do_stop() {
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

check_for_upstart() {
if init_is_upstart; then
echo "Your are using upstart. This script should not be used"
exit $1
fi
}

check_config_file() {
if test ! -e $CONFIGFILE
then
mkdir -p $(dirname $CONFIGFILE) 2>/dev/null || true
cat >> $CONFIGFILE <<- _EOF_
# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
# If you deploy your application to several instances be sure to use the same key!
play.crypto.secret="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1)"
_EOF_
chown $DAEMONUSER $CONFIGFILE
chmod o-rwx $CONFIGFILE
fi
}

case "$1" in
start)
check_for_upstart 1
check_config_file
log_daemon_msg "Starting Cortex" $NAME || true
if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --chdir $DAEMONDIR --exec $DAEMON -- -Dconfig.file=$CONFIGFILE -Dhttp.port=$LISTENPORT -Dpidfile.path=$PIDFILE $DAEMON_OPTS
then
log_end_msg 0 || true
else
log_end_msg 1 || true
if [ "$ENABLED" = no ]; then
echo "The service cortex is disabled (/etc/default/cortex)"
exit 1
fi

[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;

stop)
check_for_upstart 1
log_daemon_msg "Stopping Cortex" $NAME || true
if start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
then
log_end_msg 0 || true
else
log_end_msg 1 || true
fi
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;

status)
Expand Down
Loading

0 comments on commit 8cfa56b

Please sign in to comment.