Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/project/project/
/project/target/
/target/
.idea
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,24 @@
# server-agent
A demo Scala service for ISLE: Introduction to Scala Language and Ecosystem
# Server HealthCheck Agent
## Overview
Server HealthCheck Agent is a daemon reporting host health checks to console. Current implementation
supports two modes of operation:
* heartbeat - agent sends heartbeat messages to console with specified frequency
* file check - agent checks for file presence in specified location with specified frequency

Program arguments:
* `--type` can be one of `heartbeat` or `filecheck`
* `--frequency` time period for repeatable check in seconds
* `--location` (mandatory for `filecheck` mode only) - location of a file to check for existence

## Building and running
Agent is using SBT for building and packaging the code. To build a fatjar with all dependencies included run:

sbt clean assembly

When agent is packaged it can be executed with `java -jar <agent.jar location>`. E.g. from project root:

#heartbeat mode
java -jar target/scala-2.12/agent.jar --type heartbeat --frequency 5

#file check mode
java -jar target/scala-2.12/agent.jar --type filecheck --location <path to file> --frequency 5
14 changes: 14 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Dependencies._

lazy val root = Project(id = "agent", file("."))
.settings(
inThisBuild(List(
organization := "io.datastrophic",
scalaVersion := "2.12.4",
version := "0.1.0-SNAPSHOT"
)),
name := "agent",
libraryDependencies += scalaTest % Test,
mainClass in assembly := Some("io.datastrophic.isle.agent.Agent"),
assemblyJarName in assembly := "agent.jar"
)
5 changes: 5 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sbt._

object Dependencies {
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.4"
}
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.1.0
1 change: 1 addition & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
28 changes: 28 additions & 0 deletions src/main/scala/io/datastrophic/isle/agent/Agent.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.datastrophic.isle.agent

import ArgumentParser._

object Agent extends App {
println("agent started. parsing arguments")
val (arguments, error) = parseArguments(args)

if(error.nonEmpty){
println(error)
} else {
if(arguments(TypeKey) == FileCheckValue) {
println("running filecheck")
val check = new FileCheck(arguments(LocationKey))
while (true) {
check.checkFile()
Thread.sleep(arguments(FrequencyKey).toLong * 1000)
}
} else {
println("running heartbeat")
val check = new HeartBeatCheck
while (true) {
check.heartbeat()
Thread.sleep(arguments(FrequencyKey).toLong * 1000)
}
}
}
}
79 changes: 79 additions & 0 deletions src/main/scala/io/datastrophic/isle/agent/ArgumentParser.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.datastrophic.isle.agent

object ArgumentParser {
val FrequencyKey = "--frequency"
val TypeKey = "--type"
val FileCheckValue = "filecheck"
val HeartbeatCheckValue = "heartbeat"
val LocationKey = "--location"

val usage =
"""
| heartbeat mode: java -jar agent.jar --type heartbeat --frequency 5
| file check mode: java -jar agent.jar --type filecheck --location <path to file> --frequency 5
""".stripMargin


/**
* @param args array of GNU-style arguments
* @return tuple that contains a map of arguments and an error message in case of parsing problem
*/
def parseArguments(args: Array[String]): (Map[String, String], String) = {
var i = 0
var error = ""
var arguments = Map.empty[String, String]

while (i < args.length){
if(!args(i).startsWith("--")){
arguments = Map()
error = s"Argument name doesn't conform GNU style: [${args(i)}]. Usage: $usage"
i = args.length
} else if (i + 1 == args.length){
arguments = Map()
error = s"Argument not specified: [${args(i)}]. Usage: $usage"
i = args.length
} else {
arguments += args(i) -> args(i+1)
i = i+2
}
}

if(error.isEmpty){
val validation = validate(arguments)

if(validation._1){
(arguments, error)
} else {
(arguments, validation._2)
}
} else {
(Map(), error)
}

}

/**
* Method provides validation for parsed arguments Map
* @param args Map of parsed arguments
* @return tuple that contains a result of validation and an error message in case of validation failure
*/
def validate(args: Map[String, String]): (Boolean, String) = {
if(args.get(FrequencyKey).isDefined && args(FrequencyKey).forall(_.isDigit)){
if(args.get(TypeKey).isDefined && (args(TypeKey) == FileCheckValue || args(TypeKey) == HeartbeatCheckValue)){
if(args(TypeKey) == FileCheckValue) {
if (args.get(LocationKey).isDefined) {
(true, "")
} else {
(false, s"$LocationKey is missing value for the FileCheck. Usage: $usage")
}
} else {
(true, "")
}
} else {
(false, s"$TypeKey key is missing or has invalid value. Usage: $usage")
}
} else {
(false, s"$FrequencyKey key is missing or not a digit. Usage: $usage")
}
}
}
13 changes: 13 additions & 0 deletions src/main/scala/io/datastrophic/isle/agent/FileCheck.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.datastrophic.isle.agent

import java.io.File

class FileCheck(path: String) {
def checkFile() = {
if(new File(path).exists()){
println("[healthy]")
} else {
println(s"[unhealthy] file not found: $path")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.datastrophic.isle.agent

class HeartBeatCheck {
def heartbeat() = {
println("[healthy]")
}
}