diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 0000000..d6e04dd --- /dev/null +++ b/.checkstyle @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f5659b --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +out +.idea + +# compiled output +/dist +/dist-server +/tmp +/out-tsc + +/front/dist + +config.env + +*.class + +dataPush +node_modules + +# dependencies +applicationFront/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db + +backPY/env + +*.pyc + +__pycache__ + +.design/ +.vscode/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5f3781a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,79 @@ +###################################################################################### +## +## buyilding-end install applications: +## +###################################################################################### +FROM archlinux:base-devel AS builder +# update system +RUN pacman -Syu --noconfirm && pacman-db-upgrade \ + && pacman -S --noconfirm jdk-openjdk maven npm \ + && pacman -Scc --noconfirm + +ENV PATH /tmp/node_modules/.bin:$PATH +WORKDIR /tmp + +###################################################################################### +## +## Build back: +## +###################################################################################### +FROM builder AS buildBack +COPY back/pom.xml /tmp +COPY back/src /tmp/src/ +RUN mvn clean compile assembly:single + +###################################################################################### +## +## Build front: +## +###################################################################################### +FROM builder AS buildFront + +ADD front/package-lock.json \ + front/package.json \ + front/karma.conf.js \ + front/protractor.conf.js \ + /tmp/ + +# install and cache app dependencies +RUN npm install + +ADD front/e2e \ + front/tsconfig.json \ + front/tslint.json \ + front/angular.json \ + /tmp/ +ADD front/src /tmp/src + +# generate build +RUN ng build --output-path=dist --configuration=production --base-href=/karusic/ --deploy-url=/karusic/ + +###################################################################################### +## +## Production area: +## +###################################################################################### + +FROM bellsoft/liberica-openjdk-alpine:latest +# add wget to manage the health check... +RUN apk add --no-cache wget + +#FROM archlinux:base +#RUN pacman -Syu --noconfirm && pacman-db-upgrade +## install package +#RUN pacman -S --noconfirm jdk-openjdk wget +## intall npm +#RUN pacman -S --noconfirm npm +## clean all the caches Need only on the release environment +#RUN pacman -Scc --noconfirm + +ENV LANG=C.UTF-8 + +COPY --from=buildBack /tmp/out/maven/*.jar /application/application.jar +COPY --from=buildFront /tmp/dist /application/front/ + +WORKDIR /application/ + +EXPOSE 80 + +CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"] diff --git a/back/CheckStyle.xml b/back/CheckStyle.xml new file mode 100755 index 0000000..d68aedd --- /dev/null +++ b/back/CheckStyle.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back/CleanUp.xml b/back/CleanUp.xml new file mode 100644 index 0000000..9df98d2 --- /dev/null +++ b/back/CleanUp.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back/Dockerfile b/back/Dockerfile new file mode 100644 index 0000000..8fc1c69 --- /dev/null +++ b/back/Dockerfile @@ -0,0 +1,21 @@ +FROM maven:3.6.3-openjdk-16 AS build + +COPY pom.xml /tmp/ +COPY src /tmp/src/ +WORKDIR /tmp/ +RUN mvn clean compile assembly:single + + + +FROM bellsoft/liberica-openjdk-alpine:latest +ENV LANG=C.UTF-8 + + +RUN mkdir /application/ +COPY --from=build /tmp/out/maven/*.jar /application/application.jar +WORKDIR /application/ + +EXPOSE 18080 + +CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"] + diff --git a/back/Formatter.xml b/back/Formatter.xml new file mode 100644 index 0000000..b775e22 --- /dev/null +++ b/back/Formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back/LICENSE b/back/LICENSE new file mode 100644 index 0000000..a9d1e81 --- /dev/null +++ b/back/LICENSE @@ -0,0 +1,6 @@ +PROPIETARY licence +================== + +Copyright at Edouard DUPIN + +you have no right \ No newline at end of file diff --git a/back/README.md b/back/README.md new file mode 100644 index 0000000..db094e1 --- /dev/null +++ b/back/README.md @@ -0,0 +1,18 @@ +Generic backend for karanage in java +=================================== + +Kar manage is a tool to keep result of system inpection like docker, ros diagnostics, system status ... + + + +mvn install + +// create a single package jar +mvn clean compile assembly:single + + + +java -cp out/maven/karanage-0.1.0-jar-with-dependencies.jar org.kar.karideo.WebLauncher + + + diff --git a/back/db.sql b/back/db.sql new file mode 100644 index 0000000..fd40910 --- /dev/null +++ b/back/db.sql @@ -0,0 +1,4 @@ + + + + diff --git a/back/pom.xml b/back/pom.xml new file mode 100644 index 0000000..0e5b697 --- /dev/null +++ b/back/pom.xml @@ -0,0 +1,174 @@ + + 4.0.0 + org.kar + karanage + 0.1.0 + + + 3.1 + 17 + 17 + + 3.1.1 + + + + gitea + https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven + + + + + + kangaroo-and-rabbit + archidata + 0.1.3 + + + + + src + test/src + ${project.basedir}/out/maven/ + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + org.codehaus.mojo + exec-maven-plugin + 1.4.0 + + io.scenarium.oauth.WebLauncher + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + private + true + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + public + + + + + + \ No newline at end of file diff --git a/back/src/org/kar/karanage/WebLauncher.java b/back/src/org/kar/karanage/WebLauncher.java new file mode 100755 index 0000000..c73e4f3 --- /dev/null +++ b/back/src/org/kar/karanage/WebLauncher.java @@ -0,0 +1,118 @@ +package org.kar.karanage; + +import java.net.URI; + +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.kar.karanage.api.Front; +import org.kar.karanage.api.HealthCheck; +import org.kar.karanage.api.StateResource; +import org.kar.karanage.api.UserResource; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.SqlWrapper; +import org.kar.archidata.UpdateJwtPublicKey; +import org.kar.archidata.filter.AuthenticationFilter; +import org.kar.archidata.filter.CORSFilter; +import org.kar.archidata.filter.OptionFilter; +import org.kar.archidata.util.ConfigBaseVariable; +import org.kar.karanage.model.DataHistory; +import org.kar.karanage.model.DataInstant; +import org.kar.karanage.model.Group; + +public class WebLauncher { + private WebLauncher() { + } + + private static URI getBaseURI() { + return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build(); + } + + public static void main(String[] args) { + ConfigBaseVariable.bdDatabase = "karanage"; + + // generate the BDD: + try { + String out = ""; + out += SqlWrapper.createTable(DataInstant.class); + out += SqlWrapper.createTable(DataHistory.class); + out += SqlWrapper.createTable(Group.class); + System.out.println(out); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // =================================================================== + // Configure resources + // =================================================================== + ResourceConfig rc = new ResourceConfig(); + + // add multipart models .. + rc.register(new MultiPartFeature()); + // global authentication system + rc.register(new OptionFilter()); + // remove cors ==> all time called by an other system... + rc.register(new CORSFilter()); + // global authentication system + rc.registerClasses(AuthenticationFilter.class); + // add default resource: + rc.registerClasses(UserResource.class); + rc.registerClasses(StateResource.class); + + rc.registerClasses(HealthCheck.class); + rc.registerClasses(Front.class); + + // add jackson to be discovenr when we are ins standalone server + rc.register(JacksonFeature.class); + // enable this to show low level request + //rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName()); + + //System.out.println("Connect on the BDD:"); + //System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'"); + //System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'"); + //System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'"); + //System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'"); + //System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'"); + System.out.println(" ==> " + GlobalConfiguration.dbConfig); + System.out.println("OAuth service " + getBaseURI()); + HttpServer server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc); + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + System.out.println("Stopping server.."); + server.shutdownNow(); + } + }, "shutdownHook")); + + // =================================================================== + // start periodic update of the token ... + // =================================================================== + UpdateJwtPublicKey keyUpdater = new UpdateJwtPublicKey(); + keyUpdater.start(); + + // =================================================================== + // run JERSEY + // =================================================================== + try { + server.start(); + System.out.println("Jersey app started at " + getBaseURI()); + System.out.println("Press CTRL^C to exit.."); + Thread.currentThread().join(); + } catch (Exception e) { + System.out.println("There was an error while starting Grizzly HTTP server."); + e.printStackTrace(); + } + keyUpdater.kill(); + try { + keyUpdater.join(4000, 0); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/back/src/org/kar/karanage/WebLauncherLocal.java b/back/src/org/kar/karanage/WebLauncherLocal.java new file mode 100755 index 0000000..659f9ad --- /dev/null +++ b/back/src/org/kar/karanage/WebLauncherLocal.java @@ -0,0 +1,16 @@ +package org.kar.karanage; + +import org.kar.archidata.util.ConfigBaseVariable; + +public class WebLauncherLocal { + private WebLauncherLocal() {} + + public static void main(String[] args) throws InterruptedException { + if (true) { + // for local test: + ConfigBaseVariable.apiAdress = "http://0.0.0.0:20080/karanage/api/"; + ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/"; + } + WebLauncher.main(args); + } +} diff --git a/back/src/org/kar/karanage/api/Front.java b/back/src/org/kar/karanage/api/Front.java new file mode 100644 index 0000000..b7018cd --- /dev/null +++ b/back/src/org/kar/karanage/api/Front.java @@ -0,0 +1,22 @@ +package org.kar.karanage.api; + +import java.io.File; +import java.util.List; + +import org.kar.archidata.annotation.security.PermitAll; +import javax.ws.rs.*; +import javax.ws.rs.core.CacheControl; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + +import org.kar.archidata.api.FrontGeneric; +import org.kar.karanage.util.ConfigVariable; + +@Path("/karanage") +public class Front extends FrontGeneric { + public Front() { + this.baseFrontFolder = ConfigVariable.getFrontFolder(); + + } +} diff --git a/back/src/org/kar/karanage/api/HealthCheck.java b/back/src/org/kar/karanage/api/HealthCheck.java new file mode 100644 index 0000000..c71a77d --- /dev/null +++ b/back/src/org/kar/karanage/api/HealthCheck.java @@ -0,0 +1,28 @@ +package org.kar.karanage.api; + +import org.kar.archidata.annotation.security.PermitAll; +import javax.ws.rs.core.Response; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +import org.kar.archidata.util.JWTWrapper; + +@Path("/health_check") +@Produces(MediaType.APPLICATION_JSON) +public class HealthCheck { + public class HealthResult { + public String value; + public HealthResult(String value) { + this.value = value; + } + } + // todo : do it better... + @GET + @PermitAll + public Response getHealth() { + if (JWTWrapper.getPublicKey() == null) { + return Response.status(500).entity(new HealthResult("Missing Jwt public token")).build(); + } + return Response.status(200).entity(new HealthResult("alive and kicking")).build(); + } +} diff --git a/back/src/org/kar/karanage/api/StateResource.java b/back/src/org/kar/karanage/api/StateResource.java new file mode 100644 index 0000000..a19e36f --- /dev/null +++ b/back/src/org/kar/karanage/api/StateResource.java @@ -0,0 +1,111 @@ +package org.kar.karanage.api; + +import org.kar.archidata.SqlWrapper; +import org.kar.karanage.model.DataInstant; +import org.kar.karanage.model.DataHistory; +import org.kar.karanage.model.Group; +import javax.ws.rs.core.Response; + + +import org.kar.archidata.annotation.security.PermitAll; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +import java.sql.Timestamp; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; + + +@Path("/state") +@Produces({MediaType.APPLICATION_JSON}) +public class StateResource { + + @GET + @Path("{group}/{topic:.*}") + //@RolesAllowed("USER") + @PermitAll + public static DataInstant getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception { + Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName); + if (group == null) { + throw new Exception("Missing Group !!!"); + } + return SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic); + } + + @GET + @Path("{group}") + //@RolesAllowed("USER") + @PermitAll + public List get(@PathParam("group") String groupName) throws Exception { + Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName); + if (group == null) { + throw new Exception("Missing Group !!!"); + } + return SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id); + } + + @POST + @Path("{group}/{topic:.*}") + //@RolesAllowed("ADMIN") + @PermitAll + @Consumes(MediaType.APPLICATION_JSON) + public Response post(@PathParam("group") String groupName, @PathParam("topic") String topic, String dataToInsert) throws Exception { + DataInstant previous = null; + Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName); + if (group != null) { + previous = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true); + } + if (previous == null) { + // insert new data + DataInstant data = new DataInstant(); + data.group = group.id; + data.topic = topic; + data.data = dataToInsert; + previous = SqlWrapper.insert(data); + DataHistory dataHistory = new DataHistory(previous); + dataHistory.year = true; + dataHistory.month = true; + dataHistory.week = true; + dataHistory.day = true; + SqlWrapper.insert(dataHistory); + return Response.status(201).build(); + } + // update Data + try { + previous.data = dataToInsert; + SqlWrapper.update(previous, previous.id, List.of("data")); + // add it in history: + DataHistory dataHistory = new DataHistory(previous); + OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ); + OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC); + //tstamp = Timestamp.valueOf(ofsdatetime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()) + + now.getDayOfMonth(); + if (sqlTime.getYear() != now.getYear()) { + dataHistory.year = true; + } + if (sqlTime.getMonth() != now.getMonth()) { + dataHistory.month = true; + } + if (!sqlTime.getDayOfWeek().equals(now.getDayOfWeek())) { + dataHistory.week = true; + } + if (sqlTime.getDayOfYear() != now.getDayOfYear()) { + dataHistory.day = true; + } + if (sqlTime.getHour() != now.getHour()) { + dataHistory.hour = true; + } + dataHistory.modify_date = Timestamp.valueOf(now.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()); + + SqlWrapper.insert(dataHistory); + } catch (Exception ex) { + System.out.print("get exception: " + ex); + } + return Response.status(204).build(); + } + +} + diff --git a/back/src/org/kar/karanage/api/UserResource.java b/back/src/org/kar/karanage/api/UserResource.java new file mode 100755 index 0000000..94f7cff --- /dev/null +++ b/back/src/org/kar/karanage/api/UserResource.java @@ -0,0 +1,101 @@ +package org.kar.karanage.api; + +import org.kar.archidata.SqlWrapper; +import org.kar.archidata.filter.GenericContext; +import org.kar.archidata.model.User; +import org.kar.karanage.model.UserKaranage; + +import org.kar.archidata.annotation.security.RolesAllowed; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.SecurityContext; +import java.util.List; + + +@Path("/users") +@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) +public class UserResource { + + public UserResource() { + } + + // curl http://localhost:9993/api/users + @GET + @RolesAllowed("ADMIN") + public List getUsers() { + System.out.println("getUsers"); + try { + return SqlWrapper.gets(UserKaranage.class, false); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + // curl http://localhost:9993/api/users/3 + @GET + @Path("{id}") + @RolesAllowed("ADMIN") + public UserKaranage getUsers(@Context SecurityContext sc, @PathParam("id") long userId) { + System.out.println("getUser " + userId); + GenericContext gc = (GenericContext) sc.getUserPrincipal(); + System.out.println("==================================================="); + System.out.println("== USER ? " + gc.user); + System.out.println("==================================================="); + try { + return SqlWrapper.get(UserKaranage.class, userId); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + // curl http://localhost:9993/api/users/3 + @GET + @Path("me") + @RolesAllowed("USER") + public User getMe(@Context SecurityContext sc) { + System.out.println("getMe()"); + GenericContext gc = (GenericContext) sc.getUserPrincipal(); + System.out.println("==================================================="); + System.out.println("== USER ? " + gc.user); + System.out.println("==================================================="); + return gc.user; + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/back/src/org/kar/karanage/internal/Log.java b/back/src/org/kar/karanage/internal/Log.java new file mode 100644 index 0000000..a70acb7 --- /dev/null +++ b/back/src/org/kar/karanage/internal/Log.java @@ -0,0 +1,60 @@ +package org.kar.karanage.internal; + +//import io.scenarium.logger.LogLevel; +//import io.scenarium.logger.Logger; + +public class Log { +// private static final String LIB_NAME = "logger"; +// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); +// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); +// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); +// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); +// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); +// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); +// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); +// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); +// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); +// +// private Log() {} +// +// public static void print(String data) { +// if (PRINT_PRINT) +// Logger.print(LIB_NAME_DRAW, data); +// } +// +// public static void todo(String data) { +// if (PRINT_TODO) +// Logger.todo(LIB_NAME_DRAW, data); +// } +// +// public static void critical(String data) { +// if (PRINT_CRITICAL) +// Logger.critical(LIB_NAME_DRAW, data); +// } +// +// public static void error(String data) { +// if (PRINT_ERROR) +// Logger.error(LIB_NAME_DRAW, data); +// } +// +// public static void warning(String data) { +// if (PRINT_WARNING) +// Logger.warning(LIB_NAME_DRAW, data); +// } +// +// public static void info(String data) { +// if (PRINT_INFO) +// Logger.info(LIB_NAME_DRAW, data); +// } +// +// public static void debug(String data) { +// if (PRINT_DEBUG) +// Logger.debug(LIB_NAME_DRAW, data); +// } +// +// public static void verbose(String data) { +// if (PRINT_VERBOSE) +// Logger.verbose(LIB_NAME_DRAW, data); +// } + +} diff --git a/back/src/org/kar/karanage/model/ApplicationToken.java b/back/src/org/kar/karanage/model/ApplicationToken.java new file mode 100644 index 0000000..1cbf82d --- /dev/null +++ b/back/src/org/kar/karanage/model/ApplicationToken.java @@ -0,0 +1,37 @@ +package org.kar.karanage.model; +/* +CREATE TABLE `node` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `deleted` BOOLEAN NOT NULL DEFAULT false, + `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created', + `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update', + `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE', + `name` TEXT COLLATE 'utf8_general_ci' NOT NULL, + `description` TEXT COLLATE 'utf8_general_ci', + `parent_id` bigint +) AUTO_INCREMENT=10; +*/ + +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLForeignKey; +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLLimitSize; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.model.GenericTable; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@SQLTableName ("applicationToken") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class ApplicationToken extends GenericTable { + @SQLComment("Group of the element") + @SQLForeignKey("group") + public long group; + @SQLLimitSize(256) + @SQLComment("Token Of the application (must be use by only one application)") + public String token = null; + @SQLComment("Description of the Group") + @SQLLimitSize(1024) + public String description; +} \ No newline at end of file diff --git a/back/src/org/kar/karanage/model/DataHistory.java b/back/src/org/kar/karanage/model/DataHistory.java new file mode 100644 index 0000000..64a364c --- /dev/null +++ b/back/src/org/kar/karanage/model/DataHistory.java @@ -0,0 +1,74 @@ +package org.kar.karanage.model; +/* +CREATE TABLE `node` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `deleted` BOOLEAN NOT NULL DEFAULT false, + `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created', + `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update', + `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE', + `name` TEXT COLLATE 'utf8_general_ci' NOT NULL, + `description` TEXT COLLATE 'utf8_general_ci', + `parent_id` bigint +) AUTO_INCREMENT=10; +*/ + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLDefault; +import org.kar.archidata.annotation.SQLForeignKey; +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLLimitSize; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.annotation.SQLUpdateTime; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + + +enum State { + OK, FAIL, UNSTABLE, RETREIVING, HAPPY, FULL, EMPTY +} +enum TypeData { + NUMBER, BOOLEAN, JSON, STRING +} + +@SQLTableName ("dataHistory") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class DataHistory extends DataInstant { + // default constructor + public DataHistory() { + + } + public DataHistory(DataInstant other) { + this.group = other.group; + this.topic = other.topic; + this.state = other.state; + this.data = other.data; + } + + @SQLComment("First message of the years (in GMT time)") + @SQLNotNull + @SQLDefault("0") + public boolean year = false; + @SQLComment("First message of the month (in GMT time)") + @SQLNotNull + @SQLDefault("0") + public boolean month = false; + @SQLComment("First message of the week: monday (in GMT time)") + @SQLNotNull + @SQLDefault("0") + public boolean week = false; + @SQLComment("First message of the day (in GMT time)") + @SQLNotNull + @SQLDefault("0") + public boolean day = false; + @SQLComment("First message of the hour (in GMT time)") + @SQLNotNull + @SQLDefault("0") + public boolean hour = false; +} \ No newline at end of file diff --git a/back/src/org/kar/karanage/model/DataInstant.java b/back/src/org/kar/karanage/model/DataInstant.java new file mode 100644 index 0000000..98cbb2b --- /dev/null +++ b/back/src/org/kar/karanage/model/DataInstant.java @@ -0,0 +1,59 @@ +package org.kar.karanage.model; +/* +CREATE TABLE `node` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `deleted` BOOLEAN NOT NULL DEFAULT false, + `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created', + `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update', + `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE', + `name` TEXT COLLATE 'utf8_general_ci' NOT NULL, + `description` TEXT COLLATE 'utf8_general_ci', + `parent_id` bigint +) AUTO_INCREMENT=10; +*/ + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLForeignKey; +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLLimitSize; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.annotation.SQLUpdateTime; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@SQLTableName ("data") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class DataInstant { + @SQLAutoIncrement // Add AUTO_INCREMENT modifier + @SQLPrimaryKey // Create a PRIMARY KEY based on this field + @SQLNotNull + @SQLComment("Primary key of the base") + public Long id = null; + + // TODO: werll managed of the not read and not set update time at @now() si c'est pas bon .. + + //@SQLNotRead + @SQLUpdateTime + @SQLNotNull + @SQLComment("When update the object") + public Timestamp modify_date = null; + @SQLComment("Group of the element") + @SQLForeignKey("group") + public long group; + @SQLLimitSize(256) + @SQLComment("Topic of the message") + public String topic = null; + @SQLComment("State of the message") + @SQLLimitSize(25) + //public State state = null; + public String state = null; + @SQLComment("Message to store") + public String data = null; +} \ No newline at end of file diff --git a/back/src/org/kar/karanage/model/Group.java b/back/src/org/kar/karanage/model/Group.java new file mode 100644 index 0000000..43a8eb0 --- /dev/null +++ b/back/src/org/kar/karanage/model/Group.java @@ -0,0 +1,24 @@ +package org.kar.karanage.model; + +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLLimitSize; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.model.GenericTable; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + + +@SQLTableName ("group") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class Group extends GenericTable { + @SQLNotNull + @SQLLimitSize(256) + @SQLComment("Name of the group.") + public String name; + @SQLComment("Description of the Group") + @SQLLimitSize(1024) + public String description; +} diff --git a/back/src/org/kar/karanage/model/UserKaranage.java b/back/src/org/kar/karanage/model/UserKaranage.java new file mode 100644 index 0000000..9db6992 --- /dev/null +++ b/back/src/org/kar/karanage/model/UserKaranage.java @@ -0,0 +1,14 @@ +package org.kar.karanage.model; + +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.model.User; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@SQLTableName ("user") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class UserKaranage extends User { + +} diff --git a/back/src/org/kar/karanage/util/ConfigVariable.java b/back/src/org/kar/karanage/util/ConfigVariable.java new file mode 100644 index 0000000..fd2ea5e --- /dev/null +++ b/back/src/org/kar/karanage/util/ConfigVariable.java @@ -0,0 +1,15 @@ +package org.kar.karanage.util; + +public class ConfigVariable { + public static final String BASE_NAME = "ORG_KARUSIC_"; + + + public static String getFrontFolder() { + String out = System.getenv(BASE_NAME + "FRONT_FOLDER"); + if (out == null) { + return "/application/front"; + } + return out; + } + +} diff --git a/device_script/.karanage.json b/device_script/.karanage.json new file mode 100644 index 0000000..ae1a206 --- /dev/null +++ b/device_script/.karanage.json @@ -0,0 +1,18 @@ +{ + "cpu": "auto", + "memory": "auto", + "swap": "auto", + "drive": { + "include": [ + "/", + "/home", + "/home/heero/HDD1", + "/home/heero/HDD2" + ] + }, + "network": { + "include": [ + "enp34s0" + ] + } +} diff --git a/device_script/inspect.py b/device_script/inspect.py new file mode 100755 index 0000000..5735919 --- /dev/null +++ b/device_script/inspect.py @@ -0,0 +1,177 @@ +#!/bin/python3 +# Importing the library +import psutil +import argparse +import time +import subprocess +import json +from pathlib import Path +from typing import Dict, List +import requests + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--config", type=str, default=".karanage.json", help="json configuration file") +parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api/state", help="Base URL of the web service") +parser.add_argument("-g", "--group", type=str, default="home", help="Group the the message") +parser.add_argument("-t", "--topic", type=str, default="PC/system", help="Topic of the message") +parser.add_argument("-s", "--sleep", type=int, default=10, help="Periodicity of the messages") +args = parser.parse_args() + +if Path(args.config).exists(): + f = open(args.config, "r") + configuration = json.loads(f.read()) + f.close() +else: + configuration = { + "cpu": "auto", + "memory": "auto", + "swap": "auto", + "drive": "auto", + "network": "auto", + } + + +def send_to_server(data: Dict) -> None: + ret = requests.post(f"{args.url}/{args.group}/{args.topic}", json=out) + if 200 <= ret.status_code <= 299: + pass # print(f" ==> done {ret}") + else: + print(f" ==> An error occured in sending message to the server !! {ret}") + + +cpu_core_count = psutil.cpu_count(logical=False) +cpu_thread_count = psutil.cpu_count() + + +def get_mounts() -> Dict: + process = subprocess.Popen( + ["mount", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + stdout, stderr = process.communicate() + """get data format: + $ mount -v + proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) + sys on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) + dev on /dev type devtmpfs (rw,nosuid,relatime,size=7049156k,nr_inodes=1762289,mode=755,inode64) + run on /run type tmpfs (rw,nosuid,nodev,relatime,mode=755,inode64) + efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime) + /dev/nvme0n1p5 on / type ext4 (rw,relatime,stripe=32) + """ + out = {} + lines = stdout.decode("utf-8").split("\n") + for line in lines: + tmp = line.split(" ") + if len(tmp) <= 2: + continue + if tmp[0].startswith('/dev/'): + out[tmp[2]] = tmp[0][5:] + return out + +mounting_points = get_mounts(); + +def filter(data: Dict, filter_list: List[str]) -> Dict: + out = {} + print(f"Request filter {data.keys()} with filter {filter_list}") + for key in data: + if key in filter_list: + out[key] = data[key] + return out + +def need_process(data: Dict) -> Dict: + return configuration["cpu"] == "auto" or "include" in configuration["cpu"] + + +def create_cpu_data() -> Dict: + # scpufreq(current=1605.5205625000003, min=400.0, max=4372.0) + cpu_frequency = psutil.cpu_freq(percpu=False) + cpu_percent_use = psutil.cpu_percent() + return { + "core": cpu_core_count, + "thread": cpu_thread_count, + "frequency": cpu_frequency.current, + "use": cpu_percent_use, + "max": cpu_frequency.max, + } + +def create_memory_data() -> Dict: + # svmem(total=14473519104, available=8289726464, percent=42.7, used=5380497408, free=3276263424, active=1775763456, inactive=8335540224, buffers=361771008, cached=5454987264, shared=243720192, slab=544526336) + mem = psutil.virtual_memory() + return { + "used": mem.used, + "total": mem.total, + } + +def create_swap_data() -> Dict: + # sswap(total=17179865088, used=262144, free=17179602944, percent=0.0, sin=0, sout=0) + swap = psutil.swap_memory() + return { + "used": swap.used, + "total": swap.total, + } +def create_drive_data() -> Dict: + tmp_elem = {} + # nvme0n1p1 => sdiskio(read_count=187, write_count=3, read_bytes=6002176, write_bytes=5120, read_time=36, write_time=7, read_merged_count=504, write_merged_count=0, busy_time=67) + drive_access = psutil.disk_io_counters(perdisk=True) + for elem in mounting_points: + # sdiskusage(total=255162540032, used=112077000704, free=130049380352, percent=46.3) + drive_usage = psutil.disk_usage(elem) + # print(f"plop {mounting_points[elem]} ==> {drive_access.keys()}") + if mounting_points[elem] in drive_access: + tmp_elem[elem] = { + "read_bytes": drive_access[mounting_points[elem]].read_bytes, + "write_bytes": drive_access[mounting_points[elem]].write_bytes, + "used": drive_usage.used, + "total": drive_usage.total, + } + else: + tmp_elem[elem] = { + "used": drive_usage.used, + "total": drive_usage.total, + } + return tmp_elem + +def create_network_data() -> Dict: + # eth0 => snetio(bytes_sent=0, bytes_recv=0, packets_sent=0, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0) + data = psutil.net_io_counters(pernic=True) + tmp_elem = {} + for elem in data: + tmp_elem[elem] = { + "bytes_sent": data[elem].bytes_sent, + "bytes_recv": data[elem].bytes_recv, + } + return tmp_elem + +def agglutinate(configuration, name, data): + if configuration[name] == "auto": + return data + elif "include" in configuration[name]: + return filter(data, configuration[name]["include"]) + return none + +while True: + out = {} + if need_process(configuration["cpu"]): + base_elem = create_cpu_data() + out["cpu"] = agglutinate(configuration, "cpu", base_elem) + + if need_process(configuration["memory"]): + base_elem = create_memory_data() + out["memory"] = agglutinate(configuration, "memory", base_elem) + + if need_process(configuration["swap"]): + base_elem = create_swap_data() + out["swap"] = agglutinate(configuration, "swap", base_elem) + + if need_process(configuration["drive"]): + base_elem = create_drive_data() + out["drive"] = agglutinate(configuration, "drive", base_elem) + + if configuration["network"] == "auto" or "include" in configuration["network"]: + base_elem = create_network_data() + out["network"] = agglutinate(configuration, "network", base_elem) + + #print("Read new value:") + print(json.dumps(out, indent=4)) + send_to_server(out) + time.sleep(args.sleep) + diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..d82f84d --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,46 @@ +version: '3' + +services: + karusic_db_service: + image: mysql:latest + restart: always + command: --default-authentication-plugin=mysql_native_password + env_file: + - ./config.env + volumes: + - /workspace/data/karusic/db:/var/lib/mysql + mem_limit: 600m + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] + timeout: 20s + retries: 10 + + karauth_adminer_service: + image: adminer:latest + restart: always + depends_on: + - karusic_db_service + ports: + - 19079:8080 + links: + - karusic_db_service:db + read_only: false + mem_limit: 100m + + karusic_back_service: + restart: always + image: gitea.atria-soft.org/kangaroo-and-rabbit/karusic:latest + depends_on: + - karusic_db_service + ports: + - 19080:18080 + env_file: + - ./config.env + links: + - karusic_db_service:db + read_only: true + mem_limit: 1200m + healthcheck: + test: ["CMD", "wget" ,"http://localhost:18080/karusic/api/health_check", "-O", "/dev/null"] + timeout: 20s + retries: 3