Skip to content

Commit

Permalink
Merge pull request #1 from vpiserchia/vpiserchia/main
Browse files Browse the repository at this point in the history
Vpiserchia/main
  • Loading branch information
vpiserchia authored Nov 3, 2023
2 parents ccb6044 + 2a24580 commit b77e870
Show file tree
Hide file tree
Showing 63 changed files with 4,346 additions and 5,424 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.git/
.github/
target/
Dockerfile
cerebro.db
50 changes: 50 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: release

on:
workflow_dispatch:
inputs:
version:
description: Version of Cerebro to build
required: true
type: string

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
release:
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write

steps:
- name: Check out the repository
uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/[email protected]
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ inputs.version }}
type=raw,value=latest
type=sha
- name: Build and push Docker image
uses: docker/[email protected]
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: CEREBRO_VERSION=${{ inputs.version }}
39 changes: 0 additions & 39 deletions .github/workflows/scala.yml

This file was deleted.

36 changes: 36 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: tests

on:
push:
branches: [main]
pull_request:

jobs:
build_backend:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Run tests
run: sbt test

build_frontend:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# except for .gitignore
!.gitignore
!.eslintrc.json
!.dockerignore
!.github/

# Ignore Play! working directory #
db
Expand All @@ -23,3 +25,6 @@ server.pid
activator-*.sbt
node_modules
cerebro.db

# Ignore IDE
*.code-workspace
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Build web assets (frontend)
FROM node as builder-grunt

RUN mkdir /app
COPY . /app
WORKDIR /app

RUN npm install -g grunt
RUN npm install
RUN grunt build

# Build scala (backend)
FROM sbtscala/scala-sbt:eclipse-temurin-jammy-11.0.17_8_1.8.2_2.13.10 as builder-scala

ARG CEREBRO_VERSION

RUN mkdir /app /opt/cerebro
WORKDIR /app
COPY --from=builder-grunt /app /app
RUN sbt packageZipTarball
RUN tar --strip-components=1 -C /opt/cerebro -xf /app/target/universal/cerebro-${CEREBRO_VERSION}.tgz
RUN sed -i '/<appender-ref ref="FILE"\/>/d' /opt/cerebro/conf/logback.xml

# Package docker image
FROM eclipse-temurin:8-jre-jammy

COPY --from=builder-scala /opt/cerebro /opt/cerebro

RUN mkdir -p /opt/cerebro/logs \
&& addgroup -gid 1000 cerebro \
&& adduser -q --system --no-create-home --disabled-login -gid 1000 -uid 1000 cerebro \
&& chown -R root:root /opt/cerebro \
&& chown -R cerebro:cerebro /opt/cerebro/logs \
&& chown cerebro:cerebro /opt/cerebro

WORKDIR /opt/cerebro
USER cerebro

ENTRYPOINT [ "/opt/cerebro/bin/cerebro" ]
9 changes: 6 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = function(grunt) {
module.exports = function (grunt) {

var singleRunTests = grunt.option('singleRunTests') !== false;
grunt.initConfig({
Expand Down Expand Up @@ -75,10 +75,13 @@ module.exports = function(grunt) {
'src/app/shared/*.js',
'src/app/shared/*/*.js'
]
},
options: {
esnext: true
}
},
karma: {
unit: {configFile: 'tests/karma.config.js', singleRun: singleRunTests }
unit: { configFile: 'tests/karma.config.js', singleRun: singleRunTests }
},
eslint: {
options: {
Expand All @@ -103,6 +106,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-eslint');
grunt.registerTask('dev', ['watch']);
grunt.registerTask('build',
['clean', 'jshint', 'eslint', 'concat', 'copy', 'karma']);
['clean', 'jshint', 'eslint', 'concat', 'copy']);
grunt.registerTask('test', ['karma'])
};
2 changes: 1 addition & 1 deletion app/controllers/AuthController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class AuthController @Inject()(system: ActorSystem,
}
resp.withSession(AuthAction.SESSION_USER -> username)
case None =>
Redirect(routes.AuthController.index()).flashing(LOGIN_MSG -> "Incorrect username or password")
Redirect(routes.AuthController.index).flashing(LOGIN_MSG -> "Incorrect username or password")
}
}
)
Expand Down
23 changes: 23 additions & 0 deletions app/controllers/IndicesController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package controllers

import javax.inject.Inject

import controllers.auth.AuthenticationModule
import elastic.{ElasticClient, Error, Success}
import models.nodes.Nodes
import models.{CerebroResponse, Hosts}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class IndicesController @Inject()(val authentication: AuthenticationModule,
val hosts: Hosts,
client: ElasticClient) extends BaseController {
def index = process { request =>
client.getIndicesStats(request.target).map {
case Success(status, repositories) => CerebroResponse(status, repositories)
case Error(status, error) => CerebroResponse(status, error)
}
}

}
4 changes: 2 additions & 2 deletions app/controllers/auth/AuthAction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class AuthAction(auth: AuthenticationModule, redirect: Boolean, override v
}.getOrElse {
if (redirect) {
Future.successful(
Results.Redirect(routes.AuthController.index()).
Results.Redirect(routes.AuthController.index).
withSession(AuthAction.REDIRECT_URL -> request.uri))
} else {
Future.successful(CerebroResponse(303, JsNull))
Expand All @@ -38,4 +38,4 @@ object AuthAction {
private[controllers] val SESSION_USER = "username"
private[controllers] val REDIRECT_URL = "redirect"

}
}
2 changes: 1 addition & 1 deletion app/controllers/auth/basic/BasicAuthConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import play.api.Configuration

class BasicAuthConfig(config: Configuration) extends AuthConfig {

implicit val conf = config
implicit val conf: Configuration = config

final val username = getSetting("username")
final val password = getSetting("password")
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/auth/basic/BasicAuthService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import play.api.Configuration

class BasicAuthService @Inject()(globalConfig: Configuration) extends AuthService {

private implicit final val config = new BasicAuthConfig(globalConfig.get[Configuration]("auth.settings"))
private implicit final val config: BasicAuthConfig = new BasicAuthConfig(globalConfig.get[Configuration]("auth.settings"))

def auth(username: String, password: String): Option[String] = {
(username, password) match {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/auth/ldap/LDAPAuthConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import play.api.Configuration

class LDAPAuthConfig(config: Configuration) extends AuthConfig {

implicit val conf = config
implicit val conf: Configuration = config

final val userTemplate = getSetting("user-template")
final val method = getSetting("method")
Expand Down
1 change: 1 addition & 0 deletions app/elastic/ElasticClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,5 @@ trait ElasticClient {

def executeRequest(method: String, path: String, data: Option[JsValue], target: ElasticServer): Future[ElasticResponse]

def getIndicesStats(target: ElasticServer): Future[ElasticResponse]
}
5 changes: 5 additions & 0 deletions app/elastic/HTTPElasticClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ class HTTPElasticClient @Inject()(client: WSClient) extends ElasticClient {
val path = "/_cat/master"
execute(s"$path?format=json", "GET", None, target)
}

override def getIndicesStats(target: ElasticServer): Future[ElasticResponse] = {
val path = "/_stats/search,get,docs,store,indexing,query_cache"
execute(s"$path", "GET", None, target)
}
}

object HTTPElasticClient {
Expand Down
10 changes: 9 additions & 1 deletion app/models/CerebroRequest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,19 @@ object CerebroRequest {
case _ => None
}

// Add default headers if host is set with wildcard. Add default authorization(same with kibana)
val defaultHeadersWhitelist: Seq[String] = hosts.getHost("*") match {
case Some(Host(_, _, headers)) => headers
case _ => Seq("Authorization")
}

val server = hosts.getHost(hostName) match {
case Some(host @ Host(h, a, headersWhitelist)) =>
val headers = headersWhitelist.flatMap(headerName => request.headers.get(headerName).map(headerName -> _))
ElasticServer(host.copy(authentication = a.orElse(requestAuth)), headers)
case None => ElasticServer(Host(hostName, requestAuth))
case None =>
val headers = defaultHeadersWhitelist.flatMap(headerName => request.headers.get(headerName).map(headerName -> _))
ElasticServer(Host(hostName, requestAuth), headers)
}

CerebroRequest(server, body, request.user)
Expand Down
2 changes: 1 addition & 1 deletion app/models/Hosts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class HostsImpl @Inject()(config: Configuration) extends Hosts {
case Failure(_) => Map()
}

def getHostNames() = hosts.keys.toSeq
def getHostNames() = hosts.values.map(h => h.name).toSeq

def getHost(name: String) = hosts.get(name)

Expand Down
3 changes: 2 additions & 1 deletion app/models/commons/NodeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ trait NodeInfo {
"ml.machine_memory",
"xpack.installed",
"transform.node",
"ml.max_open_jobs"
"ml.max_open_jobs",
"ml.max_jvm_size"
)

def attrs(info: JsValue) = {
Expand Down
2 changes: 1 addition & 1 deletion app/models/commons/NodeRoles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ object NodeRoles {

def apply(nodeInfo: JsValue): NodeRoles = {
// >= 7.10
val dataRoles = Seq("data", "data_content", "data_hot", "data_warm", "data_cold").map(JsString)
val dataRoles = Seq("data", "data_content", "data_hot", "data_warm", "data_cold", "data_frozen").map(JsString)

(nodeInfo \ "roles").asOpt[JsArray] match {
case Some(JsArray(roles)) => // >= 5.X
Expand Down
6 changes: 5 additions & 1 deletion app/models/nodes/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ object Node extends NodeInfo {
"master" -> JsBoolean(roles.master),
"coordinating" -> JsBoolean(roles.coordinating),
"ingest" -> JsBoolean(roles.ingest),
"data" -> JsBoolean(roles.data)
"data" -> JsBoolean(roles.data),
"roles" -> JsArray(info \ "roles" match {
case JsDefined(JsArray(roles)) => roles
case _ => Seq.empty
})
)
}

Expand Down
9 changes: 6 additions & 3 deletions app/models/overview/ClosedIndex.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package models.overview

import play.api.libs.json.{JsBoolean, JsString, Json}
import play.api.libs.json.{JsBoolean, JsNumber, JsString, JsValue, Json}

object ClosedIndex {

def apply(name: String) =
def apply(name: String, aliases: JsValue, numShards: JsNumber, numReplicas: JsNumber) =
Json.obj(
"name" -> JsString(name),
"closed" -> JsBoolean(true),
"special" -> JsBoolean(name.startsWith("."))
"special" -> JsBoolean(name.startsWith(".")),
"aliases" -> aliases,
"num_shards" -> numShards,
"num_replicas" -> numReplicas
)

}
Loading

0 comments on commit b77e870

Please sign in to comment.