Skip to content

Commit

Permalink
Merge pull request #76 from tchiotludo/dev
Browse files Browse the repository at this point in the history
Release 0.8.0
  • Loading branch information
tchiotludo authored Jun 5, 2019
2 parents 266d120 + ef2f845 commit 013d1b4
Show file tree
Hide file tree
Showing 37 changed files with 550 additions and 135 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ file example can be found here :[application.example.yml](application.example.ym
### KafkaHQ configuration

#### Topic List
* `kafkahq.topic.page-size` number of topics per page (default : 25)
* `kafkahq.topic.default-view` is default list view (ALL, HIDE_INTERNAL, HIDE_INTERNAL_STREAM, HIDE_STREAM)
* `kafkahq.topic.internal-regexps` is list of regexp to be considered as internal (internal topic can't be deleted or updated)
* `kafkahq.topic.stream-regexps` is list of regexp to be considered as internal stream topic
Expand All @@ -124,6 +125,10 @@ file example can be found here :[application.example.yml](application.example.ym
* `kafkahq.topic-data.poll-timeout`: The time, in milliseconds, spent waiting in poll if data is not available in the
buffer (default: 1000).


#### Schema List
* `kafkahq.schema.page-size` number of schemas per page (default : 25)


### Security
* `kafkahq.security.default-roles`: Roles available for all the user even unlogged user, roles available are :
Expand Down Expand Up @@ -161,13 +166,17 @@ kafkahq:
- connect/read
```
#### Basic Auth
* `kafkahq.security.basic-auth`: List user & password with affected roles
* `actual-username`: login of the current user as a yaml key (may be anything email, login, ...)
* `password`: Password in sha256, can be converted with command `echo -n "password" | sha256sum`
* `roles`: Role for current users

> Take care that basic auth will use session store in server **memory**. If your instance is behind a reverse proxy or a
> loadbalancer, you will need to forward the session cookie named `SESSION` and / or use
> [sesssion stickiness](https://en.wikipedia.org/wiki/Load_balancing_(computing)#Persistence)


### Server
* `kafkahq.server.base-path`: if behind a reverse proxy, path to kafkahq with trailing slash (optional). Example:
kafkahq is behind a reverse proxy with url <http://my-server/kafkahq>, set base-path: "/kafkahq/". Not needed if you're
Expand All @@ -188,6 +197,17 @@ KafkaHQ docker image support 3 environment variables to handle configuraiton :
* `MICRONAUT_APPLICATION_JSON`: a string that contains the full configuration in JSON format
* `MICRONAUT_CONFIG_FILES`: a path to to a configuration file on container. Default path is `/app/application.yml`

## Monitoring endpoint
Several monitoring endpoint is enabled by default. You can disabled it or restrict access only for authenticated users
following micronaut configuration below.

* `/info` [Info Endpoint](https://docs.micronaut.io/snapshot/guide/index.html#infoEndpoint) with git status
informations.
* `/health` [Health Endpoint](https://docs.micronaut.io/snapshot/guide/index.html#healthEndpoint)
* `/loggers` [Loggers Endpoint](https://docs.micronaut.io/snapshot/guide/index.html#loggersEndpoint)
* `/metrics` [Metrics Endpoint](https://docs.micronaut.io/snapshot/guide/index.html#metricsEndpoint)
* `/prometheus` [Prometheus Endpoint](https://micronaut-projects.github.io/micronaut-micrometer/latest/guide/)

## Development Environment
A docker-compose is provide to start a development environnement.
Just install docker & docker-compose, clone the repository and issue a simple `docker-compose -f docker-compose-dev.yml up` to start a dev server.
Expand Down
5 changes: 5 additions & 0 deletions application.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ kafkahq:

# Topic list display options (optional)
topic:
page-size: 25 # number of topics per page (default : 25)
default-view: HIDE_INTERNAL # default list view (ALL, HIDE_INTERNAL, HIDE_INTERNAL_STREAM, HIDE_STREAM)
internal-regexps: # list of regexp to be considered as internal (internal topic can't be deleted or updated)
- "^_.*$"
Expand All @@ -77,6 +78,10 @@ kafkahq:
size: 50 # max record per page (default: 50)
poll-timeout: 1000 # The time, in milliseconds, spent waiting in poll if data is not available in the buffer.

# Schama list display options (optional)
schema:
page-size: 25 # number of schemas per page (default : 25)

# Auth & Roles (optional)
security:
default-roles: # Roles available for all the user even unlogged user
Expand Down
2 changes: 1 addition & 1 deletion assets/modules/datas/filter.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@include media-breakpoint-up(sm) {
select {
max-width: 200px;
max-width: 170px;
}
}

Expand Down
2 changes: 1 addition & 1 deletion assets/modules/templates/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ h3.logo {
margin-left: $menu-width;
}

@include media-breakpoint-down(md) {
@include media-breakpoint-down(sm) {
width: 100%;
}

Expand Down
22 changes: 13 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
micronautVersion = "1.1.1"
micronautVersion = "1.1.3"
confluentVersion = "5.2.+"
kafkaVersion = "2.2.+"
}
Expand All @@ -13,7 +13,7 @@ buildscript {

dependencies {
// kafkahq
classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:0.16.0"
classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:0.17.0"
}
}

Expand All @@ -25,11 +25,12 @@ plugins {
id "java"
id "net.ltgt.apt-eclipse" version "0.21"
id "net.ltgt.apt-idea" version "0.21"
id "com.gorylenko.gradle-git-properties" version "2.0.0"

// kafkahq
id "com.moowork.node" version "1.3.1"
id 'io.franzbecker.gradle-lombok' version '3.0.0'
id 'com.adarshr.test-logger' version '1.6.0'
id 'io.franzbecker.gradle-lombok' version '3.1.0'
id 'com.adarshr.test-logger' version '1.7.0'
id 'com.github.psxpaul.execfork' version '0.1.10'
id "com.github.ben-manes.versions" version "0.21.0"
}
Expand Down Expand Up @@ -95,7 +96,7 @@ tasks.withType(JavaCompile){
}

gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(run)) {
if (graph.hasTask(run) || graph.hasTask(testClasses)) {
webpack.enabled = false
npmInstall.enabled = false
}
Expand All @@ -108,7 +109,7 @@ dependencies {
// micronaut
annotationProcessor "io.micronaut:micronaut-inject-java"
annotationProcessor "io.micronaut:micronaut-validation"
annotationProcessor "io.micronaut:micronaut-security:" + micronautVersion
annotationProcessor "io.micronaut:micronaut-security"
compile "io.micronaut:micronaut-inject"
compile "io.micronaut:micronaut-validation"
compile 'io.micronaut:micronaut-views'
Expand All @@ -117,14 +118,17 @@ dependencies {
compile "io.micronaut:micronaut-http-server-netty"
runtime "ch.qos.logback:logback-classic:1.2.3"
runtime 'org.freemarker:freemarker:2.3.28'
compile "io.micronaut:micronaut-security:" + micronautVersion
compile "io.micronaut:micronaut-security-session:" + micronautVersion
compile "io.micronaut:micronaut-security"
compile "io.micronaut:micronaut-security-session"
compile "io.micronaut:micronaut-management"
compile 'io.micronaut.configuration:micronaut-micrometer-registry-prometheus'
compile 'io.github.mweirauch:micrometer-jvm-extras:0.1.3'

// kafka
compile group: "org.apache.kafka", name: "kafka-clients", version: kafkaVersion
compile group: "io.confluent", name: "kafka-schema-registry-client", version: confluentVersion
compile group: "io.confluent", name: "kafka-avro-serializer", version: confluentVersion
compile group: 'org.apache.avro', name: 'avro', version: '1.8.2'
compile group: 'org.apache.avro', name: 'avro', version: '1.9.0'
compile group: 'org.sourcelab', name: 'kafka-connect-client', version: '2.0.+'

// log
Expand Down
3 changes: 0 additions & 3 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
version: '3.6'

volumes:
gradle-cache:
driver: local
zookeeper-data:
driver: local
zookeeper-log:
Expand All @@ -17,7 +15,6 @@ services:
working_dir: /app
volumes:
- ./:/app
- gradle-cache:/home/gradle/.gradle
ports:
- 127.11.8.17:8080:8080
depends_on:
Expand Down
2 changes: 1 addition & 1 deletion docker/app/kafkahq
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ do
JAVA_OPTS="${JAVA_OPTS} ${JVM_OPT}"
done

/usr/bin/java ${JAVA_OPTS} -jar /app/kafkahq.jar
/usr/local/openjdk-11/bin/java ${JAVA_OPTS} -jar /app/kafkahq.jar
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
27 changes: 14 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public HttpResponse slash() throws URISyntaxException {
return HttpResponse.redirect(this.uri("/" + kafkaModule.getClustersList().get(0) + "/topic"));
}

@Get("${kafkahq.server.base-path:}")
@Get("${kafkahq.server.base-path:}^")
public HttpResponse home() throws URISyntaxException {
return HttpResponse.redirect(this.uri("/" + kafkaModule.getClustersList().get(0) + "/topic"));
}
Expand Down
56 changes: 54 additions & 2 deletions src/main/java/org/kafkahq/controllers/SchemaController.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,93 @@
package org.kafkahq.controllers;

import com.google.common.collect.ImmutableMap;
import io.confluent.kafka.schemaregistry.client.rest.exceptions.RestClientException;
import io.micronaut.context.annotation.Value;
import io.micronaut.http.*;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import io.micronaut.security.annotation.Secured;
import io.micronaut.views.View;
import org.codehaus.httpcache4j.uri.URIBuilder;
import org.kafkahq.configs.Role;
import org.kafkahq.models.Schema;
import org.kafkahq.modules.RequestHelper;
import org.kafkahq.repositories.SchemaRegistryRepository;
import org.kafkahq.utils.CompletablePaged;

import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Secured(Role.ROLE_REGISTRY_READ)
@Controller("${kafkahq.server.base-path:}/{cluster}/schema")
public class SchemaController extends AbstractController {
private SchemaRegistryRepository schemaRepository;

@Value("${kafkahq.schema.page-size:25}")
private Integer pageSize;

@Inject
public SchemaController(SchemaRegistryRepository schemaRepository) {
this.schemaRepository = schemaRepository;
}

@View("schemaList")
@Get
public HttpResponse list(HttpRequest request, String cluster) throws IOException, RestClientException {
public HttpResponse list(
HttpRequest request,
String cluster,
Optional<String> search,
Optional<Integer> page
) throws IOException, RestClientException, ExecutionException, InterruptedException {
List<CompletableFuture<Schema>> list = this.schemaRepository.getAll(cluster, search);

URIBuilder uri = URIBuilder.fromURI(request.getUri());
CompletablePaged<Schema> paged = new CompletablePaged<>(
list,
this.pageSize,
uri,
page.orElse(1)
);

return this.template(
request,
cluster,
"schemas", this.schemaRepository.getAll(cluster)
"schemas", paged.complete(),
"search", search,
"pagination", ImmutableMap.builder()
.put("size", paged.size())
.put("before", paged.before().toNormalizedURI(false).toString())
.put("after", paged.after().toNormalizedURI(false).toString())
.build()
);
}

@Get("id/{id}")
public HttpResponse redirectId(HttpRequest request, String cluster, Integer id) throws IOException, RestClientException, URISyntaxException, ExecutionException, InterruptedException {
Schema find = this.schemaRepository.getById(cluster, id);

if (find != null) {
return HttpResponse.redirect(this.uri("/" + cluster + "/schema/" + find.getSubject() + "/version#" + id));
} else {
MutableHttpResponse<Void> response = HttpResponse.redirect(this.uri("/" + cluster + "/schema"));

this.toast(response, AbstractController.Toast.builder()
.message("Unable to find avro schema for id '" + id + "'")
.type(AbstractController.Toast.Type.error)
.build()
);

return response;
}
}

@Secured(Role.ROLE_REGISTRY_INSERT)
@View("schemaCreate")
@Get("create")
Expand Down
Loading

0 comments on commit 013d1b4

Please sign in to comment.