├── .editorconfig ├── .gitignore ├── .pullapprove.yml ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── bin ├── install ├── install-version └── minimesos ├── build.gradle ├── cli ├── Dockerfile ├── build.gradle └── src │ ├── integration-test │ ├── java │ │ └── com │ │ │ └── containersol │ │ │ └── minimesos │ │ │ └── main │ │ │ ├── CommandInitTest.java │ │ │ ├── CommandLogsTest.java │ │ │ ├── CommandPsTest.java │ │ │ ├── CommandTest.java │ │ │ ├── CommandUninstallTest.java │ │ │ └── CommandUpTest.java │ └── resources │ │ ├── app.json │ │ ├── clusterconfig │ │ ├── basic.groovy │ │ └── two-agents.groovy │ │ ├── configFiles │ │ ├── complete-minimesosFile │ │ ├── invalid-minimesosFile.txt │ │ ├── marathonAppConfig-minimesosFile │ │ └── withMarathon-minimesosFile │ │ └── logback-test.xml │ ├── main │ └── java │ │ └── com │ │ └── containersol │ │ └── minimesos │ │ └── main │ │ ├── Command.java │ │ ├── CommandDestroy.java │ │ ├── CommandHelp.java │ │ ├── CommandInfo.java │ │ ├── CommandInit.java │ │ ├── CommandInstall.java │ │ ├── CommandLogs.java │ │ ├── CommandPs.java │ │ ├── CommandState.java │ │ ├── CommandUninstall.java │ │ ├── CommandUp.java │ │ ├── CommandVersion.java │ │ └── Main.java │ └── test │ ├── java │ └── com │ │ └── containersol │ │ └── minimesos │ │ └── main │ │ ├── CommandInstallTest.java │ │ └── MainTest.java │ └── resources │ ├── app.json │ └── group.json ├── docs ├── cc-cc.png ├── images │ └── introduction-to-minimesos-screenshot.jpg ├── index.md └── minimesos.png ├── gradle.properties ├── gradle ├── quality.gradle ├── spock.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── images ├── minimesos-talk.jpg └── minimesos.png ├── minimesos ├── build.gradle └── src │ ├── integration-test │ └── java │ │ └── com.containersol.minimesos │ │ └── integrationtest │ │ ├── AuthenticationTest.java │ │ ├── MesosClusterTest.java │ │ └── container │ │ ├── HelloWorldContainer.java │ │ └── MesosExecuteContainer.java │ ├── main │ ├── groovy │ │ └── com │ │ │ └── containersol │ │ │ └── minimesos │ │ │ └── config │ │ │ ├── AgentResourcesConfig.groovy │ │ │ ├── AppConfig.groovy │ │ │ ├── ClusterConfig.groovy │ │ │ ├── ConfigParser.groovy │ │ │ ├── ConsulConfig.groovy │ │ │ ├── ContainerConfig.groovy │ │ │ ├── ContainerConfigBlock.groovy │ │ │ ├── GroovyBlock.groovy │ │ │ ├── GroupConfig.groovy │ │ │ ├── MarathonConfig.groovy │ │ │ ├── MesosAgentConfig.groovy │ │ │ ├── MesosContainerConfig.groovy │ │ │ ├── MesosDNSConfig.groovy │ │ │ ├── MesosMasterConfig.groovy │ │ │ ├── RegistratorConfig.groovy │ │ │ ├── ResourceDef.groovy │ │ │ ├── ResourceDefRanges.groovy │ │ │ ├── ResourceDefScalar.groovy │ │ │ └── ZooKeeperConfig.groovy │ ├── java │ │ └── com │ │ │ └── containersol │ │ │ └── minimesos │ │ │ ├── MinimesosException.java │ │ │ ├── cluster │ │ │ ├── ClusterProcess.java │ │ │ ├── ClusterRepository.java │ │ │ ├── ClusterUtil.java │ │ │ ├── Consul.java │ │ │ ├── Filter.java │ │ │ ├── Marathon.java │ │ │ ├── MesosAgent.java │ │ │ ├── MesosCluster.java │ │ │ ├── MesosClusterFactory.java │ │ │ ├── MesosContainer.java │ │ │ ├── MesosDns.java │ │ │ ├── MesosMaster.java │ │ │ ├── Registrator.java │ │ │ └── ZooKeeper.java │ │ │ ├── docker │ │ │ ├── DockerClientFactory.java │ │ │ └── DockerContainersUtil.java │ │ │ ├── integrationtest │ │ │ └── container │ │ │ │ ├── AbstractContainer.java │ │ │ │ └── ContainerName.java │ │ │ ├── junit │ │ │ └── MesosClusterTestRule.java │ │ │ ├── marathon │ │ │ └── MarathonContainer.java │ │ │ ├── mesos │ │ │ ├── ClusterContainers.java │ │ │ ├── ConsulContainer.java │ │ │ ├── MesosAgentContainer.java │ │ │ ├── MesosClusterContainersFactory.java │ │ │ ├── MesosContainerImpl.java │ │ │ ├── MesosDnsContainer.java │ │ │ ├── MesosMasterContainer.java │ │ │ ├── RegistratorContainer.java │ │ │ └── ZooKeeperContainer.java │ │ │ ├── state │ │ │ ├── Discovery.java │ │ │ ├── Executor.java │ │ │ ├── Framework.java │ │ │ ├── Port.java │ │ │ ├── Ports.java │ │ │ ├── State.java │ │ │ └── Task.java │ │ │ └── util │ │ │ ├── CollectionsUtils.java │ │ │ ├── Downloader.java │ │ │ ├── Environment.java │ │ │ ├── EnvironmentBuilder.java │ │ │ ├── Predicate.java │ │ │ └── ResourceUtil.java │ └── resources │ │ ├── logback.xml │ │ └── marathon │ │ ├── elasticsearch.json │ │ └── mesos-consul.json │ └── test │ ├── groovy │ └── com │ │ └── containersol │ │ └── minimesos │ │ └── config │ │ ├── AgentResourcesConfigTest.groovy │ │ ├── ConfigParserTest.groovy │ │ ├── ConfigWriterTest.groovy │ │ └── ResourceDefScalarTest.groovy │ ├── java │ └── com │ │ └── containersol │ │ └── minimesos │ │ ├── ClusterBuilderTest.java │ │ ├── ParseStateJSONTest.java │ │ ├── factory │ │ └── MesosClusterContainersFactoryTest.java │ │ ├── integrationtest │ │ └── container │ │ │ ├── ContainerNameTest.java │ │ │ └── MesosAgentTest.java │ │ ├── jdepend │ │ └── JDependCyclesTest.java │ │ ├── mesos │ │ ├── ClusterContainersTest.java │ │ └── ClusterUtilTest.java │ │ └── util │ │ ├── CollectionsUtilsTest.java │ │ ├── EnvironmentBuilderTest.java │ │ └── ResourceUtilTest.java │ └── resources │ ├── configFiles │ ├── minimesosFile-authenticationTest │ └── minimesosFile-mesosClusterTest │ └── logback-test.xml ├── opt ├── apps │ └── weave-scope.json ├── sonar │ ├── DockerFile │ ├── certificate.yaml │ ├── setup.md │ ├── sonar-deployment.yaml │ ├── sonar-plugins │ │ ├── sonar-github-plugin-1.1.jar │ │ ├── sonar-java-plugin-3.7.1.jar │ │ ├── sonar-scm-git-plugin-1.0.jar │ │ └── sonar-scm-svn-plugin-1.2.jar │ ├── sonar-postgres-deployment.yaml │ ├── sonar-postgres-service.yaml │ └── sonar-service.yaml └── vagrant │ └── debian │ └── jessie64 │ ├── Vagrantfile │ └── provision.sh ├── settings.gradle └── travis.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | 9 | [*.java] 10 | indent_style = space 11 | indent_size = 4 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | minimesosFile 2 | .minimesos/* 3 | *.class 4 | .gradle/ 5 | build/ 6 | 7 | # Vagrant working files 8 | .vagrant 9 | 10 | # Build system 11 | .gradle/ 12 | build/ 13 | 14 | # IDEA files 15 | *.i?? 16 | out/ 17 | .idea/ 18 | 19 | # Maven 20 | /target 21 | 22 | # Mobile Tools for Java (J2ME) 23 | .mtj.tmp/ 24 | 25 | # Package Files # 26 | *.war 27 | *.ear 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | 32 | # private docker registry images 33 | .registry 34 | -------------------------------------------------------------------------------- /.pullapprove.yml: -------------------------------------------------------------------------------- 1 | approve_by_comment: true 2 | approve_regex: ^(Approved|LGTM|:\+1:) 3 | author_approval: ignored 4 | reject_regex: ^Rejected 5 | reset_on_push: false 6 | reviewers: 7 | members: 8 | - frankscholten 9 | - mwl 10 | - sadovnikov 11 | - philwinder 12 | - lguminski 13 | - adam-sandor 14 | name: default 15 | required: 1 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | sudo: required 7 | 8 | install: 9 | # one liner installation of docker 1.9.1 below did not work (see https://github.com/moul/travis-docker/issues/38). 10 | # - curl -sLo - http://j.mp/install-travis-docker | sh -xe 11 | # Therefore installing it through a script 12 | - sudo sh -c 'echo "deb https://apt.dockerproject.org/repo ubuntu-precise main" > /etc/apt/sources.list.d/docker.list' 13 | - sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D 14 | - sudo apt-get update 15 | - sudo apt-key update 16 | - sudo apt-get -qqy install docker-engine=1.9.1-0~precise 17 | # Has to run this script with sudo because custom installation does not allow $USER to use docker and it's not possible to relogin 18 | - sudo make deps 19 | 20 | # Has to run the build script with sudo because custom installation does not allow $USER to use docker and it's not possible to relogin 21 | script: chmod +x travis.sh && sudo ./travis.sh 22 | 23 | notifications: 24 | email: true 25 | # see details on https://docs.travis-ci.com/user/notifications 26 | slack: 27 | secure: RWUEmM8nef6hH9+AmVaBWVxcjUt5hVPdbw02x+iBdTqAxPC2wxq3Ya/vlWDwhyyXdUgMujfWTJxks3A15qHAzPH22/mVsmAoz8Duspj/C3x8dp/7IncnkbX5AI1fEJy+z+D8uL4J6ALM90y8kUm2QKoddOq1+xO65xZyzvXoxFJDZ9eIlSVsDv7q7qqkaHnWH8nW+DqtGFPlhu5K/luaw56gy7lChUX/KvAy+8fzaUFNPKdJTVu+GpdgJZrqKeQS8+gY00k0AaAS6fOHxTeAUmyC6eDTL1FgBueS5auBha321qU84sQTCQSTHxl0J8YSQzzrBEiGn506DMKFjZLQZWmR4DxxGSc8jd4sdbVXBoWEBQvNI8jZoAzagFnNig1NKPtRAXIuip28FJUhsvK3WOs1H/XsnkRxKZ52jRrDg0yYi48HsqIr7af6nSzAkAK5JEL58Yc1nYvALa0vXjVWuyuo8um0sFNvEDRE/eDi5o6iul0I4CPOM0j+6d8ymVuD6oJ8eeGjYSFVk7XgdCBp1Gcl8NHLgiVjnygcT0U07kszDV7q8ab0iAfjMoTJwFTjPGkwFWJnlD5dciliO7ncWORl//A3JOQqRh5kMp/96995Ia9G4pVnEkh6tQI6G84/qMU0blDrOtTWIO6NjDV4UiGAYtaixr8BGKQWji9K+eY= 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: build 2 | .PHONY: setup deps test build 3 | 4 | setup: 5 | sudo route delete 172.17.0.0/16; sudo route -n add 172.17.0.0/16 $(shell docker-machine ip ${shell DOCKER_MACHINE_NAME}) 6 | 7 | deps: 8 | docker pull containersol/mesos-agent:1.0.0-0.1.0 9 | docker pull containersol/mesos-master:1.0.0-0.1.0 10 | docker pull gliderlabs/registrator:v6 11 | docker pull consul:0.7.1 12 | docker pull xebia/mesos-dns:0.0.5 13 | docker pull mesosphere/marathon:v1.3.5 14 | docker pull jplock/zookeeper:3.4.6 15 | docker pull containersol/alpine3.3-java8-jre:v1 16 | docker pull tutum/hello-world:latest 17 | 18 | clean: 19 | ./gradlew clean 20 | -docker rmi containersol/minimesos-cli:latest 21 | 22 | build: 23 | ./gradlew build --info --stacktrace 24 | 25 | build-no-tests: 26 | ./gradlew build --info --stacktrace -x test 27 | 28 | test: 29 | ./gradlew test --info --stacktrace 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # minimesos [![Build Status](https://travis-ci.org/ContainerSolutions/minimesos.svg?branch=master)](https://travis-ci.org/ContainerSolutions/minimesos) 2 | 3 | The experimentation and testing tool for Apache Mesos 4 | 5 | NOTE: NO LONGER MAINTAINED! 6 | 7 |
8 | 9 | 17 |
18 | 19 | ## Videos 20 | 21 | #### MesosCon 2016 Denver - minimesos - The Experimentation and Testing tool for Apache Mesos by Frank Scholten [@frank_scholten](https://twitter.com/Frank_Scholten) 22 | 23 | [![minimesos - The Experimentation and Testing tool for Apache Mesos by Frank](https://github.com/ContainerSolutions/minimesos/raw/master/images/minimesos-talk.jpg)](https://www.youtube.com/watch?v=J14_H4T0JB0) 24 | 25 | #### Introduction to Minimesos by Viktor Sadovnikov [@sadovnikov](https://twitter.com/sadovnikov) 26 | 27 | [![Introduction to minimesos by Viktor](https://raw.githubusercontent.com/containersolutions/minimesos/master/docs/images/introduction-to-minimesos-screenshot.jpg)](https://www.youtube.com/watch?v=jVGyz8sCZSU) 28 | -------------------------------------------------------------------------------- /bin/install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is meant for quick & easy install via: 4 | # `sudo curl -sSL https://raw.githubusercontent.com/ContainerSolutions/minimesos/master/bin/install | bash` 5 | # 6 | # Uses the latest release, unless a version identifier is specified as a parameter of this script. 7 | 8 | { # Prevent execution if the script is only partially downloaded 9 | 10 | command_exists() { 11 | command -v "$@" > /dev/null 2>&1 12 | } 13 | 14 | install_version() { 15 | curl -sSL $1 | sh -s $2 16 | } 17 | 18 | if ! command_exists curl; then 19 | echo "Please install curl to fetch the minimesos files" 20 | exit 1 21 | fi 22 | 23 | VERSION=$(echo $@ | xargs) 24 | 25 | if [ -z "$VERSION" ]; then 26 | VERSION=$(curl -s https://api.github.com/repos/containersolutions/minimesos/releases/latest | grep "tag_name" | awk '{ print $2 }' | tr -d '",') 27 | if [ ! "$VERSION" ]; then 28 | echo "Cannot determine latest release of minimesos. Please check https://github.com/containersolutions/minimesos/releases" 29 | exit 1 30 | fi 31 | fi 32 | 33 | # invoking versioned installation script 34 | SCRIPT_PATH=https://raw.githubusercontent.com/ContainerSolutions/minimesos/$VERSION 35 | httpcode=$(curl -s -o /dev/null -I -w '%{http_code}' --max-time 10 --retry-delay 2 --retry 3 $SCRIPT_PATH/bin/install-version || echo "404" ) 36 | if [ $httpcode -eq 200 ]; then 37 | install_version $SCRIPT_PATH/bin/install-version $VERSION 38 | else 39 | echo "Failed to pull installer off github.com (http err: ${httpcode}), please try again." 40 | exit 1 41 | fi 42 | 43 | exit 0 44 | } # Prevent execution if the script is only partially downloaded 45 | 46 | -------------------------------------------------------------------------------- /bin/install-version: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is meant to be invoked with VERSION given as a parameter. 4 | # Installs the given version of minimesos on the box 5 | 6 | { # Prevent execution if the script is only partially downloaded 7 | 8 | command_exists() { 9 | command -v "$@" > /dev/null 2>&1 10 | } 11 | 12 | if ! command_exists curl; then 13 | echo "Please install curl to fetch the minimesos files" 14 | exit 1 15 | fi 16 | 17 | if [ ! "$#" -eq 1 ]; then 18 | echo "Version is not given as parameter" 19 | exit 1 20 | fi 21 | 22 | INSTALL_LOCATION=$HOME/.minimesos/bin 23 | VERSION=$1 24 | echo "Installing version " $VERSION 25 | mkdir -p $INSTALL_LOCATION 26 | curl -sSL https://raw.githubusercontent.com/ContainerSolutions/minimesos/$VERSION/bin/minimesos > $INSTALL_LOCATION/minimesos 27 | chmod +x $INSTALL_LOCATION/minimesos 28 | 29 | if [ -f "/usr/local/bin/minimesos" ]; then 30 | echo "Found an old version of minimesos, please remove it:" && echo 31 | echo "rm -f /usr/local/bin/minimesos" && echo 32 | fi 33 | 34 | echo "minimesos is installed into ${INSTALL_LOCATION}/minimesos" 35 | echo "Run the following command to add it to your executables path:" && echo 36 | echo "export PATH=\$PATH:$INSTALL_LOCATION" 37 | 38 | exit 0 39 | 40 | } # Prevent execution if the script is only partially downloaded 41 | -------------------------------------------------------------------------------- /bin/minimesos: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | MINIMESOS_TAG="latest" 6 | PARAMS="$@" 7 | MINIMESOS_CLI_IMAGE="containersol/minimesos-cli" 8 | 9 | command_exists() { 10 | command -v "$@" > /dev/null 2>&1 11 | } 12 | 13 | DOCKER_VERSION=$(docker version --format "{{.Server.Version}}") 14 | SMALLEST_VERSION=$(printf "%s\n1.11.0\n" $DOCKER_VERSION | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g | head -n 1) 15 | 16 | if ! command_exists docker || [ $SMALLEST_VERSION != "1.11.0" ]; then 17 | echo "Minimesos requires Docker 1.11.0 or higher" 18 | exit 1 19 | fi 20 | 21 | if [ "$DOCKER_HOST" != "" ] && [[ $DOCKER_HOST == tcp* ]]; then 22 | DOCKER_HOST_IP=$(echo "$DOCKER_HOST" | grep -o '[0-9]\+[.][0-9]\+[.][0-9]\+[.][0-9]\+') 23 | elif command_exists docker-machine && [ "$DOCKER_MACHINE_NAME" != "" ]; then 24 | DOCKER_HOST_IP=$(docker-machine ip ${DOCKER_MACHINE_NAME}) 25 | elif [ $(uname) != "Darwin" ]; then 26 | DOCKER_HOST_IP=$(ip addr show dev docker0 | grep inet | sed -r "s/.*inet\s([0-9\.]+)\/.*/\1/" | head -n 1) 27 | else 28 | DOCKER_HOST_IP="" 29 | fi 30 | 31 | pullImage() { 32 | if [ "$(docker images $1 | grep $2 2> /dev/null)" = "" ]; then 33 | echo "Pulling $1:$2" 34 | docker pull "$1:$2" 35 | fi 36 | } 37 | 38 | if [ "$#" -gt 0 -a "$1" = up ]; then 39 | pullImage ${MINIMESOS_CLI_IMAGE} ${MINIMESOS_TAG} 40 | fi 41 | 42 | if [ $(uname) == "Darwin" ]; then 43 | MINIMESOS_OS="Mac OS X" 44 | else 45 | MINIMESOS_OS="Linux" 46 | fi 47 | 48 | MINIMESOS_HOST_DIR="$(pwd)" 49 | MINIMESOS_DIR="$(pwd)/.minimesos" 50 | if [ ! -d "${MINIMESOS_DIR}" ]; then 51 | mkdir -p "${MINIMESOS_DIR}" 52 | echo "# Created minimesos directory at ${MINIMESOS_DIR}." 53 | fi 54 | 55 | 56 | DOCKER_CONTAINER=$( 57 | docker create --rm \ 58 | -v "${MINIMESOS_HOST_DIR}":"${MINIMESOS_HOST_DIR}" \ 59 | -v /var/run/docker.sock:/var/run/docker.sock \ 60 | -v /sys/fs/cgroup:/sys/fs/cgroup \ 61 | -i \ 62 | --env DOCKER_HOST_IP=${DOCKER_HOST_IP} \ 63 | --env MINIMESOS_OS="${MINIMESOS_OS}" \ 64 | --entrypoint java \ 65 | ${MINIMESOS_CLI_IMAGE}:${MINIMESOS_TAG} \ 66 | -Dminimesos.file="/minimesosFile" \ 67 | -Dminimesos.host.dir="${MINIMESOS_HOST_DIR}" \ 68 | -jar /usr/local/share/minimesos/minimesos-cli.jar ${PARAMS} \ 69 | ) 70 | 71 | docker cp ${MINIMESOS_HOST_DIR}/minimesosFile $DOCKER_CONTAINER:/minimesosFile 72 | docker start -a $DOCKER_CONTAINER 73 | -------------------------------------------------------------------------------- /cli/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie-backports 2 | FROM openjdk:8-jre-alpine 3 | MAINTAINER Container Solutions BV 4 | 5 | RUN apk add --update curl libstdc++&& \ 6 | rm -rf /var/cache/apk/* 7 | 8 | RUN curl https://get.docker.com/builds/Linux/x86_64/docker-1.12.0.tgz -o docker-1.12.0.tgz && \ 9 | tar xzf docker-1.12.0.tgz && \ 10 | mv docker/docker /usr/bin/docker && \ 11 | chmod +x /usr/bin/docker 12 | 13 | ADD minimesos-cli.jar /usr/local/share/minimesos/minimesos-cli.jar 14 | -------------------------------------------------------------------------------- /cli/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'application' 2 | 3 | import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage 4 | import com.bmuschko.gradle.docker.tasks.image.DockerPushImage 5 | import com.bmuschko.gradle.docker.tasks.image.DockerTagImage 6 | 7 | dependencies { 8 | compile 'com.beust:jcommander:1.48' 9 | compile 'org.slf4j:slf4j-api:1.7.12' 10 | 11 | compile project(':minimesos') 12 | 13 | testCompile 'junit:junit:4.11' 14 | testCompile "org.mockito:mockito-core:1.+" 15 | testCompile "guru.nidi:jdepend:2.9.5" 16 | } 17 | 18 | mainClassName = "com.containersol.minimesos.main.Main" 19 | 20 | ext { 21 | imageName = repository + '/minimesos-cli' 22 | } 23 | 24 | jar { 25 | baseName = "minimesos-cli" 26 | from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 27 | manifest { 28 | attributes( 29 | 'Main-Class': mainClassName, 30 | 'Implementation-Version': project.version 31 | ) 32 | } 33 | exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' 34 | } 35 | 36 | artifacts { 37 | archives jar 38 | } 39 | 40 | task copyFilesForDocker(type: Copy) { 41 | dependsOn 'jar' 42 | from "build/libs/minimesos-cli-${project.version}.jar" 43 | into 'build/docker' 44 | rename { String fileName -> 45 | fileName.replace("-${project.version}", "") 46 | } 47 | } 48 | 49 | task copyDockerfile(type: Copy) { 50 | dependsOn 'copyFilesForDocker' 51 | from "Dockerfile" 52 | into 'build/docker' 53 | } 54 | 55 | task buildDockerImage(type: DockerBuildImage, dependsOn: [copyDockerfile], description: 'build Docker image') { 56 | inputDir = new File("${buildDir}/docker") 57 | setTag(project.imageName) 58 | } 59 | 60 | afterEvaluate { project -> 61 | for (tag in ['snapshot', 'version']) { 62 | String uppercasedTag = tag.capitalize() 63 | 64 | task "tagDockerImageWith$uppercasedTag"(type: DockerTagImage, description: 'tag Docker image') { 65 | setImageId(project.imageName) 66 | setTag('version' == tag ? project.version : tag) 67 | setRepository(project.imageName) 68 | setForce(true) 69 | } 70 | 71 | task "publishDockerImageWith$uppercasedTag"(type: DockerPushImage, dependsOn: ["tagDockerImageWith$uppercasedTag"], 72 | description: 'publish Docker image') { 73 | setImageName(project.imageName) 74 | setTag('version' == tag ? project.version : tag) 75 | } 76 | } 77 | } 78 | 79 | sourceSets { 80 | integrationTest { 81 | java { 82 | compileClasspath += main.output + test.output 83 | runtimeClasspath += main.output + test.output 84 | srcDir file('src/integration-test/java') 85 | } 86 | resources.srcDir file('src/integration-test/resources') 87 | } 88 | } 89 | 90 | configurations { 91 | integrationTestCompile.extendsFrom mainCompile 92 | integrationTestCompile.extendsFrom testCompile 93 | integrationTestRuntime.extendsFrom mainRuntime 94 | integrationTestRuntime.extendsFrom testRuntime 95 | } 96 | 97 | task integrationTest(type: Test) { 98 | testClassesDir = sourceSets.integrationTest.output.classesDir 99 | classpath = sourceSets.integrationTest.runtimeClasspath 100 | testLogging { 101 | showStandardStreams = true 102 | } 103 | } 104 | 105 | integrationTest.dependsOn buildDockerImage 106 | 107 | project.build.dependsOn buildDockerImage 108 | 109 | assemble.dependsOn jar 110 | -------------------------------------------------------------------------------- /cli/src/integration-test/java/com/containersol/minimesos/main/CommandInitTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.config.ClusterConfig; 6 | import org.apache.commons.io.FileUtils; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.nio.file.Files; 13 | import java.nio.file.Paths; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertTrue; 17 | 18 | public class CommandInitTest { 19 | 20 | private CommandInit commandInit; 21 | 22 | @Before 23 | public void before() { 24 | commandInit = new CommandInit(); 25 | } 26 | 27 | @Test 28 | public void testFileContent() throws IOException { 29 | String fileContent = commandInit.getConfigFileContent(); 30 | assertTrue("agent section is not found", fileContent.contains("agent {")); 31 | assertTrue("agent resources section is not found", fileContent.contains("resources {")); 32 | assertTrue("zookeeper section is not found", fileContent.contains("zookeeper {")); 33 | assertTrue("consul section is not found", fileContent.contains("consul {")); 34 | assertTrue("registrator section is not found", fileContent.contains("registrator {")); 35 | assertTrue("mesosdns section is not found", fileContent.contains("mesosdns {")); 36 | } 37 | 38 | @Test(expected = MinimesosException.class) 39 | public void testExecute_existingMiniMesosFile() throws IOException { 40 | String oldHostDir = System.getProperty(MesosCluster.MINIMESOS_HOST_DIR_PROPERTY); 41 | File dir = File.createTempFile("mimimesos-test", "dir"); 42 | assertTrue("Failed to delete temp file", dir.delete()); 43 | assertTrue("Failed to create temp directory", dir.mkdir()); 44 | System.setProperty(MesosCluster.MINIMESOS_HOST_DIR_PROPERTY, dir.getAbsolutePath()); 45 | 46 | 47 | File minimesosFile = new File(dir, ClusterConfig.DEFAULT_CONFIG_FILE); 48 | Files.write(Paths.get(minimesosFile.getAbsolutePath()), "minimesos { }".getBytes()); 49 | 50 | try { 51 | commandInit.execute(); 52 | } finally { 53 | if (oldHostDir == null) { 54 | System.getProperties().remove(MesosCluster.MINIMESOS_HOST_DIR_PROPERTY); 55 | } else { 56 | System.setProperty(MesosCluster.MINIMESOS_HOST_DIR_PROPERTY, oldHostDir); 57 | } 58 | FileUtils.forceDelete(dir); 59 | } 60 | } 61 | 62 | @Test 63 | public void testValidateParameters() { 64 | assertTrue(commandInit.validateParameters()); 65 | } 66 | 67 | @Test 68 | public void testName() { 69 | assertEquals("init", commandInit.getName()); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cli/src/integration-test/java/com/containersol/minimesos/main/CommandPsTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.containersol.minimesos.cluster.ClusterRepository; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.cluster.MesosClusterFactory; 6 | import com.containersol.minimesos.mesos.MesosMasterContainer; 7 | import com.containersol.minimesos.state.Discovery; 8 | import com.containersol.minimesos.state.Framework; 9 | import com.containersol.minimesos.state.Port; 10 | import com.containersol.minimesos.state.Ports; 11 | import com.containersol.minimesos.state.State; 12 | import com.containersol.minimesos.state.Task; 13 | import org.apache.commons.io.output.ByteArrayOutputStream; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | 17 | import java.io.PrintStream; 18 | import java.io.UnsupportedEncodingException; 19 | import java.util.ArrayList; 20 | 21 | import static java.util.Collections.singletonList; 22 | import static org.junit.Assert.assertEquals; 23 | import static org.mockito.Matchers.any; 24 | import static org.mockito.Mockito.mock; 25 | import static org.mockito.Mockito.when; 26 | 27 | public class CommandPsTest { 28 | 29 | private static final String FORMAT = "%-20s %-20s %-20s %-20s\n"; 30 | private static final Object[] COLUMNS = { "FRAMEWORK", "TASK", "STATE", "PORT"}; 31 | private static final Object[] VALUES = {"marathon", "weave-scope", "TASK_RUNNING", "4040" }; 32 | 33 | private ByteArrayOutputStream outputStream; 34 | 35 | private PrintStream ps; 36 | 37 | @Before 38 | public void initTest() { 39 | outputStream = new ByteArrayOutputStream(); 40 | ps = new PrintStream(outputStream, true); 41 | } 42 | 43 | @Test 44 | public void execute() throws UnsupportedEncodingException { 45 | State state = new State(); 46 | Framework marathon = new Framework(); 47 | marathon.setName("marathon"); 48 | 49 | Task task = new Task(); 50 | task.setName("weave-scope"); 51 | task.setState("TASK_RUNNING"); 52 | 53 | Port port = new Port(); 54 | port.setNumber(4040); 55 | 56 | Ports ports = new Ports(); 57 | ports.setPorts(singletonList(port)); 58 | 59 | Discovery discovery = new Discovery(); 60 | discovery.setPorts(ports); 61 | 62 | task.setDiscovery(discovery); 63 | 64 | ArrayList tasks = new ArrayList<>(); 65 | tasks.add(task); 66 | 67 | marathon.setTasks(tasks); 68 | 69 | ArrayList frameworks = new ArrayList<>(); 70 | frameworks.add(marathon); 71 | state.setFrameworks(frameworks); 72 | 73 | MesosMasterContainer master = mock(MesosMasterContainer.class); 74 | when(master.getState()).thenReturn(state); 75 | 76 | MesosCluster mesosCluster = mock(MesosCluster.class); 77 | when(mesosCluster.getMaster()).thenReturn(master); 78 | 79 | ClusterRepository repository = mock(ClusterRepository.class); 80 | when(repository.loadCluster(any(MesosClusterFactory.class))).thenReturn(mesosCluster); 81 | 82 | CommandPs commandPs = new CommandPs(ps); 83 | commandPs.setRepository(repository); 84 | 85 | commandPs.execute(); 86 | 87 | String result = outputStream.toString("UTF-8"); 88 | assertEquals(String.format(FORMAT, COLUMNS) + String.format(FORMAT, VALUES), result); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /cli/src/integration-test/java/com/containersol/minimesos/main/CommandUninstallTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.ClusterRepository; 5 | import com.containersol.minimesos.cluster.Marathon; 6 | import com.containersol.minimesos.cluster.MesosCluster; 7 | import com.containersol.minimesos.cluster.MesosClusterFactory; 8 | import mesosphere.marathon.client.model.v2.Result; 9 | import org.apache.commons.io.output.ByteArrayOutputStream; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.mockito.Matchers; 13 | import org.mockito.Mockito; 14 | 15 | import java.io.PrintStream; 16 | import java.io.UnsupportedEncodingException; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.mockito.Mockito.when; 20 | 21 | public class CommandUninstallTest { 22 | 23 | private ByteArrayOutputStream outputStream; 24 | 25 | private PrintStream ps; 26 | private Marathon marathon; 27 | private MesosCluster mesosCluster; 28 | private ClusterRepository repository; 29 | private CommandUninstall commandUninstall; 30 | 31 | @Before 32 | public void initTest() { 33 | outputStream = new ByteArrayOutputStream(); 34 | ps = new PrintStream(outputStream, true); 35 | 36 | marathon = Mockito.mock(Marathon.class); 37 | 38 | mesosCluster = Mockito.mock(MesosCluster.class); 39 | when(mesosCluster.getMarathon()).thenReturn(marathon); 40 | 41 | repository = Mockito.mock(ClusterRepository.class); 42 | when(repository.loadCluster(Matchers.any(MesosClusterFactory.class))).thenReturn(mesosCluster); 43 | 44 | commandUninstall = new CommandUninstall(ps); 45 | commandUninstall.setRepository(repository); 46 | } 47 | 48 | @Test 49 | public void execute_app() throws UnsupportedEncodingException { 50 | // Given 51 | commandUninstall.setApp("/app"); 52 | when(marathon.deleteApp("/app")).thenReturn(new Result()); 53 | 54 | // When 55 | commandUninstall.execute(); 56 | 57 | // Then 58 | String string = outputStream.toString("UTF-8"); 59 | assertEquals("Deleted app '/app'\n", string); 60 | } 61 | 62 | @Test 63 | public void execute_group() throws UnsupportedEncodingException { 64 | // Given 65 | commandUninstall.setGroup("/group"); 66 | when(marathon.deleteGroup("/group")).thenReturn(new Result()); 67 | 68 | // When 69 | commandUninstall.execute(); 70 | 71 | // Then 72 | String string = outputStream.toString("UTF-8"); 73 | assertEquals("Deleted group '/group'\n", string); 74 | } 75 | 76 | @Test 77 | public void execute_appAndGroup() throws UnsupportedEncodingException { 78 | // Given 79 | commandUninstall.setGroup("/group1"); 80 | commandUninstall.setApp("/app2"); 81 | 82 | // When 83 | commandUninstall.execute(); 84 | 85 | // Then 86 | String string = outputStream.toString("UTF-8"); 87 | assertEquals("Please specify --app or --group to uninstall an app or group\n", string); 88 | } 89 | 90 | @Test 91 | public void execute_appDoesNotExist() throws UnsupportedEncodingException { 92 | Mockito.doThrow(new MinimesosException("App does not exist")).when(marathon).deleteApp("app"); 93 | 94 | commandUninstall.execute(); 95 | 96 | String result = outputStream.toString("UTF-8"); 97 | assertEquals("Please specify --app or --group to uninstall an app or group\n", result); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /cli/src/integration-test/java/com/containersol/minimesos/main/CommandUpTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.config.ClusterConfig; 6 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.ArgumentCaptor; 10 | 11 | import java.io.IOException; 12 | 13 | import static org.junit.Assert.assertTrue; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | public class CommandUpTest { 19 | 20 | private CommandUp commandUp; 21 | 22 | private ArgumentCaptor capturedClusterConfig; 23 | 24 | private MesosCluster mesosCluster; 25 | 26 | @Before 27 | public void before() { 28 | MesosClusterContainersFactory mesosClusterFactory = mock(MesosClusterContainersFactory.class); 29 | mesosCluster = mock(MesosCluster.class); 30 | when(mesosCluster.getClusterId()).thenReturn("123456"); 31 | 32 | capturedClusterConfig = ArgumentCaptor.forClass(ClusterConfig.class); 33 | when(mesosClusterFactory.createMesosCluster(capturedClusterConfig.capture())).thenReturn(mesosCluster); 34 | 35 | commandUp = new CommandUp(); 36 | commandUp.setMesosClusterFactory(mesosClusterFactory); 37 | } 38 | 39 | @Test(expected = MinimesosException.class) 40 | public void testExecute_missingMinimesosFile() throws IOException { 41 | commandUp.execute(); 42 | } 43 | 44 | @Test(expected = MinimesosException.class) 45 | public void testExecute_invalidMinimesosFile() throws IOException { 46 | commandUp.setClusterConfigPath("src/integration-test/resources/configFiles/invalid-minimesosFile"); 47 | commandUp.execute(); 48 | } 49 | 50 | @Test 51 | public void testBasicClusterConfig() throws IOException { 52 | commandUp.setClusterConfigPath("src/integration-test/resources/clusterconfig/basic.groovy"); 53 | commandUp.execute(); 54 | 55 | verify(mesosCluster).start(); 56 | } 57 | 58 | @Test 59 | public void testExecute_mapPortsToHost() { 60 | commandUp.setClusterConfigPath("src/integration-test/resources/configFiles/complete-minimesosFile"); 61 | commandUp.setMapPortsToHost(true); 62 | commandUp.execute(); 63 | 64 | assertTrue("Map ports to host from configuration is expected to remain", capturedClusterConfig.getValue().isMapPortsToHost()); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "hello", 3 | "cmd": "echo 'hello'", 4 | "cpus": 0.1, 5 | "mem": 16.0, 6 | "instances": 1 7 | } -------------------------------------------------------------------------------- /cli/src/integration-test/resources/clusterconfig/basic.groovy: -------------------------------------------------------------------------------- 1 | package clusterconfig 2 | 3 | minimesos { 4 | 5 | mapPortsToHost = true 6 | timeout = 60 7 | mesosVersion = "1.0.0" 8 | clusterName = "minimesos-test" 9 | 10 | master { 11 | } 12 | 13 | agent { 14 | 15 | resources { 16 | cpu { 17 | role = "logstash" 18 | value = 0.2 19 | } 20 | mem { 21 | role = "logstash" 22 | value = 512 23 | } 24 | disk { 25 | role = "*" 26 | value = 5120 27 | } 28 | } 29 | 30 | imageName = "containersol/mesos-agent" 31 | imageTag = "1.0.0-0.1.0" 32 | 33 | } 34 | 35 | zookeeper { 36 | } 37 | 38 | marathon { 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/clusterconfig/two-agents.groovy: -------------------------------------------------------------------------------- 1 | package clusterconfig 2 | 3 | minimesos { 4 | agent { 5 | resources { 6 | cpu { 7 | role = "*" 8 | value = 2 9 | } 10 | mem { 11 | role = "*" 12 | value = 1024 13 | } 14 | disk { 15 | role = "*" 16 | value = 8192 17 | } 18 | } 19 | } 20 | agent { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/configFiles/complete-minimesosFile: -------------------------------------------------------------------------------- 1 | minimesos { 2 | clusterName = "Change Cluster Name in minimesosFile file" 3 | mapPortsToHost = false 4 | loggingLevel = "INFO" 5 | mapAgentSandboxVolume = false 6 | mesosVersion = "0.28" 7 | timeout = 60 8 | 9 | agent { 10 | imageName = "containersol/mesos-agent" 11 | imageTag = "1.0.0-0.1.0" 12 | loggingLevel = "# INHERIT FROM CLUSTER" 13 | portNumber = 5051 14 | 15 | resources { 16 | 17 | cpu { 18 | role = "*" 19 | value = 4 20 | } 21 | 22 | disk { 23 | role = "*" 24 | value = 2000 25 | } 26 | 27 | mem { 28 | role = "*" 29 | value = 512 30 | } 31 | 32 | ports { 33 | role = "*" 34 | value = "[31000-32000]" 35 | } 36 | } 37 | } 38 | 39 | consul { 40 | imageName = "consul" 41 | imageTag = "0.7.1" 42 | } 43 | 44 | marathon { 45 | imageName = "mesosphere/marathon" 46 | imageTag = "v1.3.5" 47 | } 48 | 49 | master { 50 | aclJson = null 51 | authenticate = false 52 | imageName = "containersol/mesos-master" 53 | imageTag = "1.0.0-0.1.0" 54 | loggingLevel = "# INHERIT FROM CLUSTER" 55 | } 56 | 57 | registrator { 58 | imageName = "gliderlabs/registrator" 59 | imageTag = "v6" 60 | } 61 | 62 | mesosdns { 63 | imageName = "xebia/mesos-dns" 64 | imageTag = "0.0.5" 65 | } 66 | 67 | zookeeper { 68 | imageName = "jplock/zookeeper" 69 | imageTag = "3.4.6" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/configFiles/invalid-minimesosFile.txt: -------------------------------------------------------------------------------- 1 | invalid -------------------------------------------------------------------------------- /cli/src/integration-test/resources/configFiles/marathonAppConfig-minimesosFile: -------------------------------------------------------------------------------- 1 | minimesos { 2 | clusterName = "minimesos-test" 3 | mapPortsToHost = false 4 | loggingLevel = "INFO" 5 | mapAgentSandboxVolume = false 6 | mesosVersion = "0.28" 7 | timeout = 60 8 | 9 | agent { 10 | imageName = "containersol/mesos-agent" 11 | imageTag = "1.0.0-0.1.0" 12 | portNumber = 5051 13 | 14 | resources { 15 | 16 | cpu { 17 | role = "*" 18 | value = 8 19 | } 20 | 21 | disk { 22 | role = "*" 23 | value = 10000 24 | } 25 | 26 | mem { 27 | role = "*" 28 | value = 1024 29 | } 30 | 31 | ports { 32 | role = "*" 33 | value = "[31000-32000]" 34 | } 35 | } 36 | } 37 | 38 | consul { 39 | imageName = "consul" 40 | imageTag = "0.7.1" 41 | } 42 | 43 | marathon { 44 | imageName = "mesosphere/marathon" 45 | imageTag = "v1.3.5" 46 | 47 | app { 48 | marathonJson = "src/test/resources/app.json" 49 | } 50 | 51 | } 52 | 53 | master { 54 | imageName = "containersol/mesos-master" 55 | imageTag = "1.0.0-0.1.0" 56 | } 57 | 58 | registrator { 59 | imageName = "gliderlabs/registrator" 60 | imageTag = "v6" 61 | } 62 | 63 | mesosdns { 64 | imageName = "xebia/mesos-dns" 65 | imageTag = "0.0.5" 66 | } 67 | 68 | zookeeper { 69 | imageName = "jplock/zookeeper" 70 | imageTag = "3.4.6" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/configFiles/withMarathon-minimesosFile: -------------------------------------------------------------------------------- 1 | minimesos { 2 | clusterName = "minimesos-test" 3 | mapPortsToHost = false 4 | loggingLevel = "INFO" 5 | mapAgentSandboxVolume = false 6 | mesosVersion = "0.28" 7 | timeout = 60 8 | 9 | marathon { 10 | imageName = "mesosphere/marathon" 11 | imageTag = "v1.3.5" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cli/src/integration-test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | System.out 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}: %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/Command.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | public interface Command { 4 | 5 | /** 6 | * Validates combination of command parameters 7 | * 8 | * @return true if command parameters are valid 9 | */ 10 | boolean validateParameters(); 11 | 12 | /** 13 | * @return name of the command 14 | */ 15 | String getName(); 16 | 17 | /** 18 | * Executes the command 19 | */ 20 | void execute(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandDestroy.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameters; 4 | import com.containersol.minimesos.cluster.ClusterRepository; 5 | import com.containersol.minimesos.cluster.MesosCluster; 6 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * Parameters for the 'destroy' command. 12 | */ 13 | @Parameters(separators = "=", commandDescription = "Destroy a minimesos cluster") 14 | public class CommandDestroy implements Command { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(CommandDestroy.class); 17 | 18 | public static final String CLINAME = "destroy"; 19 | 20 | private ClusterRepository repository = new ClusterRepository(); 21 | 22 | @Override 23 | public void execute() { 24 | 25 | MesosClusterContainersFactory clusterFactory = new MesosClusterContainersFactory(); 26 | 27 | MesosCluster cluster = repository.loadCluster(clusterFactory); 28 | if (cluster != null) { 29 | cluster.destroy(clusterFactory); 30 | LOGGER.info("Destroyed minimesos cluster with ID " + cluster.getClusterId()); 31 | } else { 32 | LOGGER.info("Minimesos cluster is not running"); 33 | } 34 | } 35 | 36 | @Override 37 | public boolean validateParameters() { 38 | return true; 39 | } 40 | 41 | @Override 42 | public String getName() { 43 | return CLINAME; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandHelp.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameters; 4 | 5 | /** 6 | * Help command 7 | */ 8 | @Parameters(separators = "=", commandDescription = "Display help") 9 | public class CommandHelp implements Command { 10 | 11 | public static final String CLINAME = "help"; 12 | 13 | @Override 14 | public void execute() { 15 | // Usage is being printed from Main 16 | } 17 | 18 | @Override 19 | public boolean validateParameters() { 20 | return true; 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return CLINAME; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandInfo.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import java.io.PrintStream; 4 | import java.net.URI; 5 | import java.util.List; 6 | 7 | import com.beust.jcommander.Parameters; 8 | import com.containersol.minimesos.cluster.ClusterProcess; 9 | import com.containersol.minimesos.cluster.ClusterRepository; 10 | import com.containersol.minimesos.cluster.ClusterUtil; 11 | import com.containersol.minimesos.cluster.MesosCluster; 12 | import com.containersol.minimesos.cluster.MesosDns; 13 | import com.containersol.minimesos.docker.DockerContainersUtil; 14 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 15 | import com.containersol.minimesos.util.Environment; 16 | 17 | /** 18 | * Info command 19 | */ 20 | @Parameters(separators = "=", commandDescription = "Display cluster information") 21 | public class CommandInfo implements Command { 22 | 23 | public static final String CLINAME = "info"; 24 | 25 | private PrintStream output = System.out; //NOSONAR 26 | 27 | private ClusterRepository repository = new ClusterRepository(); 28 | 29 | public CommandInfo() { //NOSONAR 30 | } 31 | 32 | public CommandInfo(PrintStream ps) { 33 | this.output = ps; 34 | } 35 | 36 | @Override 37 | public void execute() { 38 | String clusterId = repository.readClusterId(); 39 | if (clusterId != null) { 40 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 41 | if (cluster != null) { 42 | output.println("Minimesos cluster is running: " + cluster.getClusterId()); 43 | output.println("Mesos version: " + cluster.getMaster().getState().getVersion()); 44 | printServiceUrls(cluster); 45 | 46 | MesosDns mesosDns = cluster.getMesosDns(); 47 | if (mesosDns != null) { 48 | output.println("Running dnsmasq? Add 'server=/mm/" + mesosDns.getIpAddress() + "#53' to /etc/dnsmasq.d/10-minimesos to resolve master.mm, zookeeper.mm and Marathon apps on app.marathon.mm."); 49 | } 50 | } else { 51 | output.println(String.format("Minimesos cluster %s is not running. %s is removed", clusterId, repository.getMinimesosFile().getAbsolutePath())); 52 | } 53 | } else { 54 | output.println("Cluster ID is not found in " + repository.getMinimesosFile().getAbsolutePath()); 55 | } 56 | } 57 | 58 | /** 59 | * Prints cluster services URLs and IPs 60 | * 61 | * @param cluster to examine 62 | */ 63 | private void printServiceUrls(MesosCluster cluster) { 64 | 65 | // print independent from roles variables 66 | String masterContainer = cluster.getMaster().getContainerId(); 67 | String gateway = String.format("export %s=%s", MesosCluster.TOKEN_NETWORK_GATEWAY, DockerContainersUtil.getGatewayIpAddress(masterContainer)); 68 | output.println(gateway); 69 | 70 | List uniqueMembers = ClusterUtil.getDistinctRoleProcesses(cluster.getMemberProcesses()); 71 | for (ClusterProcess process : uniqueMembers) { 72 | 73 | URI serviceUrl = process.getServiceUrl(); 74 | if (serviceUrl != null) { 75 | String service = String.format("export %s%s=%s", MesosCluster.MINIMESOS_TOKEN_PREFIX, process.getRole().toUpperCase(), serviceUrl.toString()); 76 | String serviceIp = String.format("export %s%s_IP=%s", MesosCluster.MINIMESOS_TOKEN_PREFIX, process.getRole().toUpperCase(), serviceUrl.getHost()); 77 | 78 | output.println(String.format("%s; %s", service, serviceIp)); 79 | } 80 | 81 | } 82 | 83 | if (Environment.isRunningInDockerOnMac()) { 84 | output.println("You are running Docker on Mac so use localhost instead of container IPs for Master, Marathon, Zookeepr and Consul"); 85 | } 86 | } 87 | 88 | @Override 89 | public boolean validateParameters() { 90 | return true; 91 | } 92 | 93 | @Override 94 | public String getName() { 95 | return CLINAME; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandInit.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.FileSystems; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.nio.file.attribute.UserPrincipal; 10 | import java.nio.file.attribute.UserPrincipalLookupService; 11 | 12 | import com.beust.jcommander.Parameters; 13 | import com.containersol.minimesos.MinimesosException; 14 | import com.containersol.minimesos.cluster.MesosCluster; 15 | import com.containersol.minimesos.config.AppConfig; 16 | import com.containersol.minimesos.config.ClusterConfig; 17 | import com.containersol.minimesos.config.ConfigParser; 18 | import com.containersol.minimesos.config.ConsulConfig; 19 | import com.containersol.minimesos.config.MarathonConfig; 20 | import com.containersol.minimesos.config.MesosAgentConfig; 21 | import com.containersol.minimesos.config.MesosDNSConfig; 22 | import com.containersol.minimesos.config.MesosMasterConfig; 23 | import com.containersol.minimesos.config.RegistratorConfig; 24 | import com.containersol.minimesos.config.ZooKeeperConfig; 25 | 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import static java.lang.String.format; 30 | 31 | /** 32 | * Initializes a default minimesosFile in the directory where minimesos is run 33 | */ 34 | @Parameters(separators = "=", commandDescription = "Initialize a minimesosFile") 35 | public class CommandInit implements Command { 36 | 37 | private static final Logger LOGGER = LoggerFactory.getLogger(CommandInit.class); 38 | 39 | public static final String CLINAME = "init"; 40 | 41 | public static final String DEFAULT_HOST_USERID = "1000"; 42 | 43 | @Override 44 | public boolean validateParameters() { 45 | return true; 46 | } 47 | 48 | @Override 49 | public String getName() { 50 | return CLINAME; 51 | } 52 | 53 | @Override 54 | public void execute() { 55 | File minimesosFile = new File(MesosCluster.getClusterHostDir(), ClusterConfig.DEFAULT_CONFIG_FILE); 56 | 57 | if (minimesosFile.exists()) { 58 | throw new MinimesosException("A minimesosFile already exists in this directory"); 59 | } 60 | 61 | String fileContent = getConfigFileContent(); 62 | 63 | Path minimesosPath = Paths.get(minimesosFile.getAbsolutePath()); 64 | try { 65 | Files.write(minimesosPath, fileContent.getBytes()); 66 | } catch (IOException e) { 67 | throw new MinimesosException(format("Could not initialize minimesosFile: %s", e.getMessage()), e); 68 | } 69 | 70 | LOGGER.info("Initialized minimesosFile in this directory"); 71 | 72 | try { 73 | UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService(); 74 | UserPrincipal owner = lookupService.lookupPrincipalByName(DEFAULT_HOST_USERID); 75 | Files.setOwner(minimesosPath, owner); 76 | } catch (IOException e) { 77 | throw new MinimesosException("NOTE: minimesosFile remains owned by root instead of user ID " + DEFAULT_HOST_USERID + ": " + e.getMessage(), e); 78 | } 79 | 80 | } 81 | 82 | public String getConfigFileContent() { 83 | ClusterConfig config = new ClusterConfig(); 84 | config.setClusterName("Change Cluster Name in " + ClusterConfig.DEFAULT_CONFIG_FILE + " file"); 85 | 86 | config.setMaster(new MesosMasterConfig(ClusterConfig.DEFAULT_MESOS_VERSION)); 87 | config.setZookeeper(new ZooKeeperConfig()); 88 | config.getAgents().add(new MesosAgentConfig(ClusterConfig.DEFAULT_MESOS_VERSION)); 89 | config.setConsul(new ConsulConfig()); 90 | config.setRegistrator(new RegistratorConfig()); 91 | config.setMesosdns(new MesosDNSConfig()); 92 | 93 | AppConfig weaveConfig = new AppConfig(); 94 | weaveConfig.setMarathonJson("https://raw.githubusercontent.com/ContainerSolutions/minimesos/master/opt/apps/weave-scope.json"); 95 | 96 | MarathonConfig marathonConfig = new MarathonConfig(); 97 | marathonConfig.getApps().add(weaveConfig); 98 | config.setMarathon(marathonConfig); 99 | 100 | ConfigParser parser = new ConfigParser(); 101 | return parser.toString(config); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandInstall.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameter; 4 | import com.beust.jcommander.Parameters; 5 | import com.containersol.minimesos.MinimesosException; 6 | import com.containersol.minimesos.cluster.ClusterRepository; 7 | import com.containersol.minimesos.cluster.Marathon; 8 | import com.containersol.minimesos.cluster.MesosCluster; 9 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 10 | import org.apache.commons.io.IOUtils; 11 | 12 | import java.io.IOException; 13 | 14 | import static org.apache.commons.lang.StringUtils.*; 15 | 16 | /** 17 | * Installs an Marathon application or application group. 18 | */ 19 | @Parameters(commandDescription = "Install a Marathon application or application group") 20 | public class CommandInstall implements Command { 21 | 22 | private static final String CLINAME = "install"; 23 | 24 | @Deprecated 25 | @Parameter(names = "--marathonFile", description = "[Deprecated - Please use --marathonApp] Relative path or URL to a JSON file with a Marathon app definition.") 26 | String marathonFile = null; 27 | 28 | @Parameter(names = "--app", description = "Relative path or URL to a JSON file with a Marathon app definition. See https://mesosphere.github.io/marathon/docs/application-basics.html.") 29 | String app = null; 30 | 31 | @Parameter(names = "--group", description = "Relative path or URL to a JSON file with a group of Marathon apps. See https://mesosphere.github.io/marathon/docs/application-groups.html.") 32 | String group = null; 33 | 34 | @Parameter(names = "--stdin", description = "Read JSON file with Marathon app or group definition from stdin.") 35 | private boolean stdin = false; 36 | 37 | @Parameter(names = "--update", description = "Update a running application instead of attempting to deploy a new application") 38 | private boolean update = false; 39 | 40 | ClusterRepository repository = new ClusterRepository(); 41 | 42 | @Override 43 | public void execute() { 44 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 45 | if (cluster != null) { 46 | Marathon marathon = cluster.getMarathon(); 47 | if (marathon == null) { 48 | throw new MinimesosException("Marathon container is not found in cluster " + cluster.getClusterId()); 49 | } 50 | 51 | String marathonJson; 52 | try { 53 | marathonJson = getMarathonJson(); 54 | } catch (IOException e) { 55 | throw new MinimesosException("Failed to read JSON file from path, URL or stdin", e); 56 | } 57 | 58 | if (update) { 59 | marathon.updateApp(marathonJson); 60 | } else if (isNotBlank(app) || isNotBlank(marathonFile)) { 61 | marathon.deployApp(marathonJson); 62 | } else if (isNotBlank(group)) { 63 | marathon.deployGroup(marathonJson); 64 | } else { 65 | throw new MinimesosException("Neither app, group, --stdinApp or --stdinGroup is provided"); 66 | } 67 | } else { 68 | throw new MinimesosException("Running cluster is not found"); 69 | } 70 | } 71 | 72 | /** 73 | * Getting content of the Marathon JSON file if specified or via standard input 74 | * 75 | * @return content of the file or standard input 76 | */ 77 | private String getMarathonJson() throws IOException { 78 | if (stdin) { 79 | return IOUtils.toString(System.in, "UTF-8"); 80 | } else { 81 | if (isNotBlank(marathonFile)) { 82 | return IOUtils.toString(MesosCluster.getInputStream(marathonFile), "UTF-8"); 83 | } else if (isNotBlank(app)) { 84 | return IOUtils.toString(MesosCluster.getInputStream(app), "UTF-8"); 85 | } else if (isNotBlank(group)) { 86 | return IOUtils.toString(MesosCluster.getInputStream(group), "UTF-8"); 87 | } 88 | } 89 | throw new IOException("Please specify a URL or path to Marathon JSON file or use --stdin"); 90 | } 91 | 92 | @Override 93 | public boolean validateParameters() { 94 | return isNotBlank(app) || isNotBlank(group) || isNotBlank(marathonFile); 95 | } 96 | 97 | @Override 98 | public String getName() { 99 | return CLINAME; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandLogs.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameter; 4 | import com.beust.jcommander.Parameters; 5 | import com.containersol.minimesos.MinimesosException; 6 | import com.containersol.minimesos.cluster.ClusterRepository; 7 | import com.containersol.minimesos.cluster.MesosAgent; 8 | import com.containersol.minimesos.cluster.MesosCluster; 9 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 10 | import com.containersol.minimesos.state.Executor; 11 | import com.containersol.minimesos.state.Framework; 12 | import com.containersol.minimesos.state.State; 13 | import com.containersol.minimesos.state.Task; 14 | import com.containersol.minimesos.util.Downloader; 15 | import org.apache.http.client.utils.URIBuilder; 16 | 17 | import java.io.PrintStream; 18 | import java.net.URI; 19 | import java.net.URISyntaxException; 20 | 21 | import static org.apache.commons.lang.StringUtils.isNotBlank; 22 | import static org.apache.commons.lang.StringUtils.isBlank; 23 | 24 | @Parameters(separators = "=", commandDescription = "Fetches the stdout logs of the specified task") 25 | public class CommandLogs implements Command { 26 | 27 | private PrintStream output = System.out; // NOSONAR 28 | 29 | private ClusterRepository repository = new ClusterRepository(); 30 | 31 | private Downloader downloader = new Downloader(); 32 | 33 | @Parameter(names = "--task", description = "Substring of a task ID", required = true) 34 | String taskId = null; 35 | 36 | @Parameter(names = "--stderr", description = "Fetch the stderr logs instead of stdout") 37 | Boolean stderr = false; 38 | 39 | public CommandLogs(PrintStream output) { 40 | this.output = output; 41 | } 42 | 43 | public CommandLogs() { 44 | //NOSONAR 45 | } 46 | 47 | @Override 48 | public boolean validateParameters() { 49 | return isNotBlank(taskId); 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return "logs"; 55 | } 56 | 57 | @Override 58 | public void execute() { 59 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 60 | if (cluster == null) { 61 | output.println("Minimesos cluster is not running"); 62 | return; 63 | } 64 | 65 | State masterState = cluster.getMaster().getState(); 66 | Task task = findTask(masterState, taskId); 67 | if (task == null) { 68 | output.println(String.format("Cannot find task: '%s'", taskId)); 69 | return; 70 | } 71 | 72 | MesosAgent agent = findAgent(cluster, task.getSlaveId()); 73 | if (agent == null) { 74 | output.println(String.format("Cannot find agent: '%s'", task.getSlaveId())); 75 | return; 76 | } 77 | 78 | 79 | String filename = stderr ? "stderr" : "stdout"; 80 | output.println(String.format("[minimesos] Fetching '%s' of task '%s'\n", filename, task.getId())); 81 | URI fileUrl = getFileUrl(agent, task, filename); 82 | String content = downloader.getFileContentAsString(fileUrl.toString()); 83 | output.println(content); 84 | } 85 | 86 | public void setRepository(ClusterRepository repository) { 87 | this.repository = repository; 88 | } 89 | 90 | void setDownloader(Downloader downloader) { 91 | this.downloader = downloader; 92 | } 93 | 94 | private Task findTask(State state, String taskId) { 95 | for (Framework framework : state.getFrameworks()) { 96 | for (Task task: framework.getTasks()) { 97 | if (task.getId().contains(taskId)) { 98 | return task; 99 | } 100 | } 101 | } 102 | return null; 103 | } 104 | 105 | private MesosAgent findAgent(MesosCluster cluster, String slaveId) { 106 | for (MesosAgent agent : cluster.getAgents()) { 107 | State agentState = agent.getState(); 108 | if (agentState.getId().equals(slaveId)) { 109 | return agent; 110 | } 111 | } 112 | return null; 113 | } 114 | 115 | private URI getFileUrl(MesosAgent agent, Task task, String filename) throws MinimesosException { 116 | Executor executor = findExecutor(agent, task); 117 | if (executor == null) { 118 | throw new MinimesosException(String.format("Cannot find executor: '%s'", taskId)); 119 | } 120 | String path = executor.getDirectory(); 121 | URIBuilder uriBuilder = new URIBuilder(agent.getServiceUrl()) 122 | .setPath("/files/download") 123 | .addParameter("path", path + "/" + filename); 124 | URI sandboxUrl = null; 125 | try { 126 | sandboxUrl = uriBuilder.build(); 127 | } catch (URISyntaxException e) { 128 | throw new MinimesosException(e.getMessage()); 129 | } 130 | return sandboxUrl; 131 | } 132 | 133 | private Executor findExecutor(MesosAgent agent, Task task) { 134 | String executorId = task.getExecutorId(); 135 | if (isBlank(executorId)) { // if executorId is empty, try with the taskId 136 | executorId = task.getId(); 137 | } 138 | for (Framework framework : agent.getState().getFrameworks()) { 139 | if (framework.getId().equals(task.getFrameworkId())) { 140 | for (Executor executor : framework.getExecutors()) { 141 | if (executor.getId().equals(executorId)) { 142 | return executor; 143 | } 144 | } 145 | } 146 | } 147 | return null; 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandPs.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameters; 4 | import com.containersol.minimesos.cluster.ClusterRepository; 5 | import com.containersol.minimesos.cluster.MesosCluster; 6 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 7 | import com.containersol.minimesos.state.Framework; 8 | import com.containersol.minimesos.state.State; 9 | import com.containersol.minimesos.state.Task; 10 | 11 | import java.io.PrintStream; 12 | 13 | /** 14 | * Lists tasks on the cluster 15 | */ 16 | @Parameters(separators = "=", commandDescription = "List running tasks") 17 | public class CommandPs implements Command { 18 | 19 | private static final String FORMAT = "%-20s %-20s %-20s %-20s\n"; 20 | 21 | private static final Object[] COLUMNS = { "FRAMEWORK", "TASK", "STATE", "PORT" }; 22 | 23 | private ClusterRepository repository = new ClusterRepository(); 24 | 25 | private PrintStream output = System.out; // NOSONAR 26 | 27 | public CommandPs(PrintStream output) { 28 | this.output = output; 29 | } 30 | 31 | public CommandPs() { 32 | // NOSONAR 33 | } 34 | 35 | @Override 36 | public boolean validateParameters() { 37 | return true; 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | return "ps"; 43 | } 44 | 45 | @Override 46 | public void execute() { 47 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 48 | 49 | if (cluster == null) { 50 | output.println("Minimesos cluster is not running"); 51 | return; 52 | } 53 | 54 | output.printf(FORMAT, COLUMNS); 55 | State state = cluster.getMaster().getState(); 56 | for (Framework framework : state.getFrameworks()) { 57 | for (Task task : framework.getTasks()) { 58 | output.printf(FORMAT, framework.getName(), task.getName(), task.getState(), task.getDiscovery().getPorts().getPorts().get(0).getNumber()); 59 | } 60 | } 61 | } 62 | 63 | public void setRepository(ClusterRepository repository) { 64 | this.repository = repository; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandState.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import java.io.PrintStream; 4 | 5 | import com.beust.jcommander.Parameters; 6 | import com.containersol.minimesos.cluster.ClusterRepository; 7 | import com.containersol.minimesos.cluster.MesosCluster; 8 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 9 | 10 | /** 11 | * Parameters for the 'state' command 12 | */ 13 | @Parameters(separators = "=", commandDescription = "Display the master's state.json file") 14 | public class CommandState implements Command { 15 | 16 | public static final String CLINAME = "state"; 17 | 18 | private PrintStream output = System.out; //NOSONAR 19 | 20 | private ClusterRepository repository = new ClusterRepository(); 21 | 22 | public CommandState() { //NOSONAR 23 | } 24 | 25 | public CommandState(PrintStream ps) { 26 | this.output = ps; 27 | } 28 | 29 | @Override 30 | public void execute() { 31 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 32 | if (cluster != null) { 33 | cluster.state(output); 34 | } else { 35 | output.println("Minimesos cluster is not running"); 36 | } 37 | } 38 | 39 | @Override 40 | public boolean validateParameters() { 41 | return true; 42 | } 43 | 44 | @Override 45 | public String getName() { 46 | return CLINAME; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandUninstall.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameter; 4 | import com.beust.jcommander.Parameters; 5 | import com.containersol.minimesos.MinimesosException; 6 | import com.containersol.minimesos.cluster.ClusterRepository; 7 | import com.containersol.minimesos.cluster.Marathon; 8 | import com.containersol.minimesos.cluster.MesosCluster; 9 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 10 | 11 | import java.io.PrintStream; 12 | 13 | import static org.apache.commons.lang.StringUtils.isNotBlank; 14 | 15 | /** 16 | * Uninstalls a Marathon app or framework 17 | */ 18 | @Parameters(separators = "=", commandDescription = "Uninstall a Marathon app") 19 | public class CommandUninstall implements Command { 20 | 21 | @Parameter(names = "--app", description = "Marathon app to uninstall") 22 | private String app = null; 23 | 24 | @Parameter(names = "--group", description = "Marathon group to uninstall") 25 | private String group = null; 26 | 27 | private ClusterRepository repository = new ClusterRepository(); 28 | 29 | private PrintStream output = System.out; // NOSONAR 30 | 31 | CommandUninstall(PrintStream output) { 32 | this.output = output; 33 | } 34 | 35 | CommandUninstall() { 36 | // NOSONAR 37 | } 38 | 39 | @Override 40 | public boolean validateParameters() { 41 | return true; 42 | } 43 | 44 | @Override 45 | public String getName() { 46 | return "uninstall"; 47 | } 48 | 49 | @Override 50 | public void execute() { 51 | MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); 52 | 53 | if (cluster == null) { 54 | output.println("Minimesos cluster is not running"); 55 | return; 56 | } 57 | 58 | Marathon marathon = cluster.getMarathon(); 59 | if (marathon == null) { 60 | throw new MinimesosException("Marathon container is not found in cluster " + cluster.getClusterId()); 61 | } 62 | 63 | if (isNotBlank(app) && isNotBlank(group)) { 64 | output.println("Please specify --app or --group to uninstall an app or group"); 65 | return; 66 | } 67 | 68 | if (isNotBlank(app)) { 69 | try { 70 | marathon.deleteApp(app); 71 | output.println("Deleted app '" + app + "'"); 72 | } catch (MinimesosException e) { // NOSONAR 73 | output.println(e.getMessage()); 74 | } 75 | } else if (isNotBlank(group)) { 76 | try { 77 | marathon.deleteGroup(group); 78 | output.println("Deleted group '" + group + "'"); 79 | } catch (MinimesosException e) { // NOSONAR 80 | output.println(e.getMessage()); 81 | } 82 | } else { 83 | output.println("Please specify --app or --group to uninstall an app or group"); 84 | } 85 | } 86 | 87 | public void setRepository(ClusterRepository repository) { 88 | this.repository = repository; 89 | } 90 | 91 | void setApp(String app) { 92 | this.app = app; 93 | } 94 | 95 | void setGroup(String group) { 96 | this.group = group; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /cli/src/main/java/com/containersol/minimesos/main/CommandVersion.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.beust.jcommander.Parameters; 4 | 5 | import java.io.PrintStream; 6 | 7 | /** 8 | * Command for printing the minimesos version 9 | */ 10 | @Parameters(separators = "=", commandDescription = "Display the version of minimesos") 11 | public class CommandVersion implements Command { 12 | 13 | public static final String CLI_NAME = "version"; 14 | 15 | private PrintStream output = System.out; //NOSONAR 16 | 17 | public CommandVersion() { // NOSONAR 18 | 19 | } 20 | 21 | public CommandVersion(PrintStream ps) { 22 | this.output = ps; 23 | } 24 | 25 | @Override 26 | public void execute() { 27 | Package mainPackage = Main.class.getPackage(); 28 | String version = mainPackage.getImplementationVersion(); 29 | output.println(version); 30 | } 31 | 32 | @Override 33 | public boolean validateParameters() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public String getName() { 39 | return CLI_NAME; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cli/src/test/java/com/containersol/minimesos/main/CommandInstallTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import com.containersol.minimesos.cluster.ClusterRepository; 4 | import com.containersol.minimesos.cluster.Marathon; 5 | import com.containersol.minimesos.cluster.MesosCluster; 6 | import org.apache.commons.io.IOUtils; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.FileReader; 11 | import java.io.IOException; 12 | 13 | import static org.mockito.Matchers.any; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | public class CommandInstallTest { 19 | 20 | private Marathon marathon; 21 | 22 | private MesosCluster mesosCluster; 23 | 24 | private ClusterRepository repository; 25 | 26 | private CommandInstall command; 27 | 28 | @Before 29 | public void before() { 30 | marathon = mock(Marathon.class); 31 | 32 | mesosCluster = mock(MesosCluster.class); 33 | when(mesosCluster.getMarathon()).thenReturn(marathon); 34 | 35 | repository = mock(ClusterRepository.class); 36 | when(repository.loadCluster(any())).thenReturn(mesosCluster); 37 | 38 | command = new CommandInstall(); 39 | command.repository = repository; 40 | } 41 | 42 | @Test 43 | public void testInstallMarathonFile() throws IOException { 44 | // Given 45 | command.marathonFile = "src/test/resources/app.json"; 46 | 47 | // When 48 | command.execute(); 49 | 50 | // Then 51 | verify(marathon).deployApp(IOUtils.toString(new FileReader(command.marathonFile))); 52 | } 53 | 54 | @Test 55 | public void testInstallMarathonApp() throws IOException { 56 | // Given 57 | command.app = "src/test/resources/app.json"; 58 | 59 | // When 60 | command.execute(); 61 | 62 | // Then 63 | verify(marathon).deployApp(IOUtils.toString(new FileReader(command.app))); 64 | } 65 | 66 | @Test 67 | public void testInstallMarathonGroup() throws IOException { 68 | // Given 69 | command.group = "src/test/resources/group.json"; 70 | 71 | // When 72 | command.execute(); 73 | 74 | // Then 75 | verify(marathon).deployGroup(IOUtils.toString(new FileReader(command.group))); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /cli/src/test/java/com/containersol/minimesos/main/MainTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.main; 2 | 3 | import org.apache.commons.io.output.ByteArrayOutputStream; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.io.PrintStream; 9 | 10 | import static junit.framework.TestCase.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.Mockito.doNothing; 13 | import static org.mockito.Mockito.spy; 14 | import static org.mockito.Mockito.verify; 15 | 16 | public class MainTest { 17 | 18 | private ByteArrayOutputStream outputStream; 19 | private Main main; 20 | 21 | private CommandInfo commandInfo; 22 | private CommandDestroy commandDestroy; 23 | private CommandState commandState; 24 | private CommandInstall commandInstall; 25 | private CommandUp commandUp; 26 | private CommandLogs commandLogs; 27 | 28 | @Before 29 | public void before() { 30 | 31 | outputStream = new ByteArrayOutputStream(); 32 | PrintStream ps = new PrintStream(outputStream, true); 33 | 34 | commandUp = spy(new CommandUp()); 35 | doNothing().when(commandUp).execute(); 36 | 37 | commandDestroy = spy(new CommandDestroy()); 38 | doNothing().when(commandDestroy).execute(); 39 | 40 | commandInfo = spy(new CommandInfo(ps)); 41 | doNothing().when(commandInfo).execute(); 42 | 43 | commandState = spy(new CommandState(ps)); 44 | doNothing().when(commandState).execute(); 45 | 46 | commandInstall = spy(new CommandInstall()); 47 | doNothing().when(commandInstall).execute(); 48 | 49 | commandLogs = spy(new CommandLogs()); 50 | doNothing().when(commandLogs).execute(); 51 | 52 | main = new Main(); 53 | main.setOutput(ps); 54 | main.addCommand(commandUp); 55 | main.addCommand(commandDestroy); 56 | main.addCommand(commandInfo); 57 | main.addCommand(commandState); 58 | main.addCommand(commandInstall); 59 | main.addCommand(commandLogs); 60 | main.addCommand(new CommandHelp()); 61 | 62 | } 63 | 64 | @Test 65 | public void testUp() { 66 | main.run(new String[]{"up"}); 67 | verify(commandUp).execute(); 68 | } 69 | 70 | @Test 71 | public void testDestroy() { 72 | main.run(new String[]{"destroy"}); 73 | verify(commandDestroy).execute(); 74 | } 75 | 76 | @Test 77 | public void testInfo() throws IOException { 78 | main.run(new String[]{"info"}); 79 | verify(commandInfo).execute(); 80 | } 81 | 82 | @Test 83 | public void testState() throws IOException { 84 | main.run(new String[]{"state"}); 85 | verify(commandState).execute(); 86 | } 87 | 88 | @Test 89 | public void testInstall() throws IOException { 90 | main.run(new String[]{"install", "--marathonFile", "bla.json"}); 91 | verify(commandInstall).execute(); 92 | } 93 | 94 | @Test 95 | public void testLogs() throws IOException { 96 | main.run(new String[]{"logs", "--task", "something"}); 97 | verify(commandLogs).execute(); 98 | } 99 | 100 | @Test 101 | public void testLogsNoParameter() throws IOException { 102 | main.run(new String[]{"logs", "--task"}); 103 | String result = outputStream.toString("UTF-8"); 104 | assertTrue(result.contains("Usage: logs [options]")); 105 | } 106 | 107 | @Test 108 | public void testUnsupportedCommand() throws IOException { 109 | main.run(new String[]{"unsupported"}); 110 | String result = outputStream.toString("UTF-8"); 111 | assertUsageText(result); 112 | } 113 | 114 | @Test 115 | public void testMinusMinusHelp() throws IOException { 116 | main.run(new String[]{"--help"}); 117 | String result = outputStream.toString("UTF-8"); 118 | assertUsageText(result); 119 | } 120 | 121 | @Test 122 | public void testInstallNoParameters() throws IOException { 123 | main.run(new String[]{"install"}); 124 | String output = outputStream.toString("UTF-8"); 125 | assertTrue(output.contains("Usage: install [options]")); 126 | } 127 | 128 | @Test 129 | public void testHelp() throws IOException { 130 | main.run(new String[]{"help"}); 131 | String result = outputStream.toString("UTF-8"); 132 | assertUsageText(result); 133 | } 134 | 135 | @Test 136 | public void testNonExistingCommand() throws IOException { 137 | main.run(new String[]{"foo"}); 138 | String result = outputStream.toString("UTF-8"); 139 | assertUsageText(result); 140 | assertFalse(result.contains("Failed to run command 'null'. null")); 141 | } 142 | 143 | private static void assertUsageText(String output) { 144 | assertTrue(output.contains("Usage: minimesos [options] [command] [command options]")); 145 | assertTrue(output.contains("Options:")); 146 | assertTrue(output.contains("Commands:")); 147 | assertTrue(output.contains("Usage: up [options]")); 148 | assertTrue(output.contains("Usage: install [options]")); 149 | assertTrue(output.contains("Usage: state [options]")); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /cli/src/test/resources/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "hello", 3 | "container": { 4 | "type": "MESOS", 5 | "docker": { 6 | "image": "weaveworks/", 7 | "network": "HOST" 8 | } 9 | }, 10 | "cpus": 0.1, 11 | "mem": 16.0, 12 | "instances": 1 13 | } 14 | -------------------------------------------------------------------------------- /cli/src/test/resources/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "pingPongGroup", 3 | "groups": [ 4 | { 5 | "id": "ping", 6 | "cmd": "echo 'ping'", 7 | "cpus": 0.1, 8 | "mem": 16.0, 9 | "instances": 1 10 | } 11 | ,{ 12 | "id": "pong", 13 | "cmd": "echo 'pong'", 14 | "cpus": 0.1, 15 | "mem": 16.0, 16 | "instances": 1 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /docs/cc-cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/docs/cc-cc.png -------------------------------------------------------------------------------- /docs/images/introduction-to-minimesos-screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/docs/images/introduction-to-minimesos-screenshot.jpg -------------------------------------------------------------------------------- /docs/minimesos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/docs/minimesos.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1024M -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 2 | release.useAutomaticVersion = false 3 | version=0.14.0 4 | # faster builds: gradle build -x findBugsM 5 | 6 | -------------------------------------------------------------------------------- /gradle/quality.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'findbugs' 2 | apply plugin: 'checkstyle' 3 | apply plugin: 'pmd' 4 | 5 | tasks.withType(FindBugs) { 6 | excludeFilter = file("$rootProject.projectDir/config/findbugs/excludeFilter.xml") 7 | } 8 | 9 | checkstyle { 10 | toolVersion = "6.6" 11 | } 12 | 13 | pmd { 14 | toolVersion = "5.1.3" 15 | ruleSets = [ 16 | 'java-basic', 17 | 'java-braces', 18 | 'java-clone', 19 | 'java-codesize', 20 | 'java-finalizers' 21 | ] 22 | } -------------------------------------------------------------------------------- /gradle/spock.gradle: -------------------------------------------------------------------------------- 1 | // used for unit tests 2 | apply plugin: 'groovy' 3 | 4 | def spockVersion = '1.0-groovy-2.4' 5 | def powermockVersion = "1.6.1" 6 | 7 | dependencies { 8 | 9 | testCompile "org.codehaus.groovy:groovy-all:2.4.1" 10 | testCompile "org.spockframework:spock-core:$spockVersion" 11 | 12 | testCompile 'cglib:cglib-nodep:2.2.2' // need to mock classes 13 | 14 | // // useful to mock out statics and final classes in Java. 15 | // testCompile "org.powermock:powermock-module-junit4:$powermockVersion" 16 | // testCompile "org.powermock:powermock-module-junit4-rule:$powermockVersion" 17 | // testCompile "org.powermock:powermock-classloading-xstream:$powermockVersion" 18 | // testCompile "org.powermock:powermock-api-mockito:$powermockVersion" 19 | } 20 | 21 | // for spock to live in test java tree 22 | sourceSets { 23 | test { 24 | groovy { srcDir 'src/test/java' } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 21 17:15:12 CEST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /images/minimesos-talk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/images/minimesos-talk.jpg -------------------------------------------------------------------------------- /images/minimesos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/images/minimesos.png -------------------------------------------------------------------------------- /minimesos/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "groovy" 2 | 3 | sourceSets { 4 | main { 5 | groovy { 6 | // this makes the groovy-compiler compile groovy- as well as java-files. 7 | // Needed, because java is normally compiled before groovy. 8 | // Since we are using groovy objects from java, we need it the other way round. 9 | srcDirs = ['src/main/groovy', 'src/main/java'] 10 | } 11 | java { 12 | srcDirs = [] // don't compile Java code twice 13 | } 14 | } 15 | 16 | integrationTest { 17 | java { 18 | compileClasspath += main.output + test.output 19 | runtimeClasspath += main.output + test.output 20 | srcDir file('src/integration-test/java') 21 | } 22 | resources.srcDir file('src/integration-test/resources') 23 | } 24 | } 25 | 26 | dependencies { 27 | compile 'org.codehaus.groovy:groovy-all:2.4.5' 28 | compile 'com.github.docker-java:docker-java:3.0.7' 29 | compile 'junit:junit:4.11' 30 | compile 'com.jayway.awaitility:awaitility:1.6.3' 31 | compile 'com.mashape.unirest:unirest-java:1.4.8' 32 | compile 'org.slf4j:slf4j-api:1.7.12' 33 | compile 'com.mesosphere:marathon-client:0.3.0' 34 | compile 'com.google.code.gson:gson-parent:2.8.0' 35 | 36 | compile 'ch.qos.logback:logback-core:1.1.3' 37 | compile 'ch.qos.logback:logback-classic:1.1.3' 38 | 39 | compile 'com.beust:jcommander:1.48' 40 | 41 | testCompile "org.mockito:mockito-core:1.+" 42 | // using guru.nidi as maintenanance of the original project is dropped https://github.com/clarkware/jdepend/pull/9 43 | testCompile "guru.nidi:jdepend:2.9.5" 44 | 45 | integrationTestCompile 'junit:junit:4.11' 46 | integrationTestCompile 'com.jayway.awaitility:awaitility:1.6.3' 47 | } 48 | 49 | compileGroovy { 50 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 51 | } 52 | 53 | configurations { 54 | integrationTestCompile.extendsFrom mainCompile 55 | integrationTestCompile.extendsFrom testCompile 56 | integrationTestRuntime.extendsFrom mainRuntime 57 | integrationTestRuntime.extendsFrom testRuntime 58 | } 59 | 60 | task integrationTest(type: Test) { 61 | testClassesDir = sourceSets.integrationTest.output.classesDir 62 | classpath = sourceSets.integrationTest.runtimeClasspath 63 | testLogging { 64 | showStandardStreams = true 65 | } 66 | } 67 | 68 | task installMinimesosScript(type: Copy) { 69 | from "$rootDir/bin/minimesos" 70 | into "/usr/local/bin" 71 | } 72 | 73 | integrationTest.dependsOn project(":cli").buildDockerImage 74 | -------------------------------------------------------------------------------- /minimesos/src/integration-test/java/com.containersol.minimesos/integrationtest/AuthenticationTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest; 2 | 3 | import com.containersol.minimesos.cluster.MesosCluster; 4 | import com.containersol.minimesos.junit.MesosClusterTestRule; 5 | import com.mashape.unirest.http.exceptions.UnirestException; 6 | import org.junit.Assert; 7 | import org.junit.ClassRule; 8 | import org.junit.Test; 9 | 10 | public class AuthenticationTest { 11 | 12 | public static final String aclExampleUnknownSyntaxUsedInStateJson = "run_tasks {\n principals {\n values: \"foo\"\n values: \"bar\"\n }\n users {\n values: \"alice\"\n }\n}\n"; 13 | 14 | @ClassRule 15 | public static final MesosClusterTestRule RULE = MesosClusterTestRule.fromFile("src/test/resources/configFiles/minimesosFile-authenticationTest"); 16 | 17 | public static MesosCluster CLUSTER = RULE.getMesosCluster(); 18 | 19 | @Test 20 | public void clusterHasZookeeperUrl() throws UnirestException { 21 | Assert.assertEquals("zk://" + CLUSTER.getZooKeeper().getIpAddress() + ":2181/mesos", CLUSTER.getMaster().getState().getFlags().get("zk")); 22 | } 23 | 24 | /** 25 | * See https://issues.apache.org/jira/browse/MESOS-3792. Because of this bug the acl values are represented 26 | * as separate key value pairs. 27 | */ 28 | @Test 29 | public void extraEnvironmentVariablesPassedToMesosMaster() throws UnirestException { 30 | Assert.assertEquals("true", CLUSTER.getMaster().getState().getFlags().get("authenticate")); 31 | Assert.assertEquals(aclExampleUnknownSyntaxUsedInStateJson, CLUSTER.getMaster().getState().getFlags().get("acls")); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /minimesos/src/integration-test/java/com.containersol.minimesos/integrationtest/container/HelloWorldContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest.container; 2 | 3 | import com.containersol.minimesos.config.ContainerConfigBlock; 4 | import com.containersol.minimesos.docker.DockerClientFactory; 5 | import com.github.dockerjava.api.command.CreateContainerCmd; 6 | import com.github.dockerjava.api.model.ExposedPort; 7 | 8 | /** 9 | * A container for testing purposes. A small web server on port 80 returns the message "hello world." 10 | */ 11 | public class HelloWorldContainer extends AbstractContainer { 12 | public static final String SERVICE_NAME = "hello-world-service"; 13 | public static final int SERVICE_PORT = 80; 14 | public static final String HELLO_WORLD_IMAGE = "tutum/hello-world"; 15 | public static final String CONTAINER_NAME_PATTERN = "^helloworld-[0-9a-f\\-]*$"; 16 | 17 | public HelloWorldContainer() { 18 | super(new ContainerConfigBlock(HELLO_WORLD_IMAGE, "latest")); 19 | } 20 | 21 | @Override 22 | public String getRole() { 23 | return "helloworld"; 24 | } 25 | 26 | @Override 27 | protected CreateContainerCmd dockerCommand() { 28 | ExposedPort exposedPort = ExposedPort.tcp(SERVICE_PORT); 29 | // port mapping is not used as port 80 is ofthen occupied on host 30 | return DockerClientFactory.build().createContainerCmd(HELLO_WORLD_IMAGE) 31 | .withEnv(String.format("SERVICE_%d_NAME=%s", SERVICE_PORT, SERVICE_NAME)) 32 | .withPrivileged(true) 33 | .withName(getName()) 34 | .withExposedPorts(exposedPort); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /minimesos/src/integration-test/java/com.containersol.minimesos/integrationtest/container/MesosExecuteContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest.container; 2 | 3 | import com.containersol.minimesos.integrationtest.MesosClusterTest; 4 | import com.containersol.minimesos.config.ClusterConfig; 5 | import com.containersol.minimesos.config.ContainerConfigBlock; 6 | import com.containersol.minimesos.config.MesosAgentConfig; 7 | import com.containersol.minimesos.docker.DockerClientFactory; 8 | import com.github.dockerjava.api.command.CreateContainerCmd; 9 | 10 | public class MesosExecuteContainer extends AbstractContainer { 11 | 12 | private static final String TASK_CLUSTER_ROLE = "test"; 13 | 14 | public MesosExecuteContainer() { 15 | super(new ContainerConfigBlock(MesosAgentConfig.MESOS_AGENT_IMAGE, ClusterConfig.DEFAULT_MESOS_CONTAINER_TAG)); 16 | } 17 | 18 | @Override 19 | public String getRole() { 20 | return TASK_CLUSTER_ROLE; 21 | } 22 | 23 | @Override 24 | protected CreateContainerCmd dockerCommand() { 25 | return DockerClientFactory.build().createContainerCmd(String.format("%s:%s", MesosAgentConfig.MESOS_AGENT_IMAGE, ClusterConfig.DEFAULT_MESOS_CONTAINER_TAG)) 26 | .withName(getName()) 27 | .withEntrypoint( 28 | "mesos-execute", 29 | "--master=" + MesosClusterTest.CLUSTER.getMaster().getIpAddress() + ":5050", 30 | "--command=echo 1", 31 | "--name=test-cmd", 32 | "--resources=cpus:0.1;mem:128" 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/AgentResourcesConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import groovy.util.logging.Slf4j 4 | 5 | import java.util.regex.Matcher 6 | 7 | @Slf4j 8 | class AgentResourcesConfig extends GroovyBlock { 9 | 10 | static public final ResourceDefScalar DEFAULT_CPU = new ResourceDefScalar("*", 4) 11 | static public final ResourceDefScalar DEFAULT_MEM = new ResourceDefScalar("*", 1024) 12 | static public final ResourceDefScalar DEFAULT_DISK = new ResourceDefScalar("*", 2000) 13 | static public final ResourceDefRanges DEFAULT_PORTS = new ResourceDefRanges("*", "[31000-32000]") 14 | 15 | HashMap cpus 16 | HashMap mems 17 | HashMap disks 18 | HashMap ports 19 | 20 | public AgentResourcesConfig() { 21 | this(true) 22 | } 23 | 24 | private AgentResourcesConfig(boolean defaults) { 25 | cpus = new HashMap<>() 26 | mems = new HashMap<>() 27 | disks = new HashMap<>() 28 | ports = new HashMap<>() 29 | if (defaults) { 30 | setDefaults() 31 | } 32 | } 33 | 34 | private void setDefaults() { 35 | addResource(cpus, DEFAULT_CPU) 36 | addResource(mems, DEFAULT_MEM) 37 | addResource(disks, DEFAULT_DISK) 38 | addResource(ports, DEFAULT_PORTS) 39 | } 40 | 41 | /** 42 | * Generates resources object from Mesos string definition 43 | * @param strResources in format like ports(*):[8081-8082]; cpus(*):1.2 44 | * @return 45 | */ 46 | static AgentResourcesConfig fromString(String strResources) { 47 | 48 | String pattern = "(\\w+)\\(([A-Za-z0-9_\\*]+)\\):(\\[?[0-9_\\-\\*., ]+\\]?)" 49 | AgentResourcesConfig resources = new AgentResourcesConfig(false) 50 | 51 | String[] split = strResources.split(";") 52 | for (String str : split) { 53 | Matcher matcher = str.trim() =~ pattern 54 | if (matcher.matches() && (matcher.groupCount() == 3)) { 55 | String type = matcher.group(1) 56 | String role = matcher.group(2) 57 | String value = matcher.group(3) 58 | 59 | switch (type) { 60 | case "ports": 61 | resources.ports.put(role, new ResourceDefRanges(role, value)) 62 | break 63 | case "cpus": 64 | resources.cpus.put(role, new ResourceDefScalar(role, Double.valueOf(value))) 65 | break 66 | case "mem": 67 | resources.mems.put(role, new ResourceDefScalar(role, Double.valueOf(value))) 68 | break 69 | case "disk": 70 | resources.disks.put(role, new ResourceDefScalar(role, Double.valueOf(value))) 71 | break 72 | } 73 | 74 | } 75 | } 76 | 77 | return resources 78 | } 79 | 80 | def cpu(@DelegatesTo(ResourceDef) Closure cl) { 81 | addResource(cpus, loadResourceDef(cl, ResourceDefScalar.class)) 82 | } 83 | 84 | def mem(@DelegatesTo(ResourceDef) Closure cl) { 85 | addResource(mems, loadResourceDef(cl, ResourceDefScalar.class)) 86 | } 87 | 88 | def disk(@DelegatesTo(ResourceDef) Closure cl) { 89 | addResource(disks, loadResourceDef(cl, ResourceDefScalar.class)) 90 | } 91 | 92 | def ports(@DelegatesTo(ResourceDef) Closure cl) { 93 | addResource(ports, loadResourceDef(cl, ResourceDefRanges.class)) 94 | } 95 | 96 | ResourceDef loadResourceDef(Closure cl, Class resourceDefClass) { 97 | ResourceDef resource = resourceDefClass.newInstance() 98 | delegateTo(resource, cl) 99 | return resource 100 | } 101 | 102 | /** 103 | * 104 | * @return formatted string with definition of resources. Example: ports(*):[31000-32000]; cpus(*):0.2; mem(*):256; disk(*):200 105 | */ 106 | String asMesosString() { 107 | 108 | StringBuilder builder = new StringBuilder() 109 | 110 | for (ResourceDef resourceDef : ports.values()) { 111 | appendResource(builder, resourceDef, "ports") 112 | } 113 | for (ResourceDef resourceDef : cpus.values()) { 114 | appendResource(builder, resourceDef, "cpus") 115 | } 116 | for (ResourceDef resourceDef : mems.values()) { 117 | appendResource(builder, resourceDef, "mem") 118 | } 119 | for (ResourceDef resourceDef : disks.values()) { 120 | appendResource(builder, resourceDef, "disk") 121 | } 122 | 123 | return builder.toString() 124 | 125 | } 126 | 127 | static void appendResource(StringBuilder builder, ResourceDef resourceDef, String res) { 128 | if (builder.length() > 0) { 129 | builder.append("; ") 130 | } 131 | builder.append(res).append("(").append(resourceDef.role).append("):").append(resourceDef.valueAsString()); 132 | } 133 | 134 | static void addResource(HashMap resources, ResourceDef resource) { 135 | resources.put(resource.role, resource) 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/AppConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | /** 4 | * Configuration for a Marathon app. Path is relative to the minimesosFile. 5 | */ 6 | class AppConfig { 7 | 8 | private String marathonJson 9 | 10 | void setMarathonJson(String marathonJson) { 11 | this.marathonJson = marathonJson 12 | } 13 | 14 | String getMarathonJson() { 15 | return marathonJson 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ClusterConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import groovy.util.logging.Slf4j 4 | import org.apache.commons.lang.StringUtils 5 | 6 | @Slf4j 7 | class ClusterConfig extends GroovyBlock { 8 | 9 | public static final int DEFAULT_TIMEOUT_SECS = 60 10 | public static final String DEFAULT_MESOS_VERSION = "1.0.0" 11 | public static final String DEFAULT_MINIMESOS_DOCKER_VERSION = "0.1.0" 12 | public static final String DEFAULT_MESOS_CONTAINER_TAG = DEFAULT_MESOS_VERSION + "-" + DEFAULT_MINIMESOS_DOCKER_VERSION 13 | public static final String DEFAULT_CONFIG_FILE = "minimesosFile" 14 | public static final String DEFAULT_LOGGING_LEVEL = "INFO" 15 | 16 | def call(Closure cl) { 17 | cl.setDelegate(this) 18 | cl.setResolveStrategy(Closure.DELEGATE_ONLY) 19 | cl.call() 20 | } 21 | 22 | boolean mapPortsToHost = false 23 | boolean mapAgentSandboxVolume = false 24 | 25 | int timeout = DEFAULT_TIMEOUT_SECS 26 | String mesosVersion = DEFAULT_MESOS_VERSION 27 | String clusterName = null 28 | String loggingLevel = DEFAULT_LOGGING_LEVEL 29 | 30 | MesosMasterConfig master = null 31 | List agents = new ArrayList<>() 32 | ZooKeeperConfig zookeeper = null 33 | MarathonConfig marathon = null 34 | MesosDNSConfig mesosdns = null 35 | ConsulConfig consul = null 36 | RegistratorConfig registrator = null 37 | 38 | def master(@DelegatesTo(MesosMasterConfig) Closure cl) { 39 | if (master != null) { 40 | throw new RuntimeException("Multiple Masters are not supported in this version yet") 41 | } 42 | master = new MesosMasterConfig(mesosVersion) 43 | delegateTo(master, cl) 44 | } 45 | 46 | def agent(@DelegatesTo(MesosAgentConfig) Closure cl) { 47 | def agent = new MesosAgentConfig(mesosVersion) 48 | delegateTo(agent, cl) 49 | agents.add(agent) 50 | } 51 | 52 | def zookeeper(@DelegatesTo(ZooKeeperConfig) Closure cl) { 53 | if (zookeeper != null) { 54 | throw new RuntimeException("Multiple Zookeepers are not supported in this version yet") 55 | } 56 | zookeeper = new ZooKeeperConfig() 57 | delegateTo(zookeeper, cl) 58 | } 59 | 60 | def marathon(@DelegatesTo(MarathonConfig) Closure cl) { 61 | if (marathon != null) { 62 | throw new RuntimeException("Cannot have more than 1 marathon") 63 | } 64 | marathon = new MarathonConfig() 65 | delegateTo(marathon, cl) 66 | } 67 | 68 | def mesosdns(@DelegatesTo(MesosDNSConfig) Closure cl) { 69 | if (mesosdns != null) { 70 | throw new RuntimeException("Cannot have more than 1 mesosDNS") 71 | } 72 | mesosdns = new MesosDNSConfig() 73 | delegateTo(mesosdns, cl) 74 | } 75 | 76 | def consul(@DelegatesTo(ConsulConfig) Closure cl) { 77 | if (consul != null) { 78 | throw new RuntimeException("Cannot have more than 1 Consul server") 79 | } 80 | consul = new ConsulConfig() 81 | delegateTo(consul, cl) 82 | } 83 | 84 | def registrator(@DelegatesTo(RegistratorConfig) Closure cl) { 85 | if (registrator != null) { 86 | throw new RuntimeException("Cannot have more than 1 registrator") 87 | } 88 | registrator = new RegistratorConfig() 89 | delegateTo(registrator, cl) 90 | } 91 | 92 | void setLoggingLevel(String loggingLevel) { 93 | if (!StringUtils.equalsIgnoreCase(loggingLevel, "WARNING") && !StringUtils.equalsIgnoreCase(loggingLevel, "INFO") && !StringUtils.equalsIgnoreCase(loggingLevel, "ERROR")) { 94 | throw new RuntimeException("Property 'loggingLevel' can only have the values INFO, WARNING or ERROR. Got '" + loggingLevel + "'") 95 | } 96 | this.loggingLevel = loggingLevel.toUpperCase() 97 | } 98 | 99 | void setMesosVersion(String mesosVersion) { 100 | if (!MesosContainerConfig.MESOS_VERSIONS.contains(mesosVersion)) { 101 | throw new RuntimeException("Property 'mesosVersion' supports values: " + StringUtils.join(MesosContainerConfig.MESOS_VERSIONS, ",")) 102 | } 103 | this.mesosVersion = mesosVersion 104 | } 105 | 106 | String getLoggingLevel() { 107 | return loggingLevel 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ConsulConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | public class ConsulConfig extends ContainerConfigBlock implements ContainerConfig { 4 | 5 | public static final String CONSUL_IMAGE_NAME = "consul" 6 | public static final String CONSUL_TAG_NAME = "0.7.1" 7 | 8 | public static final int CONSUL_HTTP_PORT = 8500 9 | public static final int CONSUL_DNS_PORT = 8600 10 | 11 | public ConsulConfig() { 12 | imageName = CONSUL_IMAGE_NAME 13 | imageTag = CONSUL_TAG_NAME 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ContainerConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | /** 4 | * Common methods for containers' configuration 5 | */ 6 | interface ContainerConfig { 7 | 8 | String getImageName() 9 | 10 | void setImageName(String imageName) 11 | 12 | String getImageTag() 13 | 14 | void setImageTag(String imageTag) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ContainerConfigBlock.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | public class ContainerConfigBlock extends GroovyBlock implements ContainerConfig { 4 | 5 | String imageName; 6 | String imageTag; 7 | 8 | public ContainerConfigBlock() { 9 | } 10 | 11 | public ContainerConfigBlock(String name, String tag) { 12 | this.imageName = name 13 | this.imageTag = tag; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/GroovyBlock.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | /** 4 | * Contains a collection of properties for a configuration object. 5 | */ 6 | class GroovyBlock { 7 | 8 | def delegateTo(Object obj, Closure cl) { 9 | def code = cl.rehydrate(obj, this, this) 10 | code.resolveStrategy = Closure.DELEGATE_ONLY 11 | code() 12 | } 13 | 14 | def methodMissing(String methodName, args) { 15 | throw new MissingPropertyException("Block '" + methodName + "' not supported") 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/GroupConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | /** 4 | * Configuration for a Marathon group. Path is relative to the minimesosFile. 5 | */ 6 | class GroupConfig { 7 | 8 | private String marathonJson 9 | 10 | void setMarathonJson(String marathonJson) { 11 | this.marathonJson = marathonJson 12 | } 13 | 14 | String getMarathonJson() { 15 | return marathonJson 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/MarathonConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import com.containersol.minimesos.MinimesosException 4 | 5 | class MarathonConfig extends ContainerConfigBlock implements ContainerConfig { 6 | 7 | public static final String MARATHON_IMAGE = "mesosphere/marathon" 8 | public static final String MARATHON_IMAGE_TAG = "v1.3.5" 9 | public static final int MARATHON_PORT = 8080 10 | public static final String MARATHON_CMD = "--master zk://minimesos-zookeeper:2181/mesos --zk zk://minimesos-zookeeper:2181/marathon" 11 | 12 | List apps = new ArrayList<>() 13 | List groups = new ArrayList<>() 14 | String cmd 15 | 16 | MarathonConfig() { 17 | imageName = MARATHON_IMAGE 18 | imageTag = MARATHON_IMAGE_TAG 19 | cmd = MARATHON_CMD 20 | } 21 | 22 | def app(@DelegatesTo(AppConfig) Closure cl) { 23 | def app = new AppConfig() 24 | delegateTo(app, cl) 25 | 26 | if (app.getMarathonJson() == null) { 27 | throw new MinimesosException("App config must have a 'marathonJson' property") 28 | } 29 | apps.add(app) 30 | } 31 | 32 | def group(@DelegatesTo(GroupConfig) Closure cl) { 33 | def group = new GroupConfig() 34 | delegateTo(group, cl) 35 | 36 | if (group.getMarathonJson() == null) { 37 | throw new MinimesosException("Group config must have a 'marathonJson' property") 38 | } 39 | groups.add(group) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/MesosAgentConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import groovy.util.logging.Slf4j 4 | 5 | @Slf4j 6 | class MesosAgentConfig extends MesosContainerConfig { 7 | 8 | public static final String MESOS_AGENT_IMAGE = "containersol/mesos-agent" 9 | public static final int DEFAULT_MESOS_AGENT_PORT = 5051 10 | public static final String DEFAULT_MESOS_ATTRIBUTES = "" 11 | 12 | int portNumber = DEFAULT_MESOS_AGENT_PORT 13 | String attributes = DEFAULT_MESOS_ATTRIBUTES 14 | 15 | AgentResourcesConfig resources = new AgentResourcesConfig() 16 | 17 | public MesosAgentConfig(String mesosVersion) { 18 | imageName = MESOS_AGENT_IMAGE 19 | imageTag = mesosVersion + "-" + MINIMESOS_DOCKER_TAG 20 | } 21 | 22 | def resources(@DelegatesTo(AgentResourcesConfig) Closure cl) { 23 | delegateTo(resources, cl) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/MesosContainerConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | abstract class MesosContainerConfig extends ContainerConfigBlock implements ContainerConfig { 4 | 5 | public static final String MESOS_LOGGING_LEVEL_INHERIT = "# INHERIT FROM CLUSTER" 6 | public static final String MINIMESOS_DOCKER_TAG = "0.1.0" 7 | 8 | private String loggingLevel = MESOS_LOGGING_LEVEL_INHERIT 9 | 10 | public static final List MESOS_VERSIONS = [ 11 | "0.25", 12 | "0.25.0", 13 | "0.26", 14 | "0.27", 15 | "0.28.0", 16 | "0.28.1", 17 | "0.28", 18 | "1.0.0", 19 | ] 20 | 21 | public String getLoggingLevel() { 22 | return loggingLevel 23 | } 24 | 25 | public void setLoggingLevel(String loggingLevel) { 26 | this.loggingLevel = loggingLevel.toUpperCase() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/MesosDNSConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | public class MesosDNSConfig extends ContainerConfigBlock implements ContainerConfig { 4 | 5 | public static final String MESOS_DNS_IMAGE_NAME = "xebia/mesos-dns" 6 | public static final String MESOS_DNS_TAG_NAME = "0.0.5" 7 | 8 | public MesosDNSConfig() { 9 | imageName = MESOS_DNS_IMAGE_NAME 10 | imageTag = MESOS_DNS_TAG_NAME 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/MesosMasterConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import groovy.util.logging.Slf4j 4 | 5 | @Slf4j 6 | class MesosMasterConfig extends MesosContainerConfig { 7 | 8 | public static final String MESOS_MASTER_IMAGE = "containersol/mesos-master" 9 | public static final int MESOS_MASTER_PORT = 5050 10 | 11 | public MesosMasterConfig(String mesosVersion) { 12 | imageName = MESOS_MASTER_IMAGE 13 | imageTag = mesosVersion + "-" + MINIMESOS_DOCKER_TAG 14 | } 15 | 16 | boolean authenticate = false 17 | String aclJson 18 | 19 | } 20 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/RegistratorConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config; 2 | 3 | public class RegistratorConfig extends ContainerConfigBlock implements ContainerConfig { 4 | 5 | public static final String REGISTRATOR_IMAGE_NAME = "gliderlabs/registrator" 6 | public static final String REGISTRATOR_TAG_NAME = "v6" 7 | 8 | public RegistratorConfig() { 9 | imageName = REGISTRATOR_IMAGE_NAME 10 | imageTag = REGISTRATOR_TAG_NAME 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ResourceDef.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | /** 4 | * Check http://mesos.apache.org/documentation/latest/attributes-resources/ for possible types of values 5 | */ 6 | abstract class ResourceDef extends GroovyBlock { 7 | 8 | String role 9 | 10 | protected ResourceDef() { 11 | } 12 | 13 | protected ResourceDef(String role) { 14 | this.role = role 15 | } 16 | 17 | abstract public String valueAsString() 18 | 19 | } 20 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ResourceDefRanges.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | /** 4 | * Check http://mesos.apache.org/documentation/latest/attributes-resources/ for possible types of values 5 | */ 6 | class ResourceDefRanges extends ResourceDef { 7 | 8 | String value 9 | 10 | public ResourceDefRanges() { 11 | } 12 | 13 | public ResourceDefRanges(String role, String value) { 14 | super(role) 15 | this.value = value 16 | } 17 | 18 | @Override 19 | String valueAsString() { 20 | return value 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ResourceDefScalar.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import java.text.DecimalFormat 4 | import java.text.DecimalFormatSymbols 5 | 6 | /** 7 | * Check http://mesos.apache.org/documentation/latest/attributes-resources/ for possible types of values 8 | */ 9 | class ResourceDefScalar extends ResourceDef { 10 | 11 | private DecimalFormat format = null; 12 | private double value 13 | 14 | public ResourceDefScalar() { 15 | } 16 | 17 | public ResourceDefScalar(String role, double value) { 18 | super(role) 19 | this.value = value 20 | } 21 | 22 | private DecimalFormat getFormat() { 23 | if (format == null) { 24 | // see http://mesos.apache.org/documentation/latest/attributes-resources/ 25 | // make format locale independent 26 | DecimalFormatSymbols symbols = new DecimalFormatSymbols(); 27 | symbols.setDecimalSeparator('.' as char) 28 | format = new DecimalFormat("#.##", symbols) 29 | } 30 | return format 31 | } 32 | 33 | public void setValue(double value) { 34 | this.value = value 35 | } 36 | 37 | /** 38 | * Without this explicit setter groovy assigns unexpected values, if they are surrounded by "" 39 | * @param value to get double from 40 | */ 41 | public void setValue(String value) { 42 | // correct format is intValue ( "." intValue )? 43 | if (value.contains(",")) { 44 | throw new NumberFormatException(value + " is not valid scalar value") 45 | } 46 | this.value = getFormat().parse(value).doubleValue() 47 | } 48 | 49 | public double getValue() { 50 | value 51 | } 52 | 53 | @Override 54 | String valueAsString() { 55 | return getFormat().format(value); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /minimesos/src/main/groovy/com/containersol/minimesos/config/ZooKeeperConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | public class ZooKeeperConfig extends ContainerConfigBlock implements ContainerConfig { 4 | 5 | public static final String DEFAULT_MESOS_ZK_PATH = "/mesos"; 6 | public static final int DEFAULT_ZOOKEEPER_PORT = 2181; 7 | 8 | public static final String MESOS_LOCAL_IMAGE = "jplock/zookeeper" 9 | public static final String ZOOKEEPER_IMAGE_TAG = "3.4.6" 10 | 11 | public ZooKeeperConfig() { 12 | imageName = MESOS_LOCAL_IMAGE 13 | imageTag = ZOOKEEPER_IMAGE_TAG 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/MinimesosException.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos; 2 | 3 | /** 4 | * Thrown when a minimesos command fails. 5 | */ 6 | public class MinimesosException extends RuntimeException { 7 | 8 | public MinimesosException(String message) { 9 | super(message); 10 | } 11 | 12 | public MinimesosException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/ClusterProcess.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import java.net.URI; 4 | 5 | /** 6 | * Generic functionality of every cluster member 7 | */ 8 | public interface ClusterProcess { 9 | 10 | MesosCluster getCluster(); 11 | 12 | void setCluster(MesosCluster mesosCluster); 13 | 14 | /** 15 | * @return the IP address of the container 16 | */ 17 | String getIpAddress(); 18 | 19 | /** 20 | * @return URI the service is available at (or null) 21 | */ 22 | URI getServiceUrl(); 23 | 24 | /** 25 | * Builds container name following the naming convention 26 | * 27 | * @return container name 28 | */ 29 | String getName(); 30 | 31 | /** 32 | * @return the ID of the container. 33 | */ 34 | String getContainerId(); 35 | 36 | /** 37 | * Starts the container and waits until is started 38 | * 39 | * @param timeout in seconds 40 | */ 41 | void start(int timeout); 42 | 43 | String getRole(); 44 | 45 | /** 46 | * Removes a container with force 47 | */ 48 | void remove(); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/ClusterRepository.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import org.apache.commons.io.FileUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.Paths; 12 | 13 | /** 14 | * Manages persistent information about the minimesos cluster 15 | */ 16 | public class ClusterRepository { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(ClusterRepository.class); 19 | 20 | public static final String MINIMESOS_FILE_PROPERTY = "minimesos.cluster"; 21 | 22 | /** 23 | * Loads representation of the running cluster 24 | * 25 | * @return representation of the cluster, which ID is found in the file 26 | */ 27 | public MesosCluster loadCluster(MesosClusterFactory factory) { 28 | String clusterId = readClusterId(); 29 | if (clusterId != null) { 30 | try { 31 | return MesosCluster.loadCluster(clusterId, factory); 32 | } catch (MinimesosException e) { 33 | deleteMinimesosFile(); 34 | } 35 | } 36 | return null; 37 | } 38 | 39 | /** 40 | * Writes cluster id to file 41 | * 42 | * @param cluster cluster to store ID 43 | */ 44 | public void saveClusterFile(MesosCluster cluster) { 45 | String clusterId = cluster.getClusterId(); 46 | File dotMinimesosDir = getMinimesosDir(); 47 | try { 48 | FileUtils.forceMkdir(dotMinimesosDir); 49 | String clusterIdPath = dotMinimesosDir.getAbsolutePath() + "/" + MINIMESOS_FILE_PROPERTY; 50 | Files.write(Paths.get(clusterIdPath), clusterId.getBytes()); 51 | LOGGER.debug("Writing cluster ID " + clusterId + " to " + clusterIdPath); 52 | } catch (IOException ie) { 53 | LOGGER.error("Could not write .minimesos folder", ie); 54 | throw new RuntimeException(ie); 55 | } 56 | } 57 | 58 | /** 59 | * Deletes cluster file 60 | */ 61 | public void deleteClusterFile() { 62 | deleteMinimesosFile(); 63 | } 64 | 65 | public String readClusterId() { 66 | try { 67 | File minimesosFile = getMinimesosFile(); 68 | String clusterId = FileUtils.readFileToString(minimesosFile, "UTF-8"); 69 | LOGGER.debug("Reading cluster ID from " + minimesosFile + ": " + clusterId); 70 | return clusterId; 71 | } catch (IOException e) { 72 | return null; 73 | } 74 | } 75 | 76 | /** 77 | * @return file, possibly non-existing, where cluster information is stored 78 | */ 79 | public File getMinimesosFile() { 80 | return new File(getMinimesosDir(), MINIMESOS_FILE_PROPERTY); 81 | } 82 | 83 | /** 84 | * @return directory, where minimesos stores ID file 85 | */ 86 | public File getMinimesosDir() { 87 | File hostDir = MesosCluster.getClusterHostDir(); 88 | File minimesosDir = new File(hostDir, ".minimesos"); 89 | if (!minimesosDir.exists()) { 90 | if (!minimesosDir.mkdirs()) { 91 | throw new MinimesosException("Failed to create " + minimesosDir.getAbsolutePath() + " directory"); 92 | } 93 | } 94 | 95 | return minimesosDir; 96 | } 97 | 98 | private void deleteMinimesosFile() { 99 | File minimesosFile = getMinimesosFile(); 100 | LOGGER.debug("Deleting minimesos.cluster file at " + getMinimesosFile()); 101 | if (minimesosFile.exists()) { 102 | try { 103 | FileUtils.forceDelete(minimesosFile); 104 | } catch (IOException e) { 105 | // ignore 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/ClusterUtil.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Optional; 8 | 9 | import static com.containersol.minimesos.cluster.Filter.withRole; 10 | 11 | /** 12 | * Helper methods for ClusterArchitecture 13 | */ 14 | public class ClusterUtil { 15 | 16 | /** 17 | * Disable constructors 18 | */ 19 | private ClusterUtil() { 20 | } 21 | 22 | /** 23 | * Filters given list of processes and returns only those with distinct roles 24 | * 25 | * @param processes complete list of processes 26 | * @return processes with distinct roles 27 | */ 28 | public static List getDistinctRoleProcesses(List processes) { 29 | 30 | List distinct = new ArrayList<>(); 31 | Map roles = new HashMap<>(); 32 | 33 | // count processes per role 34 | for (ClusterProcess process : processes) { 35 | Integer prev = roles.get(process.getRole()); 36 | int count = (prev != null) ? prev : 0; 37 | roles.put(process.getRole(), count+1 ); 38 | } 39 | 40 | for (Map.Entry role : roles.entrySet() ) { 41 | if (role.getValue() == 1) { 42 | Optional process = processes.stream().filter(withRole(role.getKey())).findFirst(); 43 | distinct.add(process.get()); 44 | } 45 | } 46 | 47 | return distinct; 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/Consul.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Consul functionality 5 | */ 6 | public interface Consul extends ClusterProcess { 7 | } 8 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/Filter.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import java.util.function.Predicate; 4 | 5 | public class Filter { 6 | 7 | private Filter() { 8 | } 9 | 10 | public static Predicate zooKeeper() { 11 | return process -> process instanceof ZooKeeper; 12 | } 13 | 14 | public static Predicate consul() { 15 | return process -> process instanceof Consul; 16 | } 17 | 18 | public static Predicate mesosMaster() { 19 | return process -> process instanceof MesosMaster; 20 | } 21 | 22 | public static Predicate mesosAgent() { 23 | return process -> process instanceof MesosAgent; 24 | } 25 | 26 | public static Predicate marathon() { 27 | return process -> process instanceof Marathon; 28 | } 29 | 30 | public static Predicate withRole(String role) { 31 | return process -> role.equals(process.getRole()); 32 | } 33 | 34 | public static Predicate registrator() { return process -> process instanceof Registrator; } 35 | 36 | public static Predicate mesosDns() { 37 | return process -> process instanceof MesosDns; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/Marathon.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import com.mashape.unirest.http.HttpResponse; 4 | import com.mashape.unirest.http.JsonNode; 5 | import mesosphere.marathon.client.model.v2.Result; 6 | 7 | /** 8 | * Functionality, which is expected from Marathon 9 | */ 10 | public interface Marathon extends ClusterProcess { 11 | 12 | /** 13 | * If Marathon configuration requires, installs the applications 14 | */ 15 | void installMarathonApps(); 16 | 17 | /** 18 | * Deploys a Marathon app by JSON string 19 | * 20 | * @param marathonJson JSON string 21 | */ 22 | void deployApp(String marathonJson); 23 | 24 | /** 25 | * Updates a Marathon app by JSON string 26 | * 27 | * @param marathonJson JSON string 28 | */ 29 | void updateApp(String marathonJson); 30 | 31 | /** 32 | * Kill all apps that are currently running. 33 | */ 34 | void killAllApps(); 35 | 36 | void setZooKeeper(ZooKeeper zookeeper); 37 | 38 | /** 39 | * Delete the given app 40 | * 41 | * @param app to be deleted 42 | */ 43 | Result deleteApp(String app); 44 | 45 | /** 46 | * Deploy a Marathon application group. 47 | * 48 | * @param groupJson JSON string with Marathon application group definition 49 | */ 50 | void deployGroup(String groupJson); 51 | 52 | /** 53 | * Deploy a Marathon application group. 54 | * 55 | * @param group group name 56 | */ 57 | Result deleteGroup(String group); 58 | } 59 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/MesosAgent.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Functionality of Mesos Master 5 | */ 6 | public interface MesosAgent extends MesosContainer { 7 | String getResources(); 8 | } 9 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/MesosClusterFactory.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Interface for creating members of the cluster and destroying running cluster 5 | */ 6 | public abstract class MesosClusterFactory { 7 | 8 | /** 9 | * Fills given cluster with discovered members 10 | * 11 | * @param cluster to load with discovered members 12 | */ 13 | public abstract void loadRunningCluster(MesosCluster cluster); 14 | 15 | /** 16 | * Destroys members of the cluster with given ID 17 | * 18 | * @param clusterId ID of the cluster to destroy 19 | */ 20 | public abstract void destroyRunningCluster(String clusterId); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/MesosContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | import com.containersol.minimesos.state.State; 4 | import com.mashape.unirest.http.exceptions.UnirestException; 5 | import org.json.JSONObject; 6 | 7 | /** 8 | * Functionality of Mesos Cluster core members 9 | */ 10 | public interface MesosContainer extends ClusterProcess { 11 | 12 | void setZooKeeper(ZooKeeper zookeeper); 13 | 14 | JSONObject getStateInfoJSON() throws UnirestException; 15 | 16 | /** 17 | * Retrieve state of the Master or Agent. 18 | * 19 | * @return state object with frameworks and tasks 20 | */ 21 | State getState(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/MesosDns.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Mesos DNS 5 | */ 6 | public interface MesosDns extends ClusterProcess { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/MesosMaster.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Functionality of Mesos Master 5 | */ 6 | public interface MesosMaster extends MesosContainer { 7 | 8 | String getStateUrl(); 9 | 10 | void waitFor(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/Registrator.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Consul functionality 5 | */ 6 | public interface Registrator extends ClusterProcess { 7 | 8 | void setConsul(Consul consul); 9 | } 10 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/cluster/ZooKeeper.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.cluster; 2 | 3 | /** 4 | * Expected from ZooKeeper functionality 5 | */ 6 | public interface ZooKeeper extends ClusterProcess { 7 | 8 | /** 9 | * @return ZooKeeper URL based on real IP address 10 | */ 11 | String getFormattedZKAddress(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/docker/DockerClientFactory.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.docker; 2 | 3 | import com.github.dockerjava.api.DockerClient; 4 | import com.github.dockerjava.core.DefaultDockerClientConfig; 5 | import com.github.dockerjava.core.DockerClientBuilder; 6 | import com.github.dockerjava.core.DockerClientConfig; 7 | import org.apache.commons.lang.StringUtils; 8 | 9 | /** 10 | * Factory for creating {@link DockerClient}s 11 | */ 12 | public class DockerClientFactory { 13 | 14 | private static DockerClient dockerClient; 15 | 16 | public static DockerClient build() { 17 | if (dockerClient == null) { 18 | DefaultDockerClientConfig.Builder builder = new DefaultDockerClientConfig.Builder(); 19 | builder = builder.withApiVersion("1.12"); 20 | 21 | String dockerHostEnv = System.getenv("DOCKER_HOST"); 22 | if (StringUtils.isBlank(dockerHostEnv)) { 23 | builder.withDockerHost("unix:///var/run/docker.sock"); 24 | } 25 | 26 | DockerClientConfig config = builder.build(); 27 | dockerClient = DockerClientBuilder.getInstance(config).build(); 28 | } 29 | return dockerClient; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/integrationtest/container/ContainerName.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest.container; 2 | 3 | /** 4 | * Utility class to assist container naming convention 5 | */ 6 | public class ContainerName { 7 | 8 | // disable creation on instances 9 | private ContainerName() { 10 | } 11 | 12 | public static String getContainerNamePattern(String clusterId) { 13 | return "^minimesos-\\w+-" + clusterId + "-\\w+$"; 14 | } 15 | 16 | /** 17 | * @param container to build the name for 18 | * @return name of the container 19 | */ 20 | public static String get(AbstractContainer container) { 21 | return String.format("minimesos-%s-%s-%s", container.getRole(), container.getClusterId(), container.getUuid()); 22 | } 23 | 24 | /** 25 | * Based on container name check if it has the given role in the cluster 26 | * 27 | * @param containerName to analyse 28 | * @param clusterId cluster to check 29 | * @param role role to check 30 | * @return true if container has the role 31 | */ 32 | public static boolean hasRoleInCluster(String containerName, String clusterId, String role) { 33 | String expectedStart = String.format("minimesos-%s-%s-", role, clusterId); 34 | return containerName.startsWith(expectedStart); 35 | } 36 | 37 | /** 38 | * Based on container name check if it has the given role in the cluster 39 | * 40 | * @param dockerNames as returned by container.getNames() 41 | * @param clusterId cluster to check 42 | * @param role role to check 43 | * @return true if container has the role 44 | */ 45 | public static boolean hasRoleInCluster(String[] dockerNames, String clusterId, String role) { 46 | String name = getFromDockerNames(dockerNames); 47 | return hasRoleInCluster(name, clusterId, role); 48 | } 49 | 50 | /** 51 | * @return true, if container with this name belongs to the cluster 52 | */ 53 | public static boolean belongsToCluster(String containerName, String clusterId) { 54 | String pattern = getContainerNamePattern(clusterId); 55 | return containerName.matches(pattern); 56 | } 57 | 58 | /** 59 | * @return true, if container with these docker names belongs to the cluster 60 | */ 61 | public static boolean belongsToCluster(String[] dockerNames, String clusterId) { 62 | String name = getFromDockerNames(dockerNames); 63 | return belongsToCluster(name, clusterId); 64 | } 65 | 66 | /** 67 | * Docker supports multiple names for a single container, when the container is linked from others. 68 | * This method selects the original name of the container and removes leading "/" 69 | * 70 | * @param dockerNames names, as they returned by container.getNames() 71 | * @return name of the container, which is not inherited from link 72 | */ 73 | public static String getFromDockerNames(String[] dockerNames) { 74 | String name = null; 75 | for (String dockerName : dockerNames) { 76 | String slashLess = dockerName; 77 | if (dockerName.startsWith("/")) { 78 | slashLess = dockerName.substring(1); 79 | } 80 | if (!slashLess.contains("/")) { 81 | name = slashLess; 82 | break; 83 | } 84 | } 85 | return name; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/junit/MesosClusterTestRule.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.junit; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | import com.containersol.minimesos.MinimesosException; 9 | import com.containersol.minimesos.cluster.MesosCluster; 10 | import com.containersol.minimesos.cluster.MesosClusterFactory; 11 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 12 | 13 | import org.junit.rules.TestRule; 14 | import org.junit.runner.Description; 15 | import org.junit.runners.model.Statement; 16 | 17 | /** 18 | * JUnit Rule extension of Mesos Cluster to use in JUnit. 19 | */ 20 | public class MesosClusterTestRule implements TestRule { 21 | 22 | private MesosClusterFactory factory = new MesosClusterContainersFactory(); 23 | 24 | private MesosCluster mesosCluster; 25 | 26 | public static MesosClusterTestRule fromClassPath(String path) { 27 | try (InputStream is = MesosClusterTestRule.class.getResourceAsStream(path)) { 28 | MesosCluster cluster = new MesosClusterContainersFactory().createMesosCluster(is); 29 | return new MesosClusterTestRule(cluster); 30 | } catch (IOException e) { 31 | throw new MinimesosException("Could not read minimesosFile on classpath " + path, e); 32 | } 33 | } 34 | 35 | public static MesosClusterTestRule fromFile(String minimesosFilePath) { 36 | try { 37 | MesosCluster cluster = new MesosClusterContainersFactory().createMesosCluster(new FileInputStream(minimesosFilePath)); 38 | return new MesosClusterTestRule(cluster); 39 | } catch (FileNotFoundException e) { 40 | throw new MinimesosException("Could not read minimesosFile at " + minimesosFilePath, e); 41 | } 42 | } 43 | 44 | private MesosClusterTestRule(MesosCluster mesosCluster) { 45 | this.mesosCluster = mesosCluster; 46 | } 47 | 48 | /** 49 | * Modifies the method-running {@link Statement} to implement this test-running rule. 50 | * 51 | * @param base The {@link Statement} to be modified 52 | * @param description A {@link Description} of the test implemented in {@code base} 53 | * @return a new statement, which may be the same as {@code base}, a wrapper around {@code base}, or a completely new Statement. 54 | */ 55 | @Override 56 | public Statement apply(Statement base, Description description) { 57 | return new Statement() { 58 | @Override 59 | public void evaluate() throws Throwable { 60 | before(); 61 | try { 62 | base.evaluate(); 63 | } finally { 64 | after(); 65 | } 66 | } 67 | }; 68 | } 69 | 70 | /** 71 | * Execute before the test 72 | */ 73 | protected void before() { 74 | mesosCluster.start(); 75 | Runtime.getRuntime().addShutdownHook(new Thread() { 76 | @Override 77 | public void run() { 78 | factory.destroyRunningCluster(mesosCluster.getClusterId()); 79 | } 80 | }); 81 | } 82 | 83 | /** 84 | * Execute after the test 85 | */ 86 | protected void after() { 87 | stop(); 88 | } 89 | 90 | /** 91 | * Destroys cluster using docker based factory of cluster members 92 | */ 93 | public void stop() { 94 | mesosCluster.destroy(factory); 95 | } 96 | 97 | public MesosCluster getMesosCluster() { 98 | return mesosCluster; 99 | } 100 | 101 | public MesosClusterFactory getFactory() { 102 | return factory; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/ClusterContainers.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.cluster.ClusterProcess; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import java.util.function.Predicate; 9 | 10 | /** 11 | * Holds the containers and helper methods for the Mesos cluster 12 | */ 13 | public class ClusterContainers { 14 | 15 | private final List containers; 16 | 17 | /** 18 | * Create a container List from scratch 19 | */ 20 | public ClusterContainers() { 21 | containers = new ArrayList<>(); 22 | } 23 | 24 | /** 25 | * Create a container List from another List 26 | * 27 | * @param containers another List of {@link ClusterProcess} 28 | */ 29 | public ClusterContainers(List containers) { 30 | this.containers = containers; 31 | } 32 | 33 | /** 34 | * Add a container to the list of containers. 35 | * 36 | * @param container of type {@link ClusterProcess} 37 | * @return this, for fluent adding. 38 | */ 39 | public ClusterContainers add(ClusterProcess container) { 40 | containers.add(container); 41 | return this; 42 | } 43 | 44 | public List getContainers() { 45 | return containers; 46 | } 47 | 48 | /** 49 | * Optionally get one of a certain type of type T. Note, this cast will always work because we are filtering on that type. 50 | * If it doesn't find that type, the optional is empty so the cast doesn't need to be performed. 51 | * 52 | * @param filter A predicate that is true when an {@link ClusterProcess} in the list is of type T 53 | * @param A container of type T that extends {@link ClusterProcess} 54 | * @return the first container it comes across. 55 | */ 56 | @SuppressWarnings("unchecked") 57 | public Optional getOne(Predicate filter) { 58 | return (Optional) getContainers().stream().filter(filter).findFirst(); 59 | } 60 | 61 | /** 62 | * Checks to see whether a container exists 63 | * 64 | * @param filter A predicate that is true when an {@link ClusterProcess} in the list is of type T 65 | * @return true if it exists 66 | */ 67 | public Boolean isPresent(Predicate filter) { 68 | return getOne(filter).isPresent(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/ConsulContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.Consul; 5 | import com.containersol.minimesos.cluster.MesosCluster; 6 | import com.containersol.minimesos.config.ConsulConfig; 7 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 8 | import com.containersol.minimesos.docker.DockerClientFactory; 9 | import com.containersol.minimesos.util.Environment; 10 | import com.github.dockerjava.api.command.CreateContainerCmd; 11 | import com.github.dockerjava.api.model.ExposedPort; 12 | import com.github.dockerjava.api.model.Ports; 13 | import org.apache.commons.lang.StringUtils; 14 | 15 | import java.net.URI; 16 | import java.net.URISyntaxException; 17 | 18 | /** 19 | * This is the Consul-in-a-container container. Consul adds service discovery through DNS, and a distributed k/v store. 20 | */ 21 | public class ConsulContainer extends AbstractContainer implements Consul { 22 | 23 | private final ConsulConfig config; 24 | 25 | public ConsulContainer(ConsulConfig config) { 26 | super(config); 27 | this.config = config; 28 | } 29 | 30 | public ConsulContainer(MesosCluster cluster, String uuid, String containerId) { 31 | this(cluster, uuid, containerId, new ConsulConfig()); 32 | } 33 | 34 | private ConsulContainer(MesosCluster cluster, String uuid, String containerId, ConsulConfig config) { 35 | super(cluster, uuid, containerId, config); 36 | this.config = config; 37 | } 38 | 39 | @Override 40 | public String getRole() { 41 | return "consul"; 42 | } 43 | 44 | @Override 45 | protected int getServicePort() { 46 | return ConsulConfig.CONSUL_HTTP_PORT; 47 | } 48 | 49 | @Override 50 | public URI getServiceUrl() { 51 | URI serviceUri = null; 52 | 53 | String protocol = getServiceProtocol(); 54 | 55 | String host; 56 | if (Environment.isRunningInJvmOnMacOsX()) { 57 | host = "localhost"; 58 | } else { 59 | host = getIpAddress(); 60 | } 61 | 62 | int port = getServicePort(); 63 | String path = getServicePath(); 64 | 65 | if (StringUtils.isNotEmpty(host)) { 66 | try { 67 | serviceUri = new URI(protocol, null, host, port, path, null, null); 68 | } catch (URISyntaxException e) { 69 | throw new MinimesosException("Failed to form service URL for " + getName(), e); 70 | } 71 | } 72 | 73 | return serviceUri; 74 | } 75 | 76 | @Override 77 | protected CreateContainerCmd dockerCommand() { 78 | int port = getServicePort(); 79 | ExposedPort exposedPort = ExposedPort.tcp(port); 80 | 81 | Ports portBindings = new Ports(); 82 | if (getCluster().isMapPortsToHost()) { 83 | portBindings.bind(exposedPort, Ports.Binding.bindPort(port)); 84 | } 85 | 86 | ExposedPort consulHTTPPort = ExposedPort.tcp(ConsulConfig.CONSUL_HTTP_PORT); 87 | ExposedPort consulDNSPort = ExposedPort.udp(ConsulConfig.CONSUL_DNS_PORT); 88 | 89 | return DockerClientFactory.build().createContainerCmd(config.getImageName() + ":" + config.getImageTag()) 90 | .withName(getName()) 91 | .withCmd("agent", "-server", "-bootstrap", "-client", "0.0.0.0") 92 | .withExposedPorts(consulHTTPPort, consulDNSPort) 93 | .withPortBindings(portBindings); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/MesosContainerImpl.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.cluster.MesosContainer; 6 | import com.containersol.minimesos.cluster.ZooKeeper; 7 | import com.containersol.minimesos.config.MesosContainerConfig; 8 | import com.containersol.minimesos.config.ZooKeeperConfig; 9 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 10 | import com.containersol.minimesos.state.State; 11 | import com.fasterxml.jackson.core.JsonParseException; 12 | import com.fasterxml.jackson.databind.JsonMappingException; 13 | import com.mashape.unirest.http.HttpResponse; 14 | import com.mashape.unirest.http.JsonNode; 15 | import com.mashape.unirest.http.Unirest; 16 | import com.mashape.unirest.http.exceptions.UnirestException; 17 | import com.mashape.unirest.request.GetRequest; 18 | import org.json.JSONObject; 19 | 20 | import java.util.Map; 21 | import java.util.TreeMap; 22 | 23 | /** 24 | * Superclass for Mesos master and agent images. 25 | * Apache Mesos abstracts CPU, memory, storage, and other compute resources away from machines (physical or virtual), enabling fault-tolerant and elastic distributed systems to easily be built and run effectively. 26 | */ 27 | public abstract class MesosContainerImpl extends AbstractContainer implements MesosContainer { 28 | 29 | private ZooKeeper zooKeeperContainer; 30 | protected MesosContainerConfig config; 31 | 32 | protected MesosContainerImpl(MesosContainerConfig config) { 33 | super(config); 34 | this.config = config; 35 | } 36 | 37 | protected MesosContainerImpl(MesosCluster cluster, String uuid, String containerId, MesosContainerConfig config) { 38 | super(cluster, uuid, containerId, config); 39 | this.config = config; 40 | } 41 | 42 | @Override 43 | public String getImageTag() { 44 | String imageTag = config.getImageTag(); 45 | if (MesosContainerConfig.MINIMESOS_DOCKER_TAG.equalsIgnoreCase(imageTag)) { 46 | imageTag = MesosContainerConfig.MINIMESOS_DOCKER_TAG; 47 | } 48 | return imageTag; 49 | } 50 | 51 | protected final Map getSharedEnvVars() { 52 | Map envs = new TreeMap<>(); 53 | envs.put("GLOG_v", "1"); 54 | envs.put("MESOS_EXECUTOR_REGISTRATION_TIMEOUT", "5mins"); 55 | envs.put("MESOS_CONTAINERIZERS", "docker,mesos"); 56 | envs.put("MESOS_ISOLATOR", "cgroups/cpu,cgroups/mem"); 57 | envs.put("MESOS_LOG_DIR", "/var/log"); 58 | envs.put("MESOS_LOGGING_LEVEL", getLoggingLevel()); 59 | return envs; 60 | } 61 | 62 | @Override 63 | public void setZooKeeper(ZooKeeper zooKeeperContainer) { 64 | this.zooKeeperContainer = zooKeeperContainer; 65 | } 66 | 67 | public ZooKeeper getZooKeeper() { 68 | return zooKeeperContainer; 69 | } 70 | 71 | public String getFormattedZKAddress() { 72 | return zooKeeperContainer.getFormattedZKAddress() + ZooKeeperConfig.DEFAULT_MESOS_ZK_PATH; 73 | } 74 | 75 | public String getStateUrl() { 76 | return getServiceUrl().toString() + "/state.json"; 77 | } 78 | 79 | @Override 80 | public JSONObject getStateInfoJSON() throws UnirestException { 81 | String stateUrl = getStateUrl(); 82 | GetRequest request = Unirest.get(stateUrl); 83 | HttpResponse response = request.asJson(); 84 | return response.getBody().getObject(); 85 | } 86 | 87 | public String getLoggingLevel() { 88 | String level = config.getLoggingLevel(); 89 | if (MesosContainerConfig.MESOS_LOGGING_LEVEL_INHERIT.equalsIgnoreCase(level)) { 90 | level = getCluster().getLoggingLevel(); 91 | } 92 | return level; 93 | } 94 | 95 | @Override 96 | public State getState() { 97 | try { 98 | return State.fromJSON(getStateInfoJSON().toString()); 99 | } catch (JsonParseException | JsonMappingException | UnirestException e) { 100 | throw new MinimesosException("Could not retrieve state from Mesos container: " + getName(), e); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/MesosDnsContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.cluster.MesosCluster; 4 | import com.containersol.minimesos.cluster.MesosDns; 5 | import com.containersol.minimesos.config.MesosDNSConfig; 6 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 7 | import com.containersol.minimesos.docker.DockerClientFactory; 8 | import com.github.dockerjava.api.command.CreateContainerCmd; 9 | import com.github.dockerjava.api.model.ExposedPort; 10 | import com.github.dockerjava.api.model.InternetProtocol; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import static com.containersol.minimesos.util.EnvironmentBuilder.newEnvironment; 16 | 17 | /** 18 | * Mesos DNS automatically registers and deregisters Mesos services. 19 | */ 20 | public class MesosDnsContainer extends AbstractContainer implements MesosDns { 21 | 22 | private static final String DNS_PORT = "53"; 23 | 24 | private static final String DOMAIN = "mm"; 25 | 26 | private static final String REFRESH_SECONDS = "1"; 27 | 28 | private MesosDNSConfig config; 29 | 30 | public MesosDnsContainer(MesosCluster cluster, String uuid, String containerId) { 31 | this(cluster, uuid, containerId, new MesosDNSConfig()); 32 | } 33 | 34 | private MesosDnsContainer(MesosCluster cluster, String uuid, String containerId, MesosDNSConfig config) { 35 | super(cluster, uuid, containerId, config); 36 | this.config = config; 37 | } 38 | 39 | public MesosDnsContainer(MesosDNSConfig mesosDNS) { 40 | super(mesosDNS); 41 | this.config = mesosDNS; 42 | } 43 | 44 | @Override 45 | public String getRole() { 46 | return "mesosdns"; 47 | } 48 | 49 | @Override 50 | protected CreateContainerCmd dockerCommand() { 51 | return DockerClientFactory.build() 52 | .createContainerCmd(config.getImageName() + ":" + config.getImageTag()) 53 | .withEnv(newEnvironment() 54 | .withValues(getMesosDNSEnvVars()) 55 | .createEnvironment()) 56 | .withCmd("-v=2", "-config=/etc/mesos-dns/config.json") 57 | .withExposedPorts(new ExposedPort(Integer.valueOf(DNS_PORT), InternetProtocol.UDP), 58 | new ExposedPort(Integer.valueOf(DNS_PORT), InternetProtocol.TCP)) 59 | .withName(getName()); 60 | } 61 | 62 | @Override 63 | protected int getServicePort() { 64 | return Integer.valueOf(DNS_PORT); 65 | } 66 | 67 | private Map getMesosDNSEnvVars() { 68 | Map mesosDNSEnvVars = new HashMap<>(); 69 | mesosDNSEnvVars.put("MESOS_DNS_ZK", getCluster().getZooKeeper().getFormattedZKAddress() + "/mesos"); 70 | mesosDNSEnvVars.put("MESOS_DNS_DOMAIN", DOMAIN); 71 | mesosDNSEnvVars.put("MESOS_DNS_PORT", DNS_PORT); 72 | mesosDNSEnvVars.put("MESOS_DNS_REFRESH_SECONDS", REFRESH_SECONDS); 73 | return mesosDNSEnvVars; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/RegistratorContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.cluster.Consul; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.cluster.Registrator; 6 | import com.containersol.minimesos.config.ConsulConfig; 7 | import com.containersol.minimesos.config.RegistratorConfig; 8 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 9 | import com.containersol.minimesos.docker.DockerClientFactory; 10 | import com.github.dockerjava.api.command.CreateContainerCmd; 11 | import com.github.dockerjava.api.model.Bind; 12 | 13 | /** 14 | * Registrator automatically registers and deregisters services for any Docker container by inspecting containers as they come online. 15 | */ 16 | public class RegistratorContainer extends AbstractContainer implements Registrator { 17 | 18 | private RegistratorConfig config; 19 | 20 | private Consul consul; 21 | 22 | public RegistratorContainer(MesosCluster cluster, String uuid, String containerId) { 23 | this(cluster, uuid, containerId, new RegistratorConfig()); 24 | } 25 | 26 | private RegistratorContainer(MesosCluster cluster, String uuid, String containerId, RegistratorConfig config) { 27 | super(cluster, uuid, containerId, config); 28 | this.config = config; 29 | } 30 | 31 | public RegistratorContainer(RegistratorConfig registrator) { 32 | super(registrator); 33 | this.config = registrator; 34 | } 35 | 36 | @Override 37 | public String getRole() { 38 | return "registrator"; 39 | } 40 | 41 | @Override 42 | protected CreateContainerCmd dockerCommand() { 43 | return DockerClientFactory.build().createContainerCmd(config.getImageName() + ":" + config.getImageTag()) 44 | .withNetworkMode("host") 45 | .withBinds(Bind.parse("/var/run/docker.sock:/tmp/docker.sock")) 46 | .withCmd("-internal", String.format("consul://%s:%d", consul.getIpAddress(), ConsulConfig.CONSUL_HTTP_PORT)) 47 | .withName(getName()); 48 | } 49 | 50 | public void setConsul(ConsulContainer consul) { 51 | this.consul = consul; 52 | } 53 | 54 | @Override 55 | public void setConsul(Consul consul) { 56 | this.consul = consul; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/mesos/ZooKeeperContainer.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.cluster.MesosCluster; 5 | import com.containersol.minimesos.cluster.ZooKeeper; 6 | import com.containersol.minimesos.config.ZooKeeperConfig; 7 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 8 | import com.containersol.minimesos.docker.DockerClientFactory; 9 | import com.containersol.minimesos.util.Environment; 10 | import com.github.dockerjava.api.command.CreateContainerCmd; 11 | import com.github.dockerjava.api.model.ExposedPort; 12 | import com.github.dockerjava.api.model.Ports; 13 | import org.apache.commons.lang.StringUtils; 14 | 15 | import java.net.URI; 16 | import java.net.URISyntaxException; 17 | 18 | /** 19 | * ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 20 | */ 21 | public class ZooKeeperContainer extends AbstractContainer implements ZooKeeper { 22 | 23 | private final ZooKeeperConfig config; 24 | 25 | public ZooKeeperContainer(ZooKeeperConfig config) { 26 | super(config); 27 | this.config = config; 28 | } 29 | 30 | protected ZooKeeperContainer() { 31 | this(new ZooKeeperConfig()); 32 | } 33 | 34 | public ZooKeeperContainer(MesosCluster cluster, String uuid, String containerId) { 35 | this(cluster, uuid, containerId, new ZooKeeperConfig()); 36 | } 37 | 38 | public ZooKeeperContainer(MesosCluster cluster, String uuid, String containerId, ZooKeeperConfig config) { 39 | super(cluster, uuid, containerId, config); 40 | this.config = config; 41 | } 42 | 43 | @Override 44 | public String getRole() { 45 | return "zookeeper"; 46 | } 47 | 48 | @Override 49 | protected CreateContainerCmd dockerCommand() { 50 | int port = getServicePort(); 51 | ExposedPort exposedPort = ExposedPort.tcp(port); 52 | 53 | Ports portBindings = new Ports(); 54 | if (getCluster().isMapPortsToHost()) { 55 | portBindings.bind(exposedPort, Ports.Binding.bindPort(port)); 56 | } 57 | 58 | return DockerClientFactory.build().createContainerCmd(config.getImageName() + ":" + config.getImageTag()) 59 | .withName(getName()) 60 | .withExposedPorts(new ExposedPort(ZooKeeperConfig.DEFAULT_ZOOKEEPER_PORT), new ExposedPort(2888), new ExposedPort(3888)) 61 | .withPortBindings(portBindings); 62 | } 63 | 64 | @Override 65 | protected String getServiceProtocol() { 66 | return "zk"; 67 | } 68 | 69 | @Override 70 | protected int getServicePort() { 71 | return ZooKeeperConfig.DEFAULT_ZOOKEEPER_PORT; 72 | } 73 | 74 | @Override 75 | protected String getServicePath() { 76 | return ZooKeeperConfig.DEFAULT_MESOS_ZK_PATH; 77 | } 78 | 79 | /** 80 | * @return ZooKeeper URL based on real IP address 81 | */ 82 | @Override 83 | public String getFormattedZKAddress() { 84 | return "zk://" + getIpAddress() + ":" + ZooKeeperConfig.DEFAULT_ZOOKEEPER_PORT; 85 | } 86 | 87 | @Override 88 | public URI getServiceUrl() { 89 | URI serviceUri = null; 90 | 91 | String protocol = getServiceProtocol(); 92 | 93 | String host; 94 | if (Environment.isRunningInJvmOnMacOsX()) { 95 | host = "localhost"; 96 | } else { 97 | host = getIpAddress(); 98 | } 99 | 100 | int port = getServicePort(); 101 | String path = getServicePath(); 102 | 103 | if (StringUtils.isNotEmpty(host)) { 104 | try { 105 | serviceUri = new URI(protocol, null, host, port, path, null, null); 106 | } catch (URISyntaxException e) { 107 | throw new MinimesosException("Failed to form service URL for " + getName(), e); 108 | } 109 | } 110 | 111 | return serviceUri; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Discovery.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | /** 6 | * Maps Mesos task discovery information from JSON string to a Java object. 7 | */ 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class Discovery { 10 | 11 | private Ports ports; 12 | 13 | public Ports getPorts() { 14 | return ports; 15 | } 16 | 17 | public void setPorts(Ports ports) { 18 | this.ports = ports; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Executor.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class Executor { 7 | 8 | private String id; 9 | private String directory; 10 | 11 | public String getId() { 12 | return id; 13 | } 14 | 15 | public void setId(String id) { 16 | this.id = id; 17 | } 18 | 19 | public String getDirectory() { 20 | return directory; 21 | } 22 | 23 | public void setDirectory(String directory) { 24 | this.directory = directory; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Framework.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * Created by peldan on 09/07/15. 10 | */ 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public class Framework { 13 | 14 | private boolean active; 15 | 16 | private boolean checkpoint; 17 | 18 | @JsonProperty("failover_timeout") 19 | private int failoverTimeout; 20 | 21 | private String hostname; 22 | 23 | private String id; 24 | 25 | private String name; 26 | 27 | private String role; 28 | 29 | private ArrayList tasks; 30 | private ArrayList executors = new ArrayList<>(); 31 | 32 | public boolean isActive() { 33 | return active; 34 | } 35 | 36 | public void setActive(boolean active) { 37 | this.active = active; 38 | } 39 | 40 | public boolean isCheckpoint() { 41 | return checkpoint; 42 | } 43 | 44 | public void setCheckpoint(boolean checkpoint) { 45 | this.checkpoint = checkpoint; 46 | } 47 | 48 | public int getFailoverTimeout() { 49 | return failoverTimeout; 50 | } 51 | 52 | public void setFailoverTimeout(int failoverTimeout) { 53 | this.failoverTimeout = failoverTimeout; 54 | } 55 | 56 | public String getHostname() { 57 | return hostname; 58 | } 59 | 60 | public void setHostname(String hostname) { 61 | this.hostname = hostname; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public void setId(String id) { 69 | this.id = id; 70 | } 71 | 72 | public String getName() { 73 | return name; 74 | } 75 | 76 | public void setName(String name) { 77 | this.name = name; 78 | } 79 | 80 | public String getRole() { 81 | return role; 82 | } 83 | 84 | public void setRole(String role) { 85 | this.role = role; 86 | } 87 | 88 | public ArrayList getTasks() { 89 | return tasks; 90 | } 91 | 92 | public void setTasks(ArrayList tasks) { 93 | this.tasks = tasks; 94 | } 95 | 96 | public ArrayList getExecutors() { 97 | return executors; 98 | } 99 | 100 | public void setExecutors(ArrayList executors) { 101 | this.executors = executors; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Port.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | /** 6 | * Maps Mesos port information from JSON string to a Java object. 7 | */ 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public class Port { 10 | 11 | private int number; 12 | 13 | private String protocol; 14 | 15 | public int getNumber() { 16 | return number; 17 | } 18 | 19 | public void setNumber(int number) { 20 | this.number = number; 21 | } 22 | 23 | public String getProtocol() { 24 | return protocol; 25 | } 26 | 27 | public void setProtocol(String protocol) { 28 | this.protocol = protocol; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Ports.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Maps Mesos task ports information from JSON string to a Java object. 9 | */ 10 | @JsonIgnoreProperties(ignoreUnknown = true) 11 | public class Ports { 12 | 13 | private List ports; 14 | 15 | public List getPorts() { 16 | return ports; 17 | } 18 | 19 | public void setPorts(List ports) { 20 | this.ports = ports; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/State.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | import com.fasterxml.jackson.core.JsonParseException; 11 | import com.fasterxml.jackson.databind.JsonMappingException; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | 14 | /** 15 | * This class is populated with the results from a GET request to /state.json on a mesos-master. 16 | */ 17 | @JsonIgnoreProperties(ignoreUnknown = true) 18 | public class State { 19 | 20 | private String id; 21 | private Map flags = new HashMap<>(); 22 | 23 | @JsonProperty("activated_slaves") 24 | private int activatedAgents = 0; // NOSONAR 25 | 26 | @JsonProperty("version") 27 | private String version; 28 | 29 | private ArrayList frameworks = new ArrayList<>(); 30 | 31 | public static State fromJSON(String jsonString) throws JsonParseException, JsonMappingException { 32 | ObjectMapper mapper = new ObjectMapper(); 33 | try { 34 | return mapper.readValue(jsonString, State.class); 35 | } catch (IOException e) { 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | 40 | public ArrayList getFrameworks() { 41 | return frameworks; 42 | } 43 | 44 | public void setFrameworks(ArrayList frameworks) { 45 | this.frameworks = frameworks; 46 | } 47 | 48 | public Framework getFramework(String name) { 49 | for (Framework fw : getFrameworks()) { 50 | if (fw.getName().equals(name)) return fw; 51 | } 52 | return null; 53 | } 54 | 55 | public Map getFlags() { 56 | return flags; 57 | } 58 | 59 | public int getActivatedAgents() { 60 | return activatedAgents; 61 | } 62 | 63 | public String getVersion() { 64 | return version; 65 | } 66 | 67 | public String getId() { 68 | return id; 69 | } 70 | 71 | public void setId(String id) { 72 | this.id = id; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/state/Task.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.state; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | /** 7 | * Maps Mesos task properties from JSON string to Java object 8 | */ 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class Task { 11 | 12 | private String id; 13 | private String name; 14 | private String state; 15 | 16 | @JsonProperty("framework_id") 17 | private String frameworkId; 18 | 19 | @JsonProperty("executor_id") 20 | private String executorId; 21 | 22 | @JsonProperty("slave_id") 23 | private String slaveId; 24 | 25 | private Discovery discovery; 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | 35 | public String getState() { 36 | return state; 37 | } 38 | 39 | public void setState(String state) { 40 | this.state = state; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public void setName(String name) { 48 | this.name = name; 49 | } 50 | 51 | public String getFrameworkId() { 52 | return frameworkId; 53 | } 54 | 55 | public void setFrameworkId(String frameworkId) { 56 | this.frameworkId = frameworkId; 57 | } 58 | 59 | public String getExecutorId() { 60 | return executorId; 61 | } 62 | 63 | public void setExecutorId(String executorId) { 64 | this.executorId = executorId; 65 | } 66 | 67 | public String getSlaveId() { 68 | return slaveId; 69 | } 70 | 71 | public void setSlaveId(String slaveId) { 72 | this.slaveId = slaveId; 73 | } 74 | 75 | public Discovery getDiscovery() { 76 | return discovery; 77 | } 78 | 79 | public void setDiscovery(Discovery discovery) { 80 | this.discovery = discovery; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/CollectionsUtils.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * Utilities for dealing with collections 13 | */ 14 | public class CollectionsUtils { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(CollectionsUtils.class); 17 | 18 | private CollectionsUtils() { 19 | // do not allow creation of instances 20 | } 21 | 22 | public static List typedList(List original, Class clazz) { 23 | 24 | ArrayList typed = new ArrayList<>(original.size()); 25 | 26 | for (Object obj : original) { 27 | if ((obj == null) || clazz.isAssignableFrom(obj.getClass())) { 28 | typed.add(clazz.cast(obj)); 29 | } else { 30 | throw new MinimesosException("Not possible to cast " + obj + " to " + clazz.getCanonicalName()); 31 | } 32 | } 33 | 34 | return typed; 35 | 36 | } 37 | 38 | /** 39 | * This function split the cmd attribute in an array of String to make 40 | * it consumable by the withCmd from docker-java. 41 | * 42 | * It ensures that quotes and double quotes are correctly handled, 43 | * the split is performed on spaces. 44 | */ 45 | public static String[] splitCmd(String cmd) { 46 | String arg = ""; 47 | ArrayList args = new ArrayList(); 48 | ArrayList quotes = new ArrayList(); 49 | 50 | LOGGER.debug(String.format("Parsing cmd line: %s", cmd)); 51 | for (int i = 0; i < cmd.length(); i++){ 52 | char c = cmd.charAt(i); 53 | if (c == ' ' && quotes.size() == 0) { // split command on spaces 54 | args.add(arg); 55 | arg = ""; 56 | continue; 57 | } else if (c == '\'' || c == '"') { // feed state array on quote and double quotes 58 | if (quotes.size() > 0 && quotes.get(0) == c) { 59 | quotes.remove(0); 60 | } else { 61 | quotes.add(0, c); 62 | } 63 | } 64 | arg += c; 65 | } 66 | // add last parsed elem 67 | if (arg != "") { 68 | args.add(arg); 69 | } 70 | // check unconsistent state 71 | if (quotes.size() != 0) { 72 | throw new MinimesosException("Marathon cmd config quotes are not closed properly"); 73 | 74 | } 75 | return args.toArray(new String[args.size()]); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/Downloader.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.mashape.unirest.http.HttpResponse; 5 | import com.mashape.unirest.http.Unirest; 6 | import com.mashape.unirest.http.exceptions.UnirestException; 7 | import org.apache.http.HttpStatus; 8 | 9 | import java.net.URI; 10 | 11 | public class Downloader { 12 | 13 | public String getFileContentAsString(String url) throws MinimesosException { 14 | HttpResponse response = null; 15 | try { 16 | response = Unirest.get(url) 17 | .header("content-type", "*/*") 18 | .asString(); 19 | } catch (UnirestException e) { 20 | throw new MinimesosException(String.format("Cannot fetch file '%s': '%s'", url, e.getMessage())); 21 | } 22 | if (response.getStatus() != HttpStatus.SC_OK) { 23 | throw new MinimesosException(String.format("Cannot fetch file '%s': '%s'", url, response.getStatus())); 24 | } 25 | return response.getBody(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/Environment.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | /** 4 | * Utility for detecting the runtime environment. 5 | */ 6 | public class Environment { 7 | 8 | private Environment() { 9 | 10 | } 11 | 12 | /** 13 | * Checks if minimesos cli runs in JVM on Mac OS X. 14 | * 15 | * @return true if it runs on Mac OS X without Docker 16 | */ 17 | public static boolean isRunningInJvmOnMacOsX() { 18 | return System.getProperty("os.name").contains("Mac OS X"); 19 | } 20 | 21 | /** 22 | * Checks if minimesos cli runs in Docker on Mac 23 | * 24 | * @return true if MINIMESOS_OS env var is set by bin/minimesos 25 | */ 26 | public static boolean isRunningInDockerOnMac() { 27 | return System.getenv("MINIMESOS_OS") != null && System.getenv("MINIMESOS_OS").contains("Mac OS X"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/EnvironmentBuilder.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import java.util.Map; 4 | import java.util.TreeMap; 5 | 6 | /** 7 | * Provides convenient API for building a map of environment variables. 8 | * Produces the String[] format needed by CreateContainerCmd.setEnv() 9 | */ 10 | public class EnvironmentBuilder { 11 | 12 | private Map envMap = new TreeMap<>(); 13 | 14 | public static EnvironmentBuilder newEnvironment() { 15 | return new EnvironmentBuilder(); 16 | } 17 | 18 | public EnvironmentBuilder withValue(String key, String value) { 19 | envMap.put(key, value); 20 | return this; 21 | } 22 | 23 | public EnvironmentBuilder withValues(Map envMap) { 24 | this.envMap.putAll(envMap); 25 | return this; 26 | } 27 | 28 | public String[] createEnvironment() { 29 | return envMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).toArray(String[]::new); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/Predicate.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | public interface Predicate { 4 | boolean test(T t); 5 | } -------------------------------------------------------------------------------- /minimesos/src/main/java/com/containersol/minimesos/util/ResourceUtil.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | 8 | /** 9 | * Utility for dealing with Mesos resources 10 | */ 11 | public class ResourceUtil { 12 | 13 | private ResourceUtil() { 14 | 15 | } 16 | 17 | /** 18 | * Turns a Mesos resource string into a List of ports. 19 | *

20 | * Example: 'ports(*):[31000-32000],;cpus(*):0.2; mem(*):256; disk(*):200' returns [31000, 32000] 21 | * 22 | * @param mesosResourceString Mesos resource string 23 | * @return list of ports if any 24 | * @throws MinimesosException if resource string is incorrect 25 | */ 26 | public static ArrayList parsePorts(String mesosResourceString) { 27 | if (mesosResourceString == null) { 28 | throw new MinimesosException("Resource string is null"); 29 | } 30 | String portRangeString = mesosResourceString.replaceAll(".*ports\\(.+\\):\\[(.*)\\].*", "$1"); 31 | ArrayList portRanges = new ArrayList<>(Arrays.asList(portRangeString.split(","))); 32 | ArrayList returnList = new ArrayList<>(); 33 | for (String portRange : portRanges) { 34 | 35 | if (!portRange.matches("\\d+-\\d+")) { 36 | throw new MinimesosException("Resource string '" + mesosResourceString + "' is incorrect. We only support a single port range."); 37 | } 38 | String[] ports = portRange.split("-"); 39 | int startPort = Integer.valueOf(ports[0]); 40 | int endPort = Integer.valueOf(ports[1]); 41 | if (startPort > endPort) { 42 | throw new MinimesosException("Incorrect port range. Start port " + startPort + " is greater than end port " + endPort); 43 | } 44 | for (int i = startPort; i <= endPort; i++) { 45 | returnList.add(i); 46 | } 47 | } 48 | return returnList; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /minimesos/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | System.out 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | %msg%n 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /minimesos/src/main/resources/marathon/elasticsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "elasticsearch-mesos-scheduler", 3 | "container": { 4 | "docker": { 5 | "image": "mesos/elasticsearch-scheduler", 6 | "network": "BRIDGE" 7 | } 8 | }, 9 | "args": [ 10 | "--zookeeperMesosUrl", 11 | "{{MINIMESOS_ZOOKEEPER}}", 12 | "--useIpAddress", 13 | "true" 14 | ], 15 | "cpus": 0.2, 16 | "mem": 512.0, 17 | "env": { 18 | "JAVA_OPTS": "-Xms128m -Xmx256m" 19 | }, 20 | "instances": 1 21 | } 22 | -------------------------------------------------------------------------------- /minimesos/src/main/resources/marathon/mesos-consul.json: -------------------------------------------------------------------------------- 1 | { 2 | "args": [ 3 | "--zk={{MINIMESOS_ZOOKEEPER}}", 4 | "--consul=1", 5 | "--consul-ip={{MINIMESOS_CONSUL_IP}}" 6 | ], 7 | "container": { 8 | "type": "DOCKER", 9 | "docker": { 10 | "network": "BRIDGE", 11 | "image": "containersol/mesos-consul:latest" 12 | } 13 | }, 14 | "id": "mesos-consul", 15 | "instances": 1, 16 | "cpus": 0.1, 17 | "mem": 256 18 | } 19 | -------------------------------------------------------------------------------- /minimesos/src/test/groovy/com/containersol/minimesos/config/AgentResourcesConfigTest.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import org.junit.Test 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class AgentResourcesConfigTest { 8 | 9 | @Test 10 | public void testDefaultResourcesAsString() { 11 | 12 | AgentResourcesConfig resources = new AgentResourcesConfig() 13 | String asString = resources.asMesosString() 14 | String expected = "ports(*):[31000-32000]; cpus(*):4; mem(*):1024; disk(*):2000" 15 | 16 | assertEquals(expected, asString) 17 | 18 | } 19 | 20 | @Test 21 | public void testPortsFromString() { 22 | 23 | String strResources = "ports(*):[8081-8082]" 24 | AgentResourcesConfig resources = AgentResourcesConfig.fromString(strResources); 25 | 26 | assertEquals(0, resources.cpus.size()) 27 | assertEquals(0, resources.disks.size()) 28 | assertEquals(0, resources.mems.size()) 29 | 30 | assertEquals(1, resources.ports.size()) 31 | assertEquals("[8081-8082]", String.valueOf(resources.ports["*"].value)) 32 | 33 | } 34 | 35 | @Test 36 | public void testPortsCpusFromString() { 37 | 38 | String strResources = "ports(*):[8081-8082]; cpus(*):1.2" 39 | AgentResourcesConfig resources = AgentResourcesConfig.fromString(strResources); 40 | 41 | assertEquals(1, resources.cpus.size()) 42 | double actual = resources.cpus["*"].value 43 | assertEquals(1.2, actual, 0.001) 44 | 45 | assertEquals(0, resources.disks.size()) 46 | assertEquals(0, resources.mems.size()) 47 | 48 | assertEquals(1, resources.ports.size()) 49 | assertEquals("[8081-8082]", resources.ports["*"].value) 50 | 51 | } 52 | 53 | @Test 54 | public void testElasticSearchResources() { 55 | 56 | String resources = "ports(testRole):[9200-9200,9300-9300]; cpus(testRole):0.2; mem(testRole):256; disk(testRole):200" 57 | AgentResourcesConfig resourcesConfig = AgentResourcesConfig.fromString(resources) 58 | 59 | assertEquals("one role is expected for ports", 1, resourcesConfig.ports.size()) 60 | assertEquals("one role is expected for cpus", 1, resourcesConfig.cpus.size()) 61 | assertEquals("one role is expected for mem", 1, resourcesConfig.mems.size()) 62 | assertEquals("one role is expected for disk", 1, resourcesConfig.disks.size()) 63 | 64 | assertEquals("[9200-9200,9300-9300]", resourcesConfig.ports["testRole"].value) 65 | assertEquals(0.2, resourcesConfig.cpus["testRole"].value, 0.0001) 66 | assertEquals(256, resourcesConfig.mems["testRole"].value, 0.0001) 67 | assertEquals(200, resourcesConfig.disks["testRole"].value, 0.0001) 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /minimesos/src/test/groovy/com/containersol/minimesos/config/ConfigWriterTest.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import org.junit.Before 4 | import org.junit.Test 5 | 6 | import static org.junit.Assert.* 7 | 8 | public class ConfigWriterTest { 9 | 10 | private ConfigParser parser 11 | 12 | @Before 13 | public void before() { 14 | parser = new ConfigParser() 15 | } 16 | 17 | @Test 18 | public void testWritingDefaultConfiguration() { 19 | ClusterConfig config = new ClusterConfig() 20 | String strConfig = parser.toString(config) 21 | ClusterConfig read = parser.parse(strConfig) 22 | compareClusters(config, read) 23 | } 24 | 25 | @Test 26 | public void testWritingFilledConfiguration() { 27 | 28 | ClusterConfig config = new ClusterConfig() 29 | 30 | config.master = new MesosMasterConfig() 31 | config.zookeeper = new ZooKeeperConfig() 32 | config.marathon = new MarathonConfig() 33 | config.agents.add(new MesosAgentConfig()) 34 | config.consul = new ConsulConfig() 35 | config.registrator = new RegistratorConfig() 36 | config.mesosdns = new MesosDNSConfig() 37 | 38 | AppConfig appConfig = new AppConfig() 39 | appConfig.setMarathonJson("http://www.google.com") 40 | config.marathon.apps.add(appConfig) 41 | 42 | AppConfig fileAppConfig = new AppConfig() 43 | fileAppConfig.setMarathonJson("/temp/fileA") 44 | config.marathon.apps.add(fileAppConfig) 45 | 46 | String strConfig = parser.toString(config) 47 | ClusterConfig read = parser.parse(strConfig) 48 | 49 | compareClusters(config, read) 50 | assertNotNull("Marathon container must be set", read.marathon) 51 | assertEquals(config.marathon.apps.size(), read.marathon.apps.size()) 52 | assertEquals("http://www.google.com", read.marathon.apps[0].marathonJson) 53 | assertEquals("/temp/fileA", read.marathon.apps[1].marathonJson) 54 | 55 | } 56 | 57 | static private void compareClusters(ClusterConfig first, ClusterConfig second) { 58 | 59 | assertEquals(first.timeout, second.timeout) 60 | assertEquals(first.clusterName, second.clusterName) 61 | assertEquals(first.mapPortsToHost, second.mapPortsToHost) 62 | assertEquals(first.loggingLevel, second.loggingLevel) 63 | 64 | compareContainers(first.marathon, second.marathon) 65 | 66 | compareContainers(first.zookeeper, second.zookeeper) 67 | compareContainers(first.consul, second.consul) 68 | compareContainers(first.registrator, second.registrator) 69 | compareContainers(first.mesosdns, second.mesosdns) 70 | 71 | compareMesosContainers(first.master, second.master) 72 | 73 | assertEquals(first.agents.size(), second.agents.size()) 74 | if (first.agents.size() > 0) { 75 | compareMesosContainers(first.agents[0], second.agents[0]) 76 | } 77 | 78 | } 79 | 80 | static void compareContainers(ContainerConfig first, ContainerConfig second) { 81 | if (first == null) { 82 | if (second != null) { 83 | fail("Expected null, but found " + second) 84 | } 85 | } else { 86 | if (second == null) { 87 | fail("Expected " + first + ", but null was found") 88 | } else { 89 | assertEquals(first.imageName, second.imageName) 90 | assertEquals(first.imageTag, second.imageTag) 91 | } 92 | } 93 | } 94 | 95 | static void compareMesosContainers(MesosContainerConfig first, MesosContainerConfig second) { 96 | compareContainers(first, second) 97 | if (first != null) { 98 | assertEquals(first.loggingLevel, second.loggingLevel) 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /minimesos/src/test/groovy/com/containersol/minimesos/config/ResourceDefScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.config 2 | 3 | import org.junit.Test 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class ResourceDefScalarTest { 8 | 9 | @Test 10 | public void testDotParsing() { 11 | 12 | ResourceDefScalar resource = new ResourceDefScalar() 13 | resource.setValue("1.2"); 14 | 15 | assertEquals(1.2, resource.getValue(), 0.0001) 16 | 17 | } 18 | 19 | @Test(expected = NumberFormatException.class) 20 | public void testCommaParsing() { 21 | 22 | ResourceDefScalar resource = new ResourceDefScalar() 23 | resource.setValue("1,2"); 24 | 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/ClusterBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos; 2 | 3 | import com.containersol.minimesos.cluster.MesosCluster; 4 | import com.containersol.minimesos.config.ClusterConfig; 5 | import com.containersol.minimesos.config.ConfigParser; 6 | import com.containersol.minimesos.mesos.MesosAgentContainer; 7 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 8 | import com.containersol.minimesos.util.CollectionsUtils; 9 | import org.junit.Test; 10 | 11 | import java.util.List; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class ClusterBuilderTest { 16 | 17 | @Test 18 | public void testInheritedImageTag() { 19 | String config = "minimesos { \n" + 20 | "mesosVersion = \"0.26\" \n" + 21 | "agent { imageTag = \"0.27.0-0.1.0\"} \n" + 22 | "agent {} \n" + 23 | "}"; 24 | 25 | ConfigParser parser = new ConfigParser(); 26 | ClusterConfig dsl = parser.parse(config); 27 | 28 | MesosCluster cluster = new MesosClusterContainersFactory().createMesosCluster(dsl); 29 | 30 | List agents = CollectionsUtils.typedList(cluster.getAgents(), MesosAgentContainer.class); 31 | assertEquals(2, agents.size()); 32 | 33 | assertEquals("0.27.0-" + ClusterConfig.DEFAULT_MINIMESOS_DOCKER_VERSION, agents.get(0).getImageTag()); 34 | assertEquals("0.26-" + ClusterConfig.DEFAULT_MINIMESOS_DOCKER_VERSION, agents.get(1).getImageTag()); 35 | } 36 | 37 | @Test 38 | public void testDefaultInAgentLoggingLevel() { 39 | String config = "minimesos { \n" + 40 | "loggingLevel = \"warning\" \n" + 41 | "agent { loggingLevel = \"ERROR\" } \n" + 42 | "agent { loggingLevel = \"INFO\" } \n" + 43 | "}"; 44 | 45 | ConfigParser parser = new ConfigParser(); 46 | ClusterConfig dsl = parser.parse(config); 47 | 48 | MesosCluster cluster = new MesosClusterContainersFactory().createMesosCluster(dsl); 49 | 50 | List agents = CollectionsUtils.typedList(cluster.getAgents(), MesosAgentContainer.class); 51 | assertEquals(2, agents.size()); 52 | 53 | assertEquals("ERROR", agents.get(0).getLoggingLevel()); 54 | assertEquals("INFO", agents.get(1).getLoggingLevel()); 55 | } 56 | 57 | @Test 58 | public void testInheritedLoggingLevel() { 59 | String config = "minimesos { \n" + 60 | "loggingLevel = \"warning\" \n" + 61 | "agent { loggingLevel = \"ERROR\"} \n" + 62 | "agent {} \n" + 63 | "}"; 64 | 65 | ConfigParser parser = new ConfigParser(); 66 | ClusterConfig dsl = parser.parse(config); 67 | 68 | MesosCluster cluster = new MesosClusterContainersFactory().createMesosCluster(dsl); 69 | 70 | List agents = CollectionsUtils.typedList(cluster.getAgents(), MesosAgentContainer.class); 71 | assertEquals(2, agents.size()); 72 | 73 | assertEquals("ERROR", agents.get(0).getLoggingLevel()); 74 | assertEquals("WARNING", agents.get(1).getLoggingLevel()); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/factory/MesosClusterContainersFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.factory; 2 | 3 | import com.containersol.minimesos.cluster.MesosCluster; 4 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 5 | import org.junit.Test; 6 | 7 | import java.io.FileInputStream; 8 | import java.io.FileNotFoundException; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNotNull; 12 | 13 | public class MesosClusterContainersFactoryTest { 14 | 15 | @Test 16 | public void testCreateMesosCluster() throws FileNotFoundException { 17 | MesosCluster mesosCluster = new MesosClusterContainersFactory().createMesosCluster(new FileInputStream("src/test/resources/configFiles/minimesosFile-mesosClusterTest")); 18 | assertEquals(3 , mesosCluster.getAgents().size()); 19 | assertNotNull(mesosCluster.getZooKeeper()); 20 | assertNotNull(mesosCluster.getMaster()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/integrationtest/container/ContainerNameTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest.container; 2 | 3 | import com.containersol.minimesos.cluster.MesosCluster; 4 | import com.containersol.minimesos.mesos.MesosAgentContainer; 5 | import com.containersol.minimesos.mesos.MesosClusterContainersFactory; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class ContainerNameTest { 14 | 15 | private MesosCluster cluster; 16 | private String clusterId; 17 | 18 | @Before 19 | public void before() { 20 | cluster = new MesosClusterContainersFactory().createMesosCluster("src/test/resources/configFiles/minimesosFile-mesosClusterTest"); 21 | 22 | clusterId = cluster.getClusterId(); 23 | } 24 | 25 | @Test 26 | public void testBelongsToCluster() throws Exception { 27 | MesosAgentContainer agent = new MesosAgentContainer(cluster, "UUID", "CONTAINERID"); 28 | String containerName = ContainerName.get(agent); 29 | 30 | assertTrue(ContainerName.hasRoleInCluster(containerName, clusterId, agent.getRole())); 31 | assertTrue(ContainerName.belongsToCluster(containerName, clusterId)); 32 | } 33 | 34 | @Test 35 | public void testWrongCluster() throws Exception { 36 | MesosAgentContainer agent = new MesosAgentContainer(cluster, "UUID", "CONTAINERID"); 37 | String containerName = ContainerName.get(agent); 38 | 39 | assertFalse(ContainerName.hasRoleInCluster(containerName, "XXXXXX", agent.getRole())); 40 | assertFalse(ContainerName.belongsToCluster(containerName, "XXXXXX")); 41 | } 42 | 43 | @Test 44 | public void testWrongRole() throws Exception { 45 | MesosAgentContainer agent = new MesosAgentContainer(cluster, "UUID", "CONTAINERID"); 46 | String containerName = ContainerName.get(agent); 47 | 48 | assertFalse(ContainerName.hasRoleInCluster(containerName, clusterId, "XXXXXX")); 49 | assertTrue(ContainerName.belongsToCluster(containerName, clusterId)); 50 | } 51 | 52 | @Test 53 | public void testSimpleContainerName() { 54 | String[] names = new String[1]; 55 | names[0] = "/minimesos-agent"; 56 | 57 | assertEquals("minimesos-agent", ContainerName.getFromDockerNames(names)); 58 | } 59 | 60 | @Test 61 | public void testLinkedContainerNames() { 62 | String[] names = new String[4]; 63 | names[0] = "/minimesos-agent0/minimesos-zookeeper"; 64 | names[1] = "/minimesos-agent1/minimesos-zookeeper"; 65 | names[2] = "/minimesos-agent2/minimesos-zookeeper"; 66 | names[3] = "/minimesos-zookeeper"; 67 | 68 | assertEquals("minimesos-zookeeper", ContainerName.getFromDockerNames(names)); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/integrationtest/container/MesosAgentTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.integrationtest.container; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import com.containersol.minimesos.config.ClusterConfig; 5 | import com.containersol.minimesos.config.MesosAgentConfig; 6 | import com.containersol.minimesos.mesos.MesosAgentContainer; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | public class MesosAgentTest { 11 | 12 | /** 13 | * It must be possible to detect wrong image within 30 seconds 14 | */ 15 | @Test(expected = MinimesosException.class, timeout = 60 * 1000) 16 | public void testPullingWrongContainer() { 17 | MesosAgentConfig config = new MesosAgentConfig(ClusterConfig.DEFAULT_MESOS_VERSION); 18 | config.setImageTag("non-existing-one"); 19 | 20 | MesosAgentContainer agent = new MesosAgentContainer(config); 21 | agent.pullImage(); 22 | } 23 | 24 | /** 25 | * Test error message 26 | */ 27 | @Test 28 | public void testPullingWrongContainerMessage() { 29 | 30 | String imageTag = "non-existing-one"; 31 | 32 | MesosAgentConfig config = new MesosAgentConfig(ClusterConfig.DEFAULT_MESOS_VERSION); 33 | config.setImageTag(imageTag); 34 | 35 | MesosAgentContainer agent = new MesosAgentContainer(config); 36 | try { 37 | agent.pullImage(); 38 | Assert.fail("Pulling non-existing image should result in an exception"); 39 | } catch (MinimesosException mme) { 40 | Assert.assertTrue("Name of the image should be in the error message: " + mme.getMessage(), mme.getMessage().contains(imageTag)); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/jdepend/JDependCyclesTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.jdepend; 2 | 3 | import jdepend.framework.JDepend; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertNotNull; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | /** 14 | * Ensures absence of dependency cycles 15 | */ 16 | public class JDependCyclesTest { 17 | 18 | private static final String EXPECTED_PACKAGE = "com.containersol.minimesos"; 19 | 20 | private JDepend jdepend; 21 | 22 | @Before 23 | public void before() throws IOException { 24 | jdepend = new JDepend(); 25 | jdepend.addDirectory("build/classes/main"); 26 | } 27 | 28 | /** 29 | * Tests that a package dependency cycle does not 30 | * exist for any of the analyzed packages. 31 | */ 32 | @Test 33 | public void testAllPackages() { 34 | 35 | jdepend.analyze(); 36 | assertTrue("Something is wrong with JDepend setup", jdepend.getPackages().size() > 0); 37 | assertNotNull("Package " + EXPECTED_PACKAGE + " is not found. Please, check", jdepend.getPackage(EXPECTED_PACKAGE)); 38 | assertEquals("Dependency Cycles are introduced", false, jdepend.containsCycles()); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/mesos/ClusterContainersTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.cluster.ClusterProcess; 4 | import com.containersol.minimesos.cluster.Filter; 5 | import com.containersol.minimesos.cluster.MesosAgent; 6 | import com.containersol.minimesos.cluster.MesosMaster; 7 | import com.containersol.minimesos.cluster.ZooKeeper; 8 | import org.junit.Test; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assert.assertTrue; 15 | import static org.mockito.Mockito.mock; 16 | 17 | /** 18 | * Tests 19 | */ 20 | public class ClusterContainersTest { 21 | @Test 22 | public void shouldEmptyStart() { 23 | assertTrue(new ClusterContainers().getContainers().isEmpty()); 24 | } 25 | 26 | @Test 27 | public void shouldAllowInjection() { 28 | List dummyList = new ArrayList<>(); 29 | assertEquals(dummyList, new ClusterContainers(dummyList).getContainers()); 30 | } 31 | 32 | @Test 33 | public void shouldFilterZooKeeper() { 34 | ZooKeeper mock = mock(ZooKeeper.class); 35 | ClusterProcess clusterProcess = mock(ClusterProcess.class); 36 | ClusterContainers clusterContainers = new ClusterContainers(); 37 | clusterContainers.add(mock).add(clusterProcess); 38 | 39 | assertTrue(clusterContainers.isPresent(Filter.zooKeeper())); 40 | } 41 | 42 | @Test 43 | public void shouldFilterMesosMaster() { 44 | MesosMaster mock = mock(MesosMaster.class); 45 | ClusterProcess clusterProcess = mock(ClusterProcess.class); 46 | ClusterContainers clusterContainers = new ClusterContainers(); 47 | clusterContainers.add(mock).add(clusterProcess); 48 | 49 | assertTrue(clusterContainers.isPresent(Filter.mesosMaster())); 50 | } 51 | 52 | @Test 53 | public void shouldFilterMesosAgent() { 54 | MesosAgent mock = mock(MesosAgent.class); 55 | ClusterProcess clusterProcess = mock(ClusterProcess.class); 56 | ClusterContainers clusterContainers = new ClusterContainers(); 57 | clusterContainers.add(mock).add(clusterProcess); 58 | 59 | assertTrue(clusterContainers.isPresent(Filter.mesosAgent())); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/mesos/ClusterUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.mesos; 2 | 3 | import com.containersol.minimesos.cluster.ClusterProcess; 4 | import com.containersol.minimesos.cluster.ClusterUtil; 5 | import com.containersol.minimesos.config.ClusterConfig; 6 | import com.containersol.minimesos.config.ConsulConfig; 7 | import com.containersol.minimesos.config.MesosAgentConfig; 8 | import com.containersol.minimesos.config.MesosMasterConfig; 9 | import com.containersol.minimesos.integrationtest.container.AbstractContainer; 10 | import com.github.dockerjava.api.command.CreateContainerCmd; 11 | import org.junit.Test; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertTrue; 18 | 19 | /** 20 | * Tests helper methods 21 | */ 22 | public class ClusterUtilTest { 23 | 24 | @Test 25 | public void testGetDistinctRoleProcesses() throws Exception { 26 | 27 | ClusterProcess master = new AbstractContainer(new MesosMasterConfig(ClusterConfig.DEFAULT_MESOS_VERSION)) { 28 | @Override 29 | protected CreateContainerCmd dockerCommand() { 30 | return null; 31 | } 32 | 33 | @Override 34 | public String getRole() { 35 | return "master"; 36 | } 37 | }; 38 | ClusterProcess consul = new AbstractContainer(new ConsulConfig()) { 39 | @Override 40 | protected CreateContainerCmd dockerCommand() { 41 | return null; 42 | } 43 | 44 | @Override 45 | public String getRole() { 46 | return "consul"; 47 | } 48 | }; 49 | ClusterProcess agent1 = new AbstractContainer(new MesosAgentConfig(ClusterConfig.DEFAULT_MESOS_VERSION)) { 50 | @Override 51 | protected CreateContainerCmd dockerCommand() { 52 | return null; 53 | } 54 | 55 | @Override 56 | public String getRole() { 57 | return "agent"; 58 | } 59 | }; 60 | ClusterProcess agent2 = new AbstractContainer(new MesosAgentConfig(ClusterConfig.DEFAULT_MESOS_VERSION)) { 61 | @Override 62 | protected CreateContainerCmd dockerCommand() { 63 | return null; 64 | } 65 | 66 | @Override 67 | public String getRole() { 68 | return "agent"; 69 | } 70 | }; 71 | 72 | List processes = Arrays.asList(master, consul, agent1, agent2); 73 | List distinct = ClusterUtil.getDistinctRoleProcesses(processes); 74 | 75 | assertEquals(2, distinct.size()); 76 | assertTrue("master has a distinct role", distinct.contains(master)); 77 | assertTrue("consul has a distinct role", distinct.contains(consul)); 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/util/CollectionsUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertArrayEquals; 8 | 9 | public class CollectionsUtilsTest { 10 | 11 | @Test(expected = MinimesosException.class) 12 | public void testSplitCmd_uncoherentCommandLine() { 13 | CollectionsUtils.splitCmd("foo bar='test"); 14 | } 15 | 16 | @Test 17 | public void testSplitCmd_cmdLineEmpty() { 18 | assertArrayEquals( 19 | CollectionsUtils.splitCmd(""), 20 | new String[]{} 21 | ); 22 | } 23 | 24 | @Test 25 | public void testSplitCmd_cmdLineNoQuotes() { 26 | assertArrayEquals( 27 | CollectionsUtils.splitCmd("foo bar baaz qux"), 28 | new String[]{"foo", "bar", "baaz", "qux"} 29 | ); 30 | } 31 | 32 | @Test 33 | public void testSplitCmd_cmdLineWithQuotes() { 34 | assertArrayEquals( 35 | CollectionsUtils.splitCmd("foo='bar baaz' qux"), 36 | new String[]{"foo='bar baaz'", "qux"} 37 | ); 38 | } 39 | 40 | @Test 41 | public void testSplitCmd_cmdLineWithDoubleQuotes() { 42 | assertArrayEquals( 43 | CollectionsUtils.splitCmd("foo=\"bar baaz\" qux"), 44 | new String[]{"foo=\"bar baaz\"", "qux"} 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/util/EnvironmentBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | import static org.hamcrest.Matchers.array; 10 | import static org.hamcrest.Matchers.is; 11 | 12 | public class EnvironmentBuilderTest { 13 | 14 | @Test 15 | @SuppressWarnings("unchecked") 16 | public void mergingSeveralSourcesProducesCorrectMap() { 17 | Map source1 = new TreeMap<>(); 18 | source1.put("envVar1", "value1"); 19 | source1.put("envVar2", "value2"); 20 | source1.put("envVar3", "value3"); 21 | source1.put("envVar4", "value4"); 22 | Map source2 = new TreeMap<>(); 23 | source2.put("envVar5", "value5"); 24 | source2.put("envVar6", "value6"); 25 | 26 | String[] result = EnvironmentBuilder.newEnvironment() 27 | .withValues(source1) 28 | .withValue("envVarX", "valueX") 29 | .withValues(source2) 30 | .createEnvironment(); 31 | 32 | Assert.assertThat(result, array(is("envVar1=value1"), 33 | is("envVar2=value2"), is("envVar3=value3"), is("envVar4=value4"), 34 | is("envVar5=value5"), is("envVar6=value6"), is("envVarX=valueX"))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /minimesos/src/test/java/com/containersol/minimesos/util/ResourceUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.containersol.minimesos.util; 2 | 3 | import com.containersol.minimesos.MinimesosException; 4 | import org.junit.Test; 5 | 6 | import java.util.ArrayList; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class ResourceUtilTest { 11 | 12 | @Test(expected = MinimesosException.class) 13 | public void testParsePorts_emptyResourceString() { 14 | ResourceUtil.parsePorts(""); 15 | } 16 | 17 | @Test(expected = MinimesosException.class) 18 | public void testParsePorts_nullResource() { 19 | ResourceUtil.parsePorts(null); 20 | } 21 | 22 | @Test 23 | public void testParsePorts_singlePortRange() { 24 | ArrayList ports = ResourceUtil.parsePorts("ports(*):[8080-8080]"); 25 | assertEquals(1, ports.size()); 26 | assertEquals(8080, ports.get(0).intValue()); 27 | } 28 | 29 | @Test 30 | public void testParsePorts_portRange() { 31 | ArrayList ports = ResourceUtil.parsePorts("ports(*):[8080-8082]"); 32 | assertEquals(3, ports.size()); 33 | assertEquals(8080, ports.get(0).intValue()); 34 | assertEquals(8081, ports.get(1).intValue()); 35 | assertEquals(8082, ports.get(2).intValue()); 36 | } 37 | 38 | @Test(expected = MinimesosException.class) 39 | /** 40 | * Should be resolved by https://github.com/ContainerSolutions/minimesos/issues/237 41 | */ 42 | public void testParsePorts_portRanges() { 43 | ResourceUtil.parsePorts("ports(*):[8080-8082],[5000-5001]"); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /minimesos/src/test/resources/configFiles/minimesosFile-authenticationTest: -------------------------------------------------------------------------------- 1 | minimesos { 2 | clusterName = "authentication-test" 3 | mapPortsToHost = false 4 | loggingLevel = "INFO" 5 | mapAgentSandboxVolume = false 6 | mesosVersion = "1.0.0" 7 | timeout = 60 8 | 9 | master { 10 | imageName = "containersol/mesos-master" 11 | imageTag = "1.0.0-0.1.0" 12 | authenticate = true 13 | aclJson = """ 14 | { 15 | "run_tasks": [ 16 | { "principals": { "values": ["foo", "bar"] }, 17 | "users": { "values": ["alice"] } 18 | } 19 | ] 20 | } 21 | """ 22 | } 23 | 24 | zookeeper { 25 | imageName = "jplock/zookeeper" 26 | imageTag = "3.4.6" 27 | } 28 | 29 | agent { 30 | imageName = "containersol/mesos-agent" 31 | imageTag = "1.0.0-0.1.0" 32 | loggingLevel = "# INHERIT FROM CLUSTER" 33 | portNumber = 5051 34 | 35 | resources { 36 | 37 | cpu { 38 | role = "*" 39 | value = 4 40 | } 41 | 42 | disk { 43 | role = "*" 44 | value = 2000 45 | } 46 | 47 | mem { 48 | role = "*" 49 | value = 512 50 | } 51 | 52 | ports { 53 | role = "*" 54 | value = "[31000-32000]" 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /minimesos/src/test/resources/configFiles/minimesosFile-mesosClusterTest: -------------------------------------------------------------------------------- 1 | minimesos { 2 | clusterName = "mesos-cluster-test" 3 | mapPortsToHost = true 4 | loggingLevel = "INFO" 5 | mapAgentSandboxVolume = false 6 | mesosVersion = "1.0.0" 7 | timeout = 60 8 | 9 | agent { 10 | imageName = "containersol/mesos-agent" 11 | imageTag = "1.0.0-0.1.0" 12 | loggingLevel = "# INHERIT FROM CLUSTER" 13 | portNumber = 5051 14 | attributes = "az:0a" 15 | 16 | resources { 17 | 18 | cpu { 19 | role = "*" 20 | value = 4 21 | } 22 | 23 | disk { 24 | role = "*" 25 | value = 2000 26 | } 27 | 28 | mem { 29 | role = "*" 30 | value = 512 31 | } 32 | 33 | ports { 34 | role = "*" 35 | value = "[31000-32000]" 36 | } 37 | } 38 | } 39 | 40 | agent { 41 | imageName = "containersol/mesos-agent" 42 | imageTag = "1.0.0-0.1.0" 43 | loggingLevel = "# INHERIT FROM CLUSTER" 44 | portNumber = 5051 45 | 46 | resources { 47 | 48 | cpu { 49 | role = "*" 50 | value = 4 51 | } 52 | 53 | disk { 54 | role = "*" 55 | value = 2000 56 | } 57 | 58 | mem { 59 | role = "*" 60 | value = 512 61 | } 62 | 63 | ports { 64 | role = "*" 65 | value = "[31000-32000]" 66 | } 67 | } 68 | } 69 | 70 | agent { 71 | imageName = "containersol/mesos-agent" 72 | imageTag = "1.0.0-0.1.0" 73 | loggingLevel = "# INHERIT FROM CLUSTER" 74 | portNumber = 5051 75 | 76 | resources { 77 | 78 | cpu { 79 | role = "*" 80 | value = 4 81 | } 82 | 83 | disk { 84 | role = "*" 85 | value = 2000 86 | } 87 | 88 | mem { 89 | role = "*" 90 | value = 512 91 | } 92 | 93 | ports { 94 | role = "*" 95 | value = "[31000-32000]" 96 | } 97 | } 98 | } 99 | 100 | consul { 101 | imageName = "consul" 102 | imageTag = "0.7.1" 103 | } 104 | 105 | master { 106 | imageName = "containersol/mesos-master" 107 | imageTag = "1.0.0-0.1.0" 108 | loggingLevel = "# INHERIT FROM CLUSTER" 109 | } 110 | 111 | marathon { 112 | imageName = "mesosphere/marathon" 113 | imageTag = "v1.3.5" 114 | } 115 | 116 | zookeeper { 117 | imageName = "jplock/zookeeper" 118 | imageTag = "3.4.6" 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /minimesos/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | System.out 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}: %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /opt/apps/weave-scope.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "weave-scope", 3 | "cpus": 1, 4 | "mem": 128, 5 | "instances": 1, 6 | "constraints": [ 7 | [ 8 | "hostname", 9 | "UNIQUE" 10 | ] 11 | ], 12 | "container": { 13 | "type": "DOCKER", 14 | "docker": { 15 | "image": "weaveworks/scope:0.13.1", 16 | "network": "HOST", 17 | "privileged": true, 18 | "parameters": [ 19 | { "key": "pid", "value": "host" }, 20 | { "key": "name", "value": "weavescope" } 21 | ] 22 | }, 23 | "volumes": [ 24 | { 25 | "containerPath": "/var/run/docker.sock", 26 | "hostPath": "/var/run/docker.sock", 27 | "mode": "RW" 28 | } 29 | ] 30 | }, 31 | "args": ["--probe.docker", "true"], 32 | "env": { 33 | "CHECKPOINT_DISABLE": "" 34 | }, 35 | "portDefinitions": [ 36 | { "port": 4040, "protocol": "tcp", "name": "http" } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /opt/sonar/DockerFile: -------------------------------------------------------------------------------- 1 | FROM sonarqube:5.3 2 | MAINTAINER Container Solutions BV 3 | 4 | ADD sonar-plugins/sonar-github-plugin-1.1.jar /opt/sonarqube/extensions/plugins 5 | ADD sonar-plugins/sonar-java-plugin-3.7.1.jar /opt/sonarqube/extensions/plugins 6 | ADD sonar-plugins/sonar-scm-git-plugin-1.0.jar /opt/sonarqube/extensions/plugins 7 | ADD sonar-plugins/sonar-scm-svn-plugin-1.2.jar /opt/sonarqube/extensions/plugins 8 | -------------------------------------------------------------------------------- /opt/sonar/certificate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: ThirdPartyResource 3 | description: "A specification of a Let's Encrypt Certificate to manage." 4 | metadata: 5 | name: "certificate.stable.hightower.com" 6 | versions: 7 | - name: v1 8 | -------------------------------------------------------------------------------- /opt/sonar/setup.md: -------------------------------------------------------------------------------- 1 | ### Create Persistent Disk 2 | `gcloud compute disks create --size 200GB minimesos-sonar-postgres-disk` 3 | 4 | ### Attach created disk to linux instance for formatting and data transfer 5 | `gcloud compute instances attach-disk jenkins-ci-4 --disk minimesos-sonar-postgres-disk --device-name postgresdisk` 6 | 7 | ### Mount and format disk 8 | `/usr/share/google/safe_format_and_mount /dev/disk/by-id/google-postgresdisk /postgresdisk` 9 | 10 | ### Detach Disk from linux instance 11 | `gcloud compute instances detach-disk jenkins-ci-4 --disk minimesos-sonar-postgres-disk` 12 | 13 | ### Create cluster 14 | `gcloud container clusters create "minimesos-sonar" --zone "europe-west1-d" --machine-type "n1-standard-2" --num-nodes "1" --network "ci-network" --enable-cloud-logging` 15 | 16 | Download cluster credentials into kubectl: 17 | `gcloud container clusters get-credentials minimesos-sonar` 18 | 19 | ### Create database password secret 20 | This password gets applied to the postgres database on first start, changin it later is not possible as it's persisted 21 | to the persistent disk 22 | 23 | echo -n "thepassword" > password 24 | `kubectl create secret generic postgres-pwd --from-file=./password` 25 | 26 | ### Create Certificate 27 | 28 | kubectl create -f certificate.yaml 29 | 30 | 31 | 32 | 1. Create new domain name as old one can't be shared anymore between Jenkins and Sonar. sonar.minimesos.ci.container-solutions.com 33 | 2. Make https work for sonar 34 | 3. User management in sonar? 35 | -------------------------------------------------------------------------------- /opt/sonar/sonar-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: sonar 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | name: sonar 10 | labels: 11 | name: sonar 12 | spec: 13 | containers: 14 | - image: containersol/minimesos-sonar 15 | args: 16 | - -Dsonar.web.context=/sonar 17 | name: sonar 18 | env: 19 | - name: SONARQUBE_JDBC_PASSWORD 20 | valueFrom: 21 | secretKeyRef: 22 | name: postgres-pwd 23 | key: password 24 | - name: SONARQUBE_JDBC_URL 25 | value: jdbc:postgresql://sonar-postgres:5432/sonar 26 | ports: 27 | - containerPort: 9000 28 | name: sonar 29 | -------------------------------------------------------------------------------- /opt/sonar/sonar-plugins/sonar-github-plugin-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/opt/sonar/sonar-plugins/sonar-github-plugin-1.1.jar -------------------------------------------------------------------------------- /opt/sonar/sonar-plugins/sonar-java-plugin-3.7.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/opt/sonar/sonar-plugins/sonar-java-plugin-3.7.1.jar -------------------------------------------------------------------------------- /opt/sonar/sonar-plugins/sonar-scm-git-plugin-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/opt/sonar/sonar-plugins/sonar-scm-git-plugin-1.0.jar -------------------------------------------------------------------------------- /opt/sonar/sonar-plugins/sonar-scm-svn-plugin-1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContainerSolutions/minimesos/016f15443f4f82b586545341a709d3d0cfbb00ba/opt/sonar/sonar-plugins/sonar-scm-svn-plugin-1.2.jar -------------------------------------------------------------------------------- /opt/sonar/sonar-postgres-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: sonar-postgres 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | name: sonar-postgres 10 | labels: 11 | name: sonar-postgres 12 | spec: 13 | containers: 14 | - image: postgres:9.5.3 15 | name: sonar-postgres 16 | env: 17 | - name: POSTGRES_PASSWORD 18 | valueFrom: 19 | secretKeyRef: 20 | name: postgres-pwd 21 | key: password 22 | - name: POSTGRES_USER 23 | value: sonar 24 | ports: 25 | - containerPort: 5432 26 | name: postgresport 27 | volumeMounts: 28 | # This name must match the volumes.name below. 29 | - name: data-disk 30 | mountPath: /var/lib/postgresql/data 31 | volumes: 32 | - name: data-disk 33 | gcePersistentDisk: 34 | # This disk must already exist. 35 | pdName: minimesos-sonar-postgres-disk 36 | fsType: ext4 37 | -------------------------------------------------------------------------------- /opt/sonar/sonar-postgres-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | name: sonar-postgres 6 | name: sonar-postgres 7 | spec: 8 | ports: 9 | - port: 5432 10 | selector: 11 | name: sonar-postgres 12 | -------------------------------------------------------------------------------- /opt/sonar/sonar-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | name: sonar 6 | name: sonar 7 | spec: 8 | ports: 9 | - port: 80 10 | targetPort: 9000 11 | name: sonarport 12 | selector: 13 | name: sonar 14 | type: LoadBalancer 15 | -------------------------------------------------------------------------------- /opt/vagrant/debian/jessie64/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure(2) do |config| 2 | 3 | config.vm.box = "debian/contrib-jessie64" 4 | 5 | config.vm.provider "virtualbox" do |vb| 6 | vb.memory = "4096" 7 | end 8 | 9 | config.vm.network "private_network", ip: "192.168.123.11" 10 | 11 | config.vm.provision :shell, :path => "provision.sh" 12 | 13 | end 14 | -------------------------------------------------------------------------------- /opt/vagrant/debian/jessie64/provision.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### 4 | ### JDK and Gradle 5 | ### 6 | 7 | echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/openjdk.list && \ 8 | apt-get update -qq && apt-get install -qqy \ 9 | apt-transport-https \ 10 | curl \ 11 | unzip \ 12 | openjdk-8-jdk 13 | 14 | curl https://downloads.gradle.org/distributions/gradle-2.12-bin.zip --output /tmp/gradle-2.12-bin.zip --silent 15 | unzip -q /tmp/gradle-2.12-bin.zip -d /usr/share 16 | 17 | echo "export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre" >> /home/vagrant/.profile 18 | echo "export GRADLE_HOME=/usr/share/gradle-2.12" >> /home/vagrant/.profile 19 | echo "export PATH=\$JAVA_HOME/bin:\$GRADLE_HOME/bin:\$PATH" >> /home/vagrant/.profile 20 | 21 | update-ca-certificates -f 22 | 23 | ### 24 | ### Getting Docker installed 25 | ### 26 | echo "" 27 | echo "Getting Docker" 28 | 29 | echo "deb https://apt.dockerproject.org/repo debian-jessie main" > /etc/apt/sources.list.d/docker.list && \ 30 | apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D && \ 31 | apt-get update -qq && \ 32 | apt-get -qqy install docker-engine=1.9.1-0~jessie 33 | 34 | echo "Enabling non-sudo access to docker" 35 | gpasswd -a vagrant docker 36 | 37 | service docker start 38 | 39 | echo '' 40 | echo 'Apply command below on the host machine' 41 | echo 'sudo route delete 172.17.0.0/16; sudo route -n add 172.17.0.0/16 192.168.123.11' 42 | 43 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'minimesos-project' 2 | include "minimesos" 3 | include "cli" 4 | -------------------------------------------------------------------------------- /travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ev 3 | 4 | GH_SONARQ_PARAMS="" 5 | 6 | # When run on Travis CI, env var TRAVIS_PULL_REQUEST either contains PR number (for PR builds) or "false" (for push builds). 7 | # Locally this env var is not set. Test: if variable is not empty and is not equal "false" 8 | if [ ! -z "$TRAVIS_PULL_REQUEST" ] && [ "${TRAVIS_PULL_REQUEST}" != "false" ] && [ "${TRAVIS_SECURE_ENV_VARS}" == "true" ]; then 9 | echo "PR build. Will execute SonarQube preview scan" 10 | GH_SONARQ_PARAMS="jacocoTestReport sonarqube -Dsonar.analysis.mode=preview -Dsonar.host.url=$SQ_URL -Dsonar.github.oauth=$GH_TOKEN -Dsonar.github.repository=$TRAVIS_REPO_SLUG -Dsonar.github.pullRequest=$TRAVIS_PULL_REQUEST" 11 | fi 12 | 13 | # Update SonarQube data on push builds on master branch 14 | if [ "${TRAVIS_PULL_REQUEST}" == "false" ] && [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_SECURE_ENV_VARS}" == "true" ]; then 15 | echo "Building $TRAVIS_BRANCH branch. Will execute SonarQube scan" 16 | GH_SONARQ_PARAMS="jacocoTestReport sonarqube -Dsonar.host.url=$SQ_URL -Dsonar.jdbc.url=$SQ_JDBC_URL -Dsonar.jdbc.driverClassName=org.postgresql.Driver -Dsonar.jdbc.user=$SQ_JDBC_USER -Dsonar.jdbc.password=$SQ_JDBC_PASSWORD" 17 | fi 18 | 19 | ./gradlew --info --stacktrace clean build integrationTest $GH_SONARQ_PARAMS 20 | 21 | --------------------------------------------------------------------------------