commit 6c46ab1f3d1d0c50ae6800ab19051ad91d21bd39 Author: Alberto Trevezani Date: Wed Nov 6 22:47:14 2019 -0300 RJ Tech Day diff --git a/README.md b/README.md new file mode 100755 index 0000000..227b2d7 --- /dev/null +++ b/README.md @@ -0,0 +1,312 @@ +# sample-bpe-microprofile +A sample of the BPe responsible for generating the key and the URL of the QRCode + + +## General + +Generating the executable jar file + +`mvn clean package` + +Running integration tests + +`mvn clean verify` + +Generating the image + +`mvn clean package docker:build` + +Remove the image + +`mvn docker:remove` + + +## Running the sample + +**bpe-api** + +`mvn thorntail:run -Dthorntail.jvmArguments=-Dbpechave.api.url=http://localhost:8280,-Dbpeqrcode.api.url=http://localhost:8180` + +Debugging + +`mvn thorntail:run -Dthorntail.debug.port=5006 -Dthorntail.jvmArguments=-Dbpechave.api.url=http://localhost:8280,-Dbpeqrcode.api.url=http://localhost:8180` + +**bpe-qrcode** + +`mvn thorntail:run -Dthorntail.jvmArguments=-Dbpechave.api.url=http://localhost:8280 -Dswarm.port.offset=100` + +**bpe-chave** + +`mvn thorntail:run -Dswarm.port.offset=200` + +or + +``` +mvn clean package -f bpe-api/pom.xml docker:build +mvn clean package -f bpe-qrcode/pom.xml docker:build +mvn clean package -f bpe-chave/pom.xml docker:build +``` + +Inside the extra/test + +``` +docker-compose up --build +``` + + +**Jaeger Traicing** + +[http://localhost:16686/](http://localhost:16686/) + +**Kibana** + +[http://localhost:5601/](http://localhost:5601/) + +**Testing the API** + +QRCode + +``` +curl -H "Content-Type: application/json" -X POST -d '{"ambiente": "2", "uf": "23", "emissao": "20190621","documento": "68830611000","modelo": "63","serie": "001","tipoEmissao": "1","numeroDocumentoFiscal": "13"}' http://localhost:8080/api/qrcode +``` + +Chave + +``` +curl -H "Content-Type: application/json" -X POST -d '{"uf": "23", "emissao": "20190621","documento": "68830611000","modelo": "63","serie": "001","tipoEmissao": "1","numeroDocumentoFiscal": "13"}' http://localhost:8080/api/chave +``` + + +## Kubernates + +**Docker Registry** + +`mkdir -p /opt/docker/auth` + +`docker run --rm --entrypoint htpasswd registry:2 -Bbn admin admin > /opt/docker/auth/htpasswd` + +`docker run -d -p 5000:5000 --restart=always --name registry -e REGISTRY_STORAGE_DELETE_ENABLED=true -v /opt/docker/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 registry:2` + +**Images** + +Generating the image and push them + +``` +mvn -Ddocker.registry=localhost:5000 -Ddocker.username=admin -Ddocker.password=admin clean package -f bpe-api/pom.xml docker:build docker:push -Pistio +mvn -Ddocker.registry=localhost:5000 -Ddocker.username=admin -Ddocker.password=admin clean package -f bpe-qrcode/pom.xml docker:build docker:push -Pistio +mvn -Ddocker.registry=localhost:5000 -Ddocker.username=admin -Ddocker.password=admin clean package -f bpe-chave/pom.xml docker:build docker:push -Pistio +``` + + +**Registry UI** + +Viewer for the images present in the Registry + +[https://github.com/jc21/docker-registry-ui](https://github.com/jc21/docker-registry-ui) + +``` +docker run --rm -it -p 5001:80 --name registry-ui -e REGISTRY_HOST=$(ipconfig getifaddr en0):5000 -e REGISTRY_STORAGE_DELETE_ENABLED=true -e REGISTRY_SSL=false -e REGISTRY_USER=admin -e REGISTRY_PASS=admin jc21/registry-ui +``` + +**Minikube/Istio** + +Starting the Minikube + +``` +minikube start --memory=8192 --cpus=4 --vm-driver=hyperkit --kubernetes-version=v1.14.0 --disk-size=30GB --insecure-registry='0.0.0.0/0' +minikube addons list +minikube addons enable heapster +minikube addons enable metrics-server +minikube addons enable ingress +``` + +Installing the Istio + +``` +# Istio 1.2.25 +curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.2.25 sh - +cd istio-1.2.25 +export PATH=$PWD/bin:$PATH + +# install +for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done +kubectl apply -f install/kubernetes/istio-demo.yaml + +# uninstall +kubectl delete -f install/kubernetes/istio-demo.yaml +for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl delete -f $i; done +``` + +Showing the pods + +``` +kubectl get pod -n istio-system +kubectl get svc -n istio-system +kubectl --namespace istio-system top pods --containers + +istioctl proxy-status +``` + +Showing the Istio Address + +``` +echo "Istio Services: $(minikube ip):$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')" +``` + +Showing the IP on MAC OS + +`echo "Local IP: $(ipconfig getifaddr en0)"` + + +**Deploying the Sample** + +Creating a namespace and defining the automatic inject for the Istio + +``` +kubectl create -f extra/kubernates/plataform/namespace-bpe.json + +kubectl label namespace bpe istio-injection=enabled --overwrite +``` + +Creating an environment variable for dynamic action inside the sample + +``` +kubectl create configmap bpe-config --from-literal='ambiente=2' -n bpe +kubectl edit configmap bpe-config -n bpe +kubectl patch deployment bpe-api-1.0.8 -p {\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"`date +'%s'`\"}}}}}" -n bpe +``` + +Defining the user and password to interact with the Registry + +``` +kubectl create secret docker-registry service-registry --namespace=bpe --docker-server=$(ipconfig getifaddr en0):5000 --docker-username=admin --docker-password=admin +``` + +Creating the Service, Deployment and Gateway + +``` +kubectl create -f extra/kubernates/plataform/bpeapi-service.yml +kubectl create -f extra/kubernates/plataform/bpeapi-deployment.yml + +kubectl create -f extra/kubernates/plataform/bpeqrcode-service.yml +kubectl create -f extra/kubernates/plataform/bpeqrcode-deployment.yml + +kubectl create -f extra/kubernates/plataform/bpechave-service.yml +kubectl create -f extra/kubernates/plataform/bpechave-deployment.yml + +kubectl create -f extra/kubernates/networking/bpeapi-gateway.yml +``` + +Testing the Gateway + +``` +curl $(minikube ip):$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')/api/versao +``` + +Showing the pods + +`kubectl get pods --namespace=bpe` + +Showing the details + +`kubectl describe pod bpe-api- --namespace=bpe` + +Testing the pod + +``` +kubectl exec -it $(kubectl get pod -l app=bpe-api -n bpe -o jsonpath='{.items[0].metadata.name}') -n bpe -c bpe-api -- curl bpe-api:8080/health +``` + + +**Istio Tools** + +Jaeger + +```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 15032:16686``` + +[http://localhost:15032](http://localhost:15032) + + +Kiali + +```kubectl port-forward $(kubectl get pod -n istio-system -l app=kiali -o jsonpath='{.items[0].metadata.name}') -n istio-system 20001``` + +[http://localhost:20001/](http://localhost:20001/) + +admin:admin + + +Grafana + +```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 3000``` + +[http://localhost:3000/dashboard/db/istio-mesh-dashboard](http://localhost:3000/dashboard/db/istio-mesh-dashboard) + + +Remove port forward + +```killall kubectl``` + + +**EFK (Monitoring)** + +Deploying the components + +``` +kubectl create namespace logging + +kubectl create -f extra/kubernetes/telemetry/elastic.yaml -n logging +kubectl create -f extra/kubernetes/telemetry/kibana.yaml -n logging +kubectl create -f extra/kubernetes/telemetry/fluentd-rbac.yaml +kubectl create -f extra/kubernetes/telemetry/fluentd-daemonset.yaml +``` + +Showing the pods + +``` +kubectl get pods,service -n logging +kubectl get pods -n kube-system +``` + +Viewing the log of the fluentd + +``` +kubectl logs $(kubectl get pods --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' -n kube-system | grep fluentd) -n kube-system +``` + +Showing the Minikube IP + +`echo "Minikube IP: $(minikube ip)"` + +Showing the Kibana Port + +`kubectl describe svc kibana -n logging | grep NodePort` + + +## Interacting with the API + +Showing the URL + +``` +echo "URL: $(minikube ip):$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')" +``` + +Retrieving a static URL + +``` +curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"ambiente": "2", "uf": "23", "emissao": "20190621","documento": "68830611000","modelo": "63","serie": "001","tipoEmissao": "1","numeroDocumentoFiscal": "13","cbp": "12345678"}' \ + http:///api/qrcode +``` + +Retrieving a dynamic URL + +``` +curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"ambiente": "2", "uf": "23", "emissao": "20190621","documento": "68830611000","modelo": "63","serie": "001","tipoEmissao": "1","numeroDocumentoFiscal": "13"}' \ + http:///api/qrcode +``` diff --git a/bpe-api/DockerfileIstio b/bpe-api/DockerfileIstio new file mode 100755 index 0000000..ce634de --- /dev/null +++ b/bpe-api/DockerfileIstio @@ -0,0 +1,13 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-api\ + JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ + JAEGER_PROPAGATION=b3\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-api/DockerfileNormal b/bpe-api/DockerfileNormal new file mode 100755 index 0000000..d6c00e3 --- /dev/null +++ b/bpe-api/DockerfileNormal @@ -0,0 +1,11 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-api\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD ./target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-api/pom.xml b/bpe-api/pom.xml new file mode 100755 index 0000000..87b8ff0 --- /dev/null +++ b/bpe-api/pom.xml @@ -0,0 +1,181 @@ + + + 4.0.0 + br.com.sample + bpe-api + BPe API + 1.0.11 + war + + + 2.4.0.Final + 1.8 + 1.8 + false + UTF-8 + + + + + + io.thorntail + bom-all + ${version.thorntail} + import + pom + + + io.thorntail + thorntail-runner + ${version.thorntail} + + + + + + bpe-api + + + io.thorntail + thorntail-maven-plugin + ${version.thorntail} + + + + package + + + + + + true + + + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 + + + + + maven-war-plugin + 3.2.3 + + + + true + true + + + + + + io.fabric8 + docker-maven-plugin + 0.31.0 + + + + ${project.build.finalName}:${project.version} + + ${project.basedir}/${dockerfile} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + true + + + + maven-failsafe-plugin + 2.22.0 + + + **/*Test + + + + + + integration-test + verify + + + + + + + + + + io.thorntail + microprofile-jwt + + + io.thorntail + microprofile + + + io.thorntail + microprofile-restclient + + + io.thorntail + microprofile-metrics + + + io.thorntail + microprofile-opentracing + + + io.thorntail + jaxrs + + + io.thorntail + jaeger + + + io.thorntail + microprofile-fault-tolerance + + + io.thorntail + microprofile-health + + + io.thorntail + microprofile-config + + + io.thorntail + fluentd + + + io.thorntail + arquillian + test + + + + + normal + + true + + + DockerfileNormal + + + + istio + + DockerfileIstio + + + + diff --git a/bpe-api/src/main/java/br/com/sample/bean/ChaveBean.java b/bpe-api/src/main/java/br/com/sample/bean/ChaveBean.java new file mode 100755 index 0000000..270a10a --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/bean/ChaveBean.java @@ -0,0 +1,107 @@ +package br.com.sample.bean; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class ChaveBean { + private String uf; + private String emissao; + private String documento; + private String modelo; + private String serie; + private String tipoEmissao; + private String numeroDocumentoFiscal; + private String cbp; + + public ChaveBean() { + + } + + public String getUf() { + return uf; + } + + public void setUf(String uf) { + this.uf = uf; + } + + public String getEmissao() { + return emissao; + } + + public void setEmissao(String emissao) { + this.emissao = emissao; + } + + public String getDocumento() { + return documento; + } + + public void setDocumento(String documento) { + this.documento = documento; + } + + public String getModelo() { + return modelo; + } + + public void setModelo(String modelo) { + this.modelo = modelo; + } + + public String getSerie() { + return serie; + } + + public void setSerie(String serie) { + this.serie = serie; + } + + public String getTipoEmissao() { + return tipoEmissao; + } + + public void setTipoEmissao(String tipoEmissao) { + this.tipoEmissao = tipoEmissao; + } + + public String getNumeroDocumentoFiscal() { + return numeroDocumentoFiscal; + } + + public void setNumeroDocumentoFiscal(String numeroDocumentoFiscal) { + this.numeroDocumentoFiscal = numeroDocumentoFiscal; + } + + public String getCbp() { + return cbp; + } + + public void setCbp(String cbp) { + this.cbp = cbp; + } + + @JsonIgnore + public boolean isValid() { + return (uf != null + && emissao != null + && documento != null + && modelo != null + && serie != null + && tipoEmissao != null + && numeroDocumentoFiscal != null); + } + + @Override + public String toString() { + return "ChaveBean{" + + "uf='" + uf + '\'' + + ", emissao='" + emissao + '\'' + + ", documento='" + documento + '\'' + + ", modelo='" + modelo + '\'' + + ", serie='" + serie + '\'' + + ", tipoEmissao='" + tipoEmissao + '\'' + + ", numeroDocumentoFiscal='" + numeroDocumentoFiscal + '\'' + + ", cbp='" + cbp + '\'' + + '}'; + } +} diff --git a/bpe-api/src/main/java/br/com/sample/bean/QRCodeBean.java b/bpe-api/src/main/java/br/com/sample/bean/QRCodeBean.java new file mode 100755 index 0000000..6536bd7 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/bean/QRCodeBean.java @@ -0,0 +1,118 @@ +package br.com.sample.bean; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class QRCodeBean { + private String ambiente; + private String uf; + private String emissao; + private String documento; + private String modelo; + private String serie; + private String tipoEmissao; + private String numeroDocumentoFiscal; + private String cbp; + + public QRCodeBean() { + + } + + public String getAmbiente() { + return ambiente; + } + + public void setAmbiente(String ambiente) { + this.ambiente = ambiente; + } + + public String getUf() { + return uf; + } + + public void setUf(String uf) { + this.uf = uf; + } + + public String getEmissao() { + return emissao; + } + + public void setEmissao(String emissao) { + this.emissao = emissao; + } + + public String getDocumento() { + return documento; + } + + public void setDocumento(String documento) { + this.documento = documento; + } + + public String getModelo() { + return modelo; + } + + public void setModelo(String modelo) { + this.modelo = modelo; + } + + public String getSerie() { + return serie; + } + + public void setSerie(String serie) { + this.serie = serie; + } + + public String getTipoEmissao() { + return tipoEmissao; + } + + public void setTipoEmissao(String tipoEmissao) { + this.tipoEmissao = tipoEmissao; + } + + public String getNumeroDocumentoFiscal() { + return numeroDocumentoFiscal; + } + + public void setNumeroDocumentoFiscal(String numeroDocumentoFiscal) { + this.numeroDocumentoFiscal = numeroDocumentoFiscal; + } + + public String getCbp() { + return cbp; + } + + public void setCbp(String cbp) { + this.cbp = cbp; + } + + @JsonIgnore + public boolean isValid() { + return (ambiente != null + && uf != null + && emissao != null + && documento != null + && modelo != null + && serie != null + && tipoEmissao != null + && numeroDocumentoFiscal != null); + } + + @Override + public String toString() { + return "QRCodeBean{" + + "ambiente='" + ambiente + '\'' + + ", uf='" + uf + '\'' + + ", emissao='" + emissao + '\'' + + ", documento='" + documento + '\'' + + ", modelo='" + modelo + '\'' + + ", serie='" + serie + '\'' + + ", tipoEmissao='" + tipoEmissao + '\'' + + ", numeroDocumentoFiscal='" + numeroDocumentoFiscal + '\'' + + ", cbp='" + cbp + '\'' + + '}'; + } +} diff --git a/bpe-api/src/main/java/br/com/sample/controller/ChaveController.java b/bpe-api/src/main/java/br/com/sample/controller/ChaveController.java new file mode 100755 index 0000000..c898429 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/controller/ChaveController.java @@ -0,0 +1,77 @@ +package br.com.sample.controller; + +import io.opentracing.Tracer; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.faulttolerance.*; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.opentracing.ClientTracingRegistrar; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Traced(value = true, operationName = "ChaveController") +public class ChaveController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Inject + @ConfigProperty(name = "bpechave.api.url", defaultValue = "http://bpe-chave:8080/") + private String bpechaveURL; + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Inject + private Tracer tracer; + + @Counted + @Timeout(3000) + @Bulkhead(value = 2, waitingTaskQueue = 10) + @Fallback(fallbackMethod = "getChaveBeanFallBack") + public JsonObject getChaveBean(final String correlationId, final String beanJsonString) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", String.format("Calling %s", bpechaveURL)); + jsonBuilder.add("bean", beanJsonString); + + JsonObject json = jsonBuilder.build(); + + tracer.activeSpan().log(json.toString()); + + Client client = ClientTracingRegistrar.configure(ClientBuilder.newBuilder()).build(); + + final Response response = client.target(bpechaveURL) + .path("chave") + .path("bean") + .request(MediaType.APPLICATION_JSON_TYPE) + .header("x-correlation-id", correlationId) + .post(Entity.json(beanJsonString)); + + return response.readEntity(JsonObject.class); + } + + public JsonObject getChaveBeanFallBack(final String correlationId, final String beanJsonString) { + JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("chbpe", "NA"); + jsonBuilder.add("app", app); + + JsonObject json = jsonBuilder.build(); + + logger.info(json.toString()); + + return json; + } +} diff --git a/bpe-api/src/main/java/br/com/sample/controller/QRCodeController.java b/bpe-api/src/main/java/br/com/sample/controller/QRCodeController.java new file mode 100755 index 0000000..77c222d --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/controller/QRCodeController.java @@ -0,0 +1,80 @@ +package br.com.sample.controller; + +import io.opentracing.Tracer; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.faulttolerance.Bulkhead; +import org.eclipse.microprofile.faulttolerance.Fallback; +import org.eclipse.microprofile.faulttolerance.Retry; +import org.eclipse.microprofile.faulttolerance.Timeout; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.opentracing.ClientTracingRegistrar; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Traced(value = true, operationName = "QRCodeController") +public class QRCodeController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Inject + @ConfigProperty(name = "bpeqrcode.api.url", defaultValue = "http://bpe-qrcode:8080/") + private String bpeqrcodeURL; + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Inject + private Tracer tracer; + + @Counted + @Timeout(3000) + @Bulkhead(value = 2, waitingTaskQueue = 10) + @Fallback(fallbackMethod = "getQRCodeBeanFallBack") + public JsonObject getQRCodeBean(final String correlationId, final String beanJsonString) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", String.format("Calling %s", bpeqrcodeURL)); + jsonBuilder.add("bean", beanJsonString); + + JsonObject json = jsonBuilder.build(); + + tracer.activeSpan().log(json.toString()); + + Client client = ClientTracingRegistrar.configure(ClientBuilder.newBuilder()).build(); + + final Response response = client.target(bpeqrcodeURL) + .path("qrcode") + .path("bean") + .request(MediaType.APPLICATION_JSON_TYPE) + .header("x-correlation-id", correlationId) + .post(Entity.json(beanJsonString)); + + return response.readEntity(JsonObject.class); + } + + public JsonObject getQRCodeBeanFallBack(final String correlationId, final String beanJsonString) { + JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("qrcode", "NA"); + jsonBuilder.add("app", app); + + JsonObject json = jsonBuilder.build(); + + logger.info(json.toString()); + + return json; + } +} diff --git a/bpe-api/src/main/java/br/com/sample/rest/ApiBPeChaveEndPoint.java b/bpe-api/src/main/java/br/com/sample/rest/ApiBPeChaveEndPoint.java new file mode 100755 index 0000000..794ebb4 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/rest/ApiBPeChaveEndPoint.java @@ -0,0 +1,126 @@ +package br.com.sample.rest; + +import br.com.sample.bean.ChaveBean; +import br.com.sample.controller.ChaveController; +import br.com.sample.util.CorrelationUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Path("/") +@Traced +public class ApiBPeChaveEndPoint { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final ObjectMapper om = new ObjectMapper(); + + @Inject + private ChaveController chaveController; + + @Inject + private CorrelationUtils correlationUtils; + + @Inject + @ConfigProperty(name = "bpechave.api.url", defaultValue = "http://bpe-chave:8080/") + private String bpechaveURL; + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @POST + @Counted(monotonic = true, name = "bpeapi-bpechave-count", absolute = true) + @Timed(name = "bpeapi-bpechave-time", absolute = true) + @Path("chave") + @Produces({MediaType.APPLICATION_JSON}) + @Consumes(MediaType.APPLICATION_JSON) + public Response doGetChaveBean(ChaveBean bean) { + String correlationId = correlationUtils.getCorrelationId(); + + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + + JsonObject obj = null; + + if (!bean.isValid()) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Parâmetros inválidos"); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.error(obj.toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(obj).build(); + } + + String chave = "NA"; + String beanJsonString = null; + + try { + beanJsonString = om.writeValueAsString(bean); + } catch (Exception e) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("exception", e.toString()); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.error(obj.toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(obj).build(); + } + + try { + obj = chaveController.getChaveBean(correlationId, beanJsonString); + chave = obj.getString("chbpe"); + + } catch (ProcessingException ex) { + String info = ex.toString(); + + if (ex.getCause() != null) { + info = ex.getCause().getClass().getSimpleName() + ": " + ex.getCause().getMessage(); + } + + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Exception trying to get the response from ".concat(bpechaveURL)); + jsonBuilder.add("exception", info); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.error(obj.toString(), ex); + + return Response + .status(Response.Status.SERVICE_UNAVAILABLE) + .entity(obj) + .build(); + } + + JsonObjectBuilder json = Json.createObjectBuilder(); + json.add("chbpe", chave); + json.add("correlation-id", correlationId); + + if (chave.equals("NA")) { + jsonBuilder.add("app", app); + } + + return Response.ok(json.build()).build(); + } +} \ No newline at end of file diff --git a/bpe-api/src/main/java/br/com/sample/rest/ApiBPeQRCodeEndPoint.java b/bpe-api/src/main/java/br/com/sample/rest/ApiBPeQRCodeEndPoint.java new file mode 100755 index 0000000..bc7bd72 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/rest/ApiBPeQRCodeEndPoint.java @@ -0,0 +1,118 @@ +package br.com.sample.rest; + +import br.com.sample.bean.QRCodeBean; +import br.com.sample.controller.QRCodeController; +import br.com.sample.util.CorrelationUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Path("/") +public class ApiBPeQRCodeEndPoint { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final ObjectMapper om = new ObjectMapper(); + + @Inject + private QRCodeController qrcodeController; + + @Inject + private CorrelationUtils correlationUtils; + + @Inject + @ConfigProperty(name = "bpeqrcode.api.url", defaultValue = "http://bpe-qrcode:8080/") + private String bpeqrcodeURL; + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @POST + @Counted(monotonic = true, name = "bpeapi-bpeqrcode-count", absolute = true) + @Timed(name = "bpeapi-bpeqrcode-time", absolute = true) + @Path("qrcode") + @Produces({MediaType.APPLICATION_JSON}) + @Consumes(MediaType.APPLICATION_JSON) + public Response doGetQRCode(QRCodeBean bean) { + String correlationId = correlationUtils.getCorrelationId(); + + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + + JsonObject obj = null; + + if (!bean.isValid()) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Parâmetros inválidos"); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.error(obj.toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(obj).build(); + } + + String beanJsonString = null; + + try { + beanJsonString = om.writeValueAsString(bean); + } catch (Exception e) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("exception", e.toString()); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.error(obj.toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(obj).build(); + } + + try { + obj = qrcodeController.getQRCodeBean(correlationId, beanJsonString); + + obj.forEach(jsonBuilder::add); + jsonBuilder.add("correlation-id", correlationId); + obj = jsonBuilder.build(); + + } catch (ProcessingException ex) { + String info = ex.toString(); + + if (ex.getCause() != null) { + info = ex.getCause().getClass().getSimpleName() + ": " + ex.getCause().getMessage(); + } + + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Exception trying to get the response from ".concat(bpeqrcodeURL)); + jsonBuilder.add("exception", info); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + obj = jsonBuilder.build(); + + logger.warn(obj.toString(), ex); + + return Response + .status(Response.Status.SERVICE_UNAVAILABLE) + .entity(obj) + .build(); + } + + return Response.ok(obj).build(); + } +} \ No newline at end of file diff --git a/bpe-api/src/main/java/br/com/sample/rest/ApiVersaoEndPoint.java b/bpe-api/src/main/java/br/com/sample/rest/ApiVersaoEndPoint.java new file mode 100755 index 0000000..9b81629 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/rest/ApiVersaoEndPoint.java @@ -0,0 +1,73 @@ +package br.com.sample.rest; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.InputStream; +import java.util.Properties; + +@ApplicationScoped +@Path("/") +public class ApiVersaoEndPoint { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Inject + @ConfigProperty(name = "ambiente", defaultValue = "2") + private String ambiente; + + @GET + @Counted(monotonic = true, name = "bpeapi-versao-count", absolute = true) + @Timed(name = "bpeapi-versao-time", absolute = true) + @Path("versao") + @Produces({MediaType.APPLICATION_JSON}) + public Response doGetversao() { + JsonObjectBuilder json = Json.createObjectBuilder(); + json.add("versao", getVersion()); + json.add("ambiente", ambiente); + + return Response.ok(json.build()).build(); + } + + public synchronized String getVersion() { + String version = null; + + try { + Properties p = new Properties(); + InputStream is = getClass().getResourceAsStream("/META-INF/maven/br.com.trevezani/bpe-api/pom.properties"); + if (is != null) { + p.load(is); + version = p.getProperty("version", ""); + } + } catch (Exception e) { + } + + // fallback to using Java API + if (version == null) { + Package aPackage = getClass().getPackage(); + if (aPackage != null) { + version = aPackage.getImplementationVersion(); + if (version == null) { + version = aPackage.getSpecificationVersion(); + } + } + } + + if (version == null) { + version = "1DF"; + } + + return version; + } +} diff --git a/bpe-api/src/main/java/br/com/sample/rest/RestApplication.java b/bpe-api/src/main/java/br/com/sample/rest/RestApplication.java new file mode 100755 index 0000000..879a21e --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/rest/RestApplication.java @@ -0,0 +1,9 @@ +package br.com.sample.rest; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/api") +public class RestApplication extends Application { + +} diff --git a/bpe-api/src/main/java/br/com/sample/rest/ServiceHealthCheck.java b/bpe-api/src/main/java/br/com/sample/rest/ServiceHealthCheck.java new file mode 100755 index 0000000..45ec4b4 --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/rest/ServiceHealthCheck.java @@ -0,0 +1,28 @@ +package br.com.sample.rest; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.health.Health; +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.HealthCheckResponseBuilder; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +@Health +@ApplicationScoped +public class ServiceHealthCheck implements HealthCheck { + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Override + public HealthCheckResponse call() { + HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named(app); + + responseBuilder.withData("memory", Runtime.getRuntime().freeMemory()); + responseBuilder.withData("availableProcessors", Runtime.getRuntime().availableProcessors()); + + return responseBuilder.state(true).build(); + } +} diff --git a/bpe-api/src/main/java/br/com/sample/util/CorrelationUtils.java b/bpe-api/src/main/java/br/com/sample/util/CorrelationUtils.java new file mode 100755 index 0000000..9c8b5ad --- /dev/null +++ b/bpe-api/src/main/java/br/com/sample/util/CorrelationUtils.java @@ -0,0 +1,13 @@ +package br.com.sample.util; + +import javax.enterprise.context.ApplicationScoped; +import java.util.UUID; + +@ApplicationScoped +public class CorrelationUtils { + + public String getCorrelationId() { + return UUID.randomUUID().toString(); + } + +} diff --git a/bpe-api/src/main/resources/META-INF/microprofile-config.properties b/bpe-api/src/main/resources/META-INF/microprofile-config.properties new file mode 100755 index 0000000..8ed4bde --- /dev/null +++ b/bpe-api/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1 @@ +app.name=bpe-api \ No newline at end of file diff --git a/bpe-api/src/resources/project-defaults.yml b/bpe-api/src/resources/project-defaults.yml new file mode 100755 index 0000000..32c7bd3 --- /dev/null +++ b/bpe-api/src/resources/project-defaults.yml @@ -0,0 +1,10 @@ +thorntail: + jaeger: + service-name: bpe-api + sampler-type: const + sampler-parameter: 1 + fluentd: + hostname: localhost + level: INFO + port: 24224 + tag: bpe-api \ No newline at end of file diff --git a/bpe-api/src/resources/project-istio.yml b/bpe-api/src/resources/project-istio.yml new file mode 100755 index 0000000..ccd3574 --- /dev/null +++ b/bpe-api/src/resources/project-istio.yml @@ -0,0 +1,7 @@ +thorntail: + jaeger: + service-name: bpe-api + sampler-type: const + sampler-parameter: 1 + enable-b3-header-propagation: true + remote-reporter-http-endpoint: 'http://jaeger-collector.istio-system:14268/api/traces' diff --git a/bpe-chave/DockerfileIstio b/bpe-chave/DockerfileIstio new file mode 100755 index 0000000..150668a --- /dev/null +++ b/bpe-chave/DockerfileIstio @@ -0,0 +1,13 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-chave\ + JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ + JAEGER_PROPAGATION=b3\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-chave/DockerfileNormal b/bpe-chave/DockerfileNormal new file mode 100755 index 0000000..2488933 --- /dev/null +++ b/bpe-chave/DockerfileNormal @@ -0,0 +1,11 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-chave\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-chave/pom.xml b/bpe-chave/pom.xml new file mode 100755 index 0000000..dfe6866 --- /dev/null +++ b/bpe-chave/pom.xml @@ -0,0 +1,182 @@ + + + 4.0.0 + br.com.sample + bpe-chave + BPe Chave + 1.0.11 + war + + + 2.4.0.Final + 1.8 + 1.8 + false + UTF-8 + + + + + + io.thorntail + bom-all + ${version.thorntail} + import + pom + + + io.thorntail + thorntail-runner + ${version.thorntail} + + + + + + bpe-chave + + + io.thorntail + thorntail-maven-plugin + ${version.thorntail} + + + + package + + + + + + true + + + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 + + + + + maven-war-plugin + 3.2.3 + + + + true + true + + + + + + io.fabric8 + docker-maven-plugin + 0.28.0 + + + + ${project.build.finalName}:${project.version} + + ${project.basedir}/${dockerfile} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + true + + + + maven-failsafe-plugin + 2.22.0 + + + **/*Test + + + + + + integration-test + verify + + + + + + + + + + io.thorntail + microprofile-jwt + + + io.thorntail + microprofile + + + io.thorntail + microprofile-restclient + + + io.thorntail + microprofile-metrics + + + io.thorntail + microprofile-opentracing + + + io.thorntail + jaxrs + + + io.thorntail + jaeger + + + io.thorntail + microprofile-fault-tolerance + + + io.thorntail + microprofile-health + + + io.thorntail + microprofile-config + + + io.thorntail + fluentd + + + io.thorntail + arquillian + test + + + + + normal + + true + + + DockerfileNormal + + + + istio + + DockerfileIstio + + + + diff --git a/bpe-chave/src/main/java/br/com/sample/bean/ChaveBean.java b/bpe-chave/src/main/java/br/com/sample/bean/ChaveBean.java new file mode 100755 index 0000000..270a10a --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/bean/ChaveBean.java @@ -0,0 +1,107 @@ +package br.com.sample.bean; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class ChaveBean { + private String uf; + private String emissao; + private String documento; + private String modelo; + private String serie; + private String tipoEmissao; + private String numeroDocumentoFiscal; + private String cbp; + + public ChaveBean() { + + } + + public String getUf() { + return uf; + } + + public void setUf(String uf) { + this.uf = uf; + } + + public String getEmissao() { + return emissao; + } + + public void setEmissao(String emissao) { + this.emissao = emissao; + } + + public String getDocumento() { + return documento; + } + + public void setDocumento(String documento) { + this.documento = documento; + } + + public String getModelo() { + return modelo; + } + + public void setModelo(String modelo) { + this.modelo = modelo; + } + + public String getSerie() { + return serie; + } + + public void setSerie(String serie) { + this.serie = serie; + } + + public String getTipoEmissao() { + return tipoEmissao; + } + + public void setTipoEmissao(String tipoEmissao) { + this.tipoEmissao = tipoEmissao; + } + + public String getNumeroDocumentoFiscal() { + return numeroDocumentoFiscal; + } + + public void setNumeroDocumentoFiscal(String numeroDocumentoFiscal) { + this.numeroDocumentoFiscal = numeroDocumentoFiscal; + } + + public String getCbp() { + return cbp; + } + + public void setCbp(String cbp) { + this.cbp = cbp; + } + + @JsonIgnore + public boolean isValid() { + return (uf != null + && emissao != null + && documento != null + && modelo != null + && serie != null + && tipoEmissao != null + && numeroDocumentoFiscal != null); + } + + @Override + public String toString() { + return "ChaveBean{" + + "uf='" + uf + '\'' + + ", emissao='" + emissao + '\'' + + ", documento='" + documento + '\'' + + ", modelo='" + modelo + '\'' + + ", serie='" + serie + '\'' + + ", tipoEmissao='" + tipoEmissao + '\'' + + ", numeroDocumentoFiscal='" + numeroDocumentoFiscal + '\'' + + ", cbp='" + cbp + '\'' + + '}'; + } +} diff --git a/bpe-chave/src/main/java/br/com/sample/controller/ChaveController.java b/bpe-chave/src/main/java/br/com/sample/controller/ChaveController.java new file mode 100755 index 0000000..2f63885 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/controller/ChaveController.java @@ -0,0 +1,48 @@ +package br.com.sample.controller; + +import br.com.sample.util.Modulo11; +import br.com.sample.util.StringUtils; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.validation.constraints.NotNull; +import java.util.Random; + +@ApplicationScoped +public class ChaveController { + @Inject + private StringUtils stringUtils; + + @Inject + private Modulo11 modulo11; + + public String getChaveBPe(@NotNull String uf, @NotNull String emissao, @NotNull String documento, + @NotNull String modelo, @NotNull String serie, @NotNull String tipoEmissao, + @NotNull String numeroDocumentoFiscal, String cbp) { + if (cbp == null) { + cbp = String.valueOf(new Random().nextInt(99999999)); + } + + // YYYYMMDD + String ano = emissao.substring(2, 4); + String mes = emissao.substring(5, 7); + + StringBuilder chave = new StringBuilder(); + chave.append(uf); + chave.append(ano); + chave.append(mes); + chave.append(stringUtils.lpadTo(documento.replaceAll("\\D", ""), 14, '0')); + chave.append(modelo); + chave.append(stringUtils.lpadTo(serie, 3, '0')); + chave.append(stringUtils.lpadTo(String.valueOf(numeroDocumentoFiscal), 9, '0')); + chave.append(stringUtils.lpadTo(tipoEmissao, 1, '0')); + chave.append(stringUtils.lpadTo(cbp, 8, '0')); + + String mod = String.valueOf(modulo11.modulo11(chave.toString())); + + chave.append(mod); + + return chave.toString(); + } + +} diff --git a/bpe-chave/src/main/java/br/com/sample/enums/Ambiente.java b/bpe-chave/src/main/java/br/com/sample/enums/Ambiente.java new file mode 100755 index 0000000..267fd9f --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/enums/Ambiente.java @@ -0,0 +1,26 @@ +package br.com.sample.enums; + +import java.util.Arrays; + +public enum Ambiente { + Producao("1"), + Homologacao("2"); + + String codigo; + + Ambiente(String codigo) { + this.codigo = codigo; + } + + public String getCodigo() { + return this.codigo; + } + + public static Ambiente getAmbiente(String codigo) { + Ambiente ambiente = Arrays.stream(Ambiente.values()) + .filter(e -> e.getCodigo().equals(codigo)) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", codigo))); + return ambiente; + } +} diff --git a/bpe-chave/src/main/java/br/com/sample/rest/BPeChaveEndPoint.java b/bpe-chave/src/main/java/br/com/sample/rest/BPeChaveEndPoint.java new file mode 100755 index 0000000..6c2bc81 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/rest/BPeChaveEndPoint.java @@ -0,0 +1,96 @@ +package br.com.sample.rest; + +import br.com.sample.bean.ChaveBean; +import br.com.sample.controller.ChaveController; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Tag(name = "BPeChave", description = "Microserviço responsável por gerar a chave BPe") +@ApplicationScoped +@Path("chave") +@Traced +public class BPeChaveEndPoint { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Inject + private ChaveController chaveController; + + @GET + @Counted(monotonic = true, name = "bpechave-count", absolute = true) + @Timed(name = "bpechave-time", absolute = true) + @Operation(summary = "Gerar chave BPe") + @APIResponse(description = "Chave BPe") + @Path("/{uf}/{emissao}/{documento}/{modelo}/{serie}/{tipoEmissao}/{numeroDocumentoFiscal}/{cbp}") + @Produces({MediaType.APPLICATION_JSON}) + public Response doGetChave(@PathParam("uf") String uf, @PathParam("emissao") String emissao, + @PathParam("documento") String documento, @PathParam("modelo") String modelo, + @PathParam("serie") String serie, @PathParam("tipoEmissao") String tipoEmissao, + @PathParam("numeroDocumentoFiscal") String numeroDocumentoFiscal, @PathParam("cbp") String cbp) { + String chave = chaveController.getChaveBPe( uf, emissao, documento, modelo, serie, tipoEmissao, numeroDocumentoFiscal, cbp); + + JsonObjectBuilder json = Json.createObjectBuilder(); + json.add("chbpe", chave); + + return Response.ok(json.build()).build(); + } + + @POST + @Counted(monotonic = true, name = "bpechave-count", absolute = true) + @Timed(name = "bpechave-time", absolute = true) + @Path("bean") + @Operation(summary = "Gerar chave BPe via JSON") + @APIResponse(description = "Chave BPe") + @Produces({MediaType.APPLICATION_JSON}) + @Consumes(MediaType.APPLICATION_JSON) + public Response doGetChaveBean(@HeaderParam("x-correlation-id") String correlationId, ChaveBean bean) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + + if (!bean.isValid()) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Parâmetros inválidos"); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + JsonObject json = jsonBuilder.build(); + + logger.error(json.toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(json).build(); + } + + String chave = chaveController.getChaveBPe( bean.getUf(), bean.getEmissao(), bean.getDocumento(), bean.getModelo(), + bean.getSerie(), bean.getTipoEmissao(), bean.getNumeroDocumentoFiscal(), bean.getCbp()); + + JsonObjectBuilder json = Json.createObjectBuilder(); + json.add("chbpe", chave); + + final JsonObjectBuilder jsonBuilderLog = Json.createObjectBuilder(); + jsonBuilderLog.add("correlation-id", correlationId); + jsonBuilderLog.add("message", String.format("Chave gerada [%s]", chave)); + jsonBuilderLog.add("app", app); + + logger.info(jsonBuilderLog.build().toString()); + + return Response.ok(json.build()).build(); + } +} diff --git a/bpe-chave/src/main/java/br/com/sample/rest/RestApplication.java b/bpe-chave/src/main/java/br/com/sample/rest/RestApplication.java new file mode 100755 index 0000000..249c7c8 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/rest/RestApplication.java @@ -0,0 +1,9 @@ +package br.com.sample.rest; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/") +public class RestApplication extends Application { + +} diff --git a/bpe-chave/src/main/java/br/com/sample/rest/ServiceHealthCheck.java b/bpe-chave/src/main/java/br/com/sample/rest/ServiceHealthCheck.java new file mode 100755 index 0000000..45ec4b4 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/rest/ServiceHealthCheck.java @@ -0,0 +1,28 @@ +package br.com.sample.rest; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.health.Health; +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.HealthCheckResponseBuilder; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +@Health +@ApplicationScoped +public class ServiceHealthCheck implements HealthCheck { + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Override + public HealthCheckResponse call() { + HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named(app); + + responseBuilder.withData("memory", Runtime.getRuntime().freeMemory()); + responseBuilder.withData("availableProcessors", Runtime.getRuntime().availableProcessors()); + + return responseBuilder.state(true).build(); + } +} diff --git a/bpe-chave/src/main/java/br/com/sample/util/Modulo11.java b/bpe-chave/src/main/java/br/com/sample/util/Modulo11.java new file mode 100755 index 0000000..b787f53 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/util/Modulo11.java @@ -0,0 +1,24 @@ +package br.com.sample.util; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class Modulo11 { + + public int modulo11(String chave) { + int total = 0; + int peso = 2; + + for (int i = 0; i < chave.length(); i++) { + total += (chave.charAt((chave.length() - 1) - i) - '0') * peso; + peso++; + if (peso == 10) + peso = 2; + } + + int resto = total % 11; + + return (resto == 0 || resto == 1) ? 0 : (11 - resto); + } + +} diff --git a/bpe-chave/src/main/java/br/com/sample/util/StringUtils.java b/bpe-chave/src/main/java/br/com/sample/util/StringUtils.java new file mode 100755 index 0000000..afea5f8 --- /dev/null +++ b/bpe-chave/src/main/java/br/com/sample/util/StringUtils.java @@ -0,0 +1,23 @@ +package br.com.sample.util; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class StringUtils { + + public String lpadTo(String input, int width, char ch) { + String strPad = ""; + + StringBuffer sb = new StringBuffer(input.trim()); + + while (sb.length() < width) + sb.insert(0, ch); + strPad = sb.toString(); + + if (strPad.length() > width) { + strPad = strPad.substring(0, width); + } + return strPad; + } + +} diff --git a/bpe-chave/src/main/resources/META-INF/microprofile-config.properties b/bpe-chave/src/main/resources/META-INF/microprofile-config.properties new file mode 100755 index 0000000..8c72a01 --- /dev/null +++ b/bpe-chave/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1 @@ +app.name=bpe-chave \ No newline at end of file diff --git a/bpe-chave/src/resources/project-defaults.yml b/bpe-chave/src/resources/project-defaults.yml new file mode 100755 index 0000000..37fc929 --- /dev/null +++ b/bpe-chave/src/resources/project-defaults.yml @@ -0,0 +1,10 @@ +thorntail: + jaeger: + service-name: bpe-chave + sampler-type: const + sampler-parameter: 1 + fluentd: + hostname: localhost + level: INFO + port: 24224 + tag: bpe-chave \ No newline at end of file diff --git a/bpe-chave/src/resources/project-istio.yml b/bpe-chave/src/resources/project-istio.yml new file mode 100755 index 0000000..95e24b9 --- /dev/null +++ b/bpe-chave/src/resources/project-istio.yml @@ -0,0 +1,7 @@ +thorntail: + jaeger: + service-name: bpe-chave + sampler-type: const + sampler-parameter: 1 + enable-b3-header-propagation: true + remote-reporter-http-endpoint: 'http://jaeger-collector.istio-system:14268/api/traces' diff --git a/bpe-chave/src/test/java/test/rest/BPeChaveEndPointTest.java b/bpe-chave/src/test/java/test/rest/BPeChaveEndPointTest.java new file mode 100755 index 0000000..0e53c62 --- /dev/null +++ b/bpe-chave/src/test/java/test/rest/BPeChaveEndPointTest.java @@ -0,0 +1,132 @@ +package test.rest; + +import br.com.sample.bean.ChaveBean; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.json.JsonObject; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.net.URL; + +@RunWith(Arquillian.class) +public class BPeChaveEndPointTest { + @ArquillianResource + private URL webappUrl; + + WebTarget target; + + ObjectMapper om = new ObjectMapper(); + + @Before + public void before() throws Exception { + target = ClientBuilder.newClient().target(webappUrl.toURI()); + } + + @Deployment + public static WebArchive createTestArchive() { + File[] files = Maven.resolver().loadPomFromFile("pom.xml") + .importRuntimeDependencies().resolve().withTransitivity().asFile(); + + WebArchive war = ShrinkWrap.create(WebArchive.class) + .addAsLibraries(files) + .addPackages(true, "br.com.trevezani.bpechave") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + + return war; + } + + @Test + @RunAsClient + @InSequence(1) + public void testChave() throws IOException { + final Response response = target.path("chave") + .path("23") + .path("20190621") + .path("68830611000") + .path("63") + .path("001") + .path("1") + .path("13") + .path("123") + .request(MediaType.APPLICATION_JSON_TYPE) + .get(); + + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + + JsonObject obj = response.readEntity(JsonObject.class); + + Assert.assertNotNull("Chave inválida", obj); + + System.out.println("Validando o retorno: ".concat(obj.toString())); + + Assert.assertEquals("QRCode diferente: ".concat(obj.getString("chbpe")), + "23196200068830611000630010000000131000001230", obj.getString("chbpe")); + } + + @Test + @RunAsClient + @InSequence(2) + public void testChaveBean() throws IOException { + ChaveBean bean = new ChaveBean(); + bean.setUf("23"); + bean.setEmissao("20190621"); + bean.setDocumento("68830611000"); + bean.setModelo("63"); + bean.setSerie("001"); + bean.setTipoEmissao("1"); + bean.setNumeroDocumentoFiscal("13"); + bean.setCbp("123"); + + String beanJsonString = om.writeValueAsString(bean); + + final Response response = target.path("chave") + .path("br.com.trevezani.bean") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(beanJsonString)); + + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + + JsonObject obj = response.readEntity(JsonObject.class); + + Assert.assertNotNull("Chave inválida", obj); + + System.out.println("Validando o retorno: ".concat(obj.toString())); + + Assert.assertEquals("QRCode diferente: ".concat(obj.getString("chbpe")), + "23196200068830611000630010000000131000001230", obj.getString("chbpe")); + } + + @Test + @RunAsClient + @InSequence(3) + public void testChaveBeanError() throws IOException { + ChaveBean bean = new ChaveBean(); + + String beanJsonString = om.writeValueAsString(bean); + + final Response response = target.path("chave") + .path("br.com.trevezani.bean") + .request(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(beanJsonString)); + + Assert.assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + } +} \ No newline at end of file diff --git a/bpe-qrcode/DockerfileIstio b/bpe-qrcode/DockerfileIstio new file mode 100755 index 0000000..5f620d1 --- /dev/null +++ b/bpe-qrcode/DockerfileIstio @@ -0,0 +1,13 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-qrcode\ + JAEGER_ENDPOINT=http://jaeger-collector.istio-system.svc:14268/api/traces\ + JAEGER_PROPAGATION=b3\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-qrcode/DockerfileNormal b/bpe-qrcode/DockerfileNormal new file mode 100755 index 0000000..e17973e --- /dev/null +++ b/bpe-qrcode/DockerfileNormal @@ -0,0 +1,11 @@ +FROM openjdk:8u212-jre-alpine +RUN apk add --update \ + curl \ + && rm -rf /var/cache/apk/* +ENV AB_OFF=true +ENV JAEGER_SERVICE_NAME=bpe-qrcode\ + JAEGER_SAMPLER_TYPE=const\ + JAEGER_SAMPLER_PARAM=1 +EXPOSE 8080 8778 9779 5006 +ADD target/*.jar /app.jar +CMD java -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006 -Djava.net.preferIPv4Stack=true -jar /app.jar \ No newline at end of file diff --git a/bpe-qrcode/pom.xml b/bpe-qrcode/pom.xml new file mode 100755 index 0000000..5b9403e --- /dev/null +++ b/bpe-qrcode/pom.xml @@ -0,0 +1,194 @@ + + + 4.0.0 + br.com.sample + bpe-qrcode + BPe QRCode URL + 1.0.12 + war + + + 2.4.0.Final + 1.8 + 1.8 + false + UTF-8 + + + + + + io.thorntail + bom-all + ${version.thorntail} + import + pom + + + io.thorntail + thorntail-runner + ${version.thorntail} + + + + + + bpe-qrcode + + + io.thorntail + thorntail-maven-plugin + ${version.thorntail} + + + + package + + + + + + true + + + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 + + + + + maven-war-plugin + 3.2.3 + + + + true + true + + + + + + io.fabric8 + docker-maven-plugin + 0.28.0 + + + + ${project.build.finalName}:${project.version} + + ${project.basedir}/${dockerfile} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + true + + + + maven-failsafe-plugin + 2.22.0 + + + **/*Test + + + + + + integration-test + verify + + + + + + + + + + io.thorntail + microprofile-jwt + + + io.thorntail + microprofile + + + + + + + + + + + io.thorntail + microprofile-restclient + + + io.thorntail + microprofile-metrics + + + io.thorntail + microprofile-openapi + + + io.thorntail + microprofile-opentracing + + + io.thorntail + jaxrs + + + io.thorntail + jaeger + + + io.thorntail + microprofile-fault-tolerance + + + io.thorntail + microprofile-health + + + io.thorntail + microprofile-config + + + io.thorntail + fluentd + + + io.thorntail + arquillian + test + + + + + normal + + true + + + DockerfileNormal + + + + istio + + DockerfileIstio + + + + diff --git a/bpe-qrcode/src/main/java/br/com/sample/bean/ChaveBean.java b/bpe-qrcode/src/main/java/br/com/sample/bean/ChaveBean.java new file mode 100755 index 0000000..270a10a --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/bean/ChaveBean.java @@ -0,0 +1,107 @@ +package br.com.sample.bean; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class ChaveBean { + private String uf; + private String emissao; + private String documento; + private String modelo; + private String serie; + private String tipoEmissao; + private String numeroDocumentoFiscal; + private String cbp; + + public ChaveBean() { + + } + + public String getUf() { + return uf; + } + + public void setUf(String uf) { + this.uf = uf; + } + + public String getEmissao() { + return emissao; + } + + public void setEmissao(String emissao) { + this.emissao = emissao; + } + + public String getDocumento() { + return documento; + } + + public void setDocumento(String documento) { + this.documento = documento; + } + + public String getModelo() { + return modelo; + } + + public void setModelo(String modelo) { + this.modelo = modelo; + } + + public String getSerie() { + return serie; + } + + public void setSerie(String serie) { + this.serie = serie; + } + + public String getTipoEmissao() { + return tipoEmissao; + } + + public void setTipoEmissao(String tipoEmissao) { + this.tipoEmissao = tipoEmissao; + } + + public String getNumeroDocumentoFiscal() { + return numeroDocumentoFiscal; + } + + public void setNumeroDocumentoFiscal(String numeroDocumentoFiscal) { + this.numeroDocumentoFiscal = numeroDocumentoFiscal; + } + + public String getCbp() { + return cbp; + } + + public void setCbp(String cbp) { + this.cbp = cbp; + } + + @JsonIgnore + public boolean isValid() { + return (uf != null + && emissao != null + && documento != null + && modelo != null + && serie != null + && tipoEmissao != null + && numeroDocumentoFiscal != null); + } + + @Override + public String toString() { + return "ChaveBean{" + + "uf='" + uf + '\'' + + ", emissao='" + emissao + '\'' + + ", documento='" + documento + '\'' + + ", modelo='" + modelo + '\'' + + ", serie='" + serie + '\'' + + ", tipoEmissao='" + tipoEmissao + '\'' + + ", numeroDocumentoFiscal='" + numeroDocumentoFiscal + '\'' + + ", cbp='" + cbp + '\'' + + '}'; + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/bean/QRCodeBean.java b/bpe-qrcode/src/main/java/br/com/sample/bean/QRCodeBean.java new file mode 100755 index 0000000..d3fe30f --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/bean/QRCodeBean.java @@ -0,0 +1,103 @@ +package br.com.sample.bean; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class QRCodeBean { + private String ambiente; + private String uf; + private String emissao; + private String documento; + private String modelo; + private String serie; + private String tipoEmissao; + private String numeroDocumentoFiscal; + private String cbp; + + public QRCodeBean() { + + } + + public String getAmbiente() { + return ambiente; + } + + public void setAmbiente(String ambiente) { + this.ambiente = ambiente; + } + + public String getUf() { + return uf; + } + + public void setUf(String uf) { + this.uf = uf; + } + + public String getEmissao() { + return emissao; + } + + public void setEmissao(String emissao) { + this.emissao = emissao; + } + + public String getDocumento() { + return documento; + } + + public void setDocumento(String documento) { + this.documento = documento; + } + + public String getModelo() { + return modelo; + } + + public void setModelo(String modelo) { + this.modelo = modelo; + } + + public String getSerie() { + return serie; + } + + public void setSerie(String serie) { + this.serie = serie; + } + + public String getTipoEmissao() { + return tipoEmissao; + } + + public void setTipoEmissao(String tipoEmissao) { + this.tipoEmissao = tipoEmissao; + } + + public String getNumeroDocumentoFiscal() { + return numeroDocumentoFiscal; + } + + public void setNumeroDocumentoFiscal(String numeroDocumentoFiscal) { + this.numeroDocumentoFiscal = numeroDocumentoFiscal; + } + + public String getCbp() { + return cbp; + } + + public void setCbp(String cbp) { + this.cbp = cbp; + } + + @JsonIgnore + public boolean isValid() { + return (ambiente != null + && uf != null + && emissao != null + && documento != null + && modelo != null + && serie != null + && tipoEmissao != null + && numeroDocumentoFiscal != null); + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/controller/QRCodeController.java b/bpe-qrcode/src/main/java/br/com/sample/controller/QRCodeController.java new file mode 100755 index 0000000..41e7ef5 --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/controller/QRCodeController.java @@ -0,0 +1,89 @@ +package br.com.sample.controller; + +import br.com.sample.enums.Ambiente; +import br.com.sample.enums.QRCodeURL; +import io.opentracing.Tracer; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.faulttolerance.Bulkhead; +import org.eclipse.microprofile.faulttolerance.Fallback; +import org.eclipse.microprofile.faulttolerance.Retry; +import org.eclipse.microprofile.faulttolerance.Timeout; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.opentracing.ClientTracingRegistrar; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Traced(value = true, operationName = "QRCodeController") +public class QRCodeController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Inject + @ConfigProperty(name = "bpechave.api.url", defaultValue = "http://bpe-chave:8080/") + private String bpechaveURL; + + @Inject + private Tracer tracer; + + public String getURL(final String ambienteId, final String ufId) { + Ambiente ambiente = Ambiente.getAmbiente(ambienteId); + String url = QRCodeURL.getURL(ambiente, ufId); + + return url; + } + + @Counted + @Timeout(3000) + @Bulkhead(value = 2, waitingTaskQueue = 10) + @Fallback(fallbackMethod = "getChaveBeanFallBack") + public JsonObject getChaveBean(final String correlationId, final String beanJsonString) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", String.format("Calling %s", bpechaveURL)); + jsonBuilder.add("bean", beanJsonString); + + JsonObject json = jsonBuilder.build(); + + tracer.activeSpan().log(json.toString()); + + Client client = ClientTracingRegistrar.configure(ClientBuilder.newBuilder()).build(); + + final Response response = client.target(bpechaveURL) + .path("chave") + .path("bean") + .request(MediaType.APPLICATION_JSON) + .header("x-correlation-id", correlationId) + .post(Entity.json(beanJsonString)); + + return response.readEntity(JsonObject.class); + } + + public JsonObject getChaveBeanFallBack(final String correlationId, final String beanJsonString) { + JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("chbpe", "NA"); + jsonBuilder.add("app", app); + + JsonObject json = jsonBuilder.build(); + + logger.info(json.toString()); + + return json; + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/enums/Ambiente.java b/bpe-qrcode/src/main/java/br/com/sample/enums/Ambiente.java new file mode 100755 index 0000000..267fd9f --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/enums/Ambiente.java @@ -0,0 +1,26 @@ +package br.com.sample.enums; + +import java.util.Arrays; + +public enum Ambiente { + Producao("1"), + Homologacao("2"); + + String codigo; + + Ambiente(String codigo) { + this.codigo = codigo; + } + + public String getCodigo() { + return this.codigo; + } + + public static Ambiente getAmbiente(String codigo) { + Ambiente ambiente = Arrays.stream(Ambiente.values()) + .filter(e -> e.getCodigo().equals(codigo)) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", codigo))); + return ambiente; + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/enums/QRCodeURL.java b/bpe-qrcode/src/main/java/br/com/sample/enums/QRCodeURL.java new file mode 100755 index 0000000..6e1946d --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/enums/QRCodeURL.java @@ -0,0 +1,58 @@ +package br.com.sample.enums; + +import java.util.Arrays; + +public enum QRCodeURL { + CE("23", "https://dfe-portal.svrs.rs.gov.br/bpe/qrCode", "https://dfe-portal.sefazvirtual.rs.gov.br/bpe/qrcode"), + RN("24", "https://dfe-portal.svrs.rs.gov.br/bpe/qrCode", "https://dfe-portal.sefazvirtual.rs.gov.br/bpe/qrcode"), + MG("31", "https://bpe.fazenda.mg.gov.br/portalbpe/sistema/qrcode.xhtml", "https://bpe.fazenda.mg.gov.br/portalbpe/sistema/qrcode.xhtml"), + RJ("33", "https://dfe-portal.svrs.rs.gov.br/bpe/qrCode", "https://dfe-portal.sefazvirtual.rs.gov.br/bpe/qrcode"); + + String uf; + String homologacao; + String producao; + + QRCodeURL(String uf, String homologacao, String producao) { + this.uf = uf; + this.homologacao = homologacao; + this.producao = producao; + } + + public String getUf() { + return uf; + } + + public static QRCodeURL getQRCodeURL(String uf) { + QRCodeURL qr = Arrays.stream(QRCodeURL.values()) + .filter(e -> e.getUf().equals(uf)) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", uf))); + return qr; + } + + public static String getURL(Ambiente ambiente, QRCodeURL qrCodeURL) { + QRCodeURL qr = Arrays.stream(QRCodeURL.values()) + .filter(e -> e.name().equals(qrCodeURL.name())) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", qrCodeURL.name()))); + + if (ambiente.equals(Ambiente.Producao)) { + return qr.producao; + } else { + return qr.homologacao; + } + } + + public static String getURL(Ambiente ambiente, String uf) { + QRCodeURL qr = Arrays.stream(QRCodeURL.values()) + .filter(e -> e.getUf().equals(uf)) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format("Unsupported type %s.", uf))); + + if (ambiente.equals(Ambiente.Producao)) { + return qr.producao; + } else { + return qr.homologacao; + } + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/rest/QRCodeEndPoint.java b/bpe-qrcode/src/main/java/br/com/sample/rest/QRCodeEndPoint.java new file mode 100755 index 0000000..82378cb --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/rest/QRCodeEndPoint.java @@ -0,0 +1,148 @@ +package br.com.sample.rest; + +import br.com.sample.bean.ChaveBean; +import br.com.sample.bean.QRCodeBean; +import br.com.sample.controller.QRCodeController; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.faulttolerance.CircuitBreaker; +import org.eclipse.microprofile.faulttolerance.Fallback; +import org.eclipse.microprofile.faulttolerance.Timeout; +import org.eclipse.microprofile.metrics.annotation.Counted; +import org.eclipse.microprofile.metrics.annotation.Timed; +import org.eclipse.microprofile.opentracing.ClientTracingRegistrar; +import org.eclipse.microprofile.opentracing.Traced; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.ws.rs.*; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@ApplicationScoped +@Path("qrcode") +@Traced +public class QRCodeEndPoint { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final ObjectMapper om = new ObjectMapper(); + + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Inject + @ConfigProperty(name = "bpechave.api.url", defaultValue = "http://bpe-chave:8080/") + private String bpechaveURL; + + @Inject + private QRCodeController qrcodeController; + + @POST + @Counted(monotonic = true, name = "bpeqrcode-count", absolute = true) + @Timed(name = "bpeqrcode-time", absolute = true) + @Path("bean") + @Produces({MediaType.APPLICATION_JSON}) + @Consumes(MediaType.APPLICATION_JSON) + public Response doGetQRCode(@HeaderParam("x-correlation-id") String correlationId, QRCodeBean bean) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + + if (!bean.isValid()) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Parâmetros inválidos"); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + logger.error(jsonBuilder.build().toString()); + + return Response.status(Response.Status.BAD_REQUEST).entity(jsonBuilder.build()).build(); + } + + ChaveBean chaveBean = new ChaveBean(); + chaveBean.setUf(bean.getUf()); + chaveBean.setEmissao(bean.getEmissao()); + chaveBean.setDocumento(bean.getDocumento()); + chaveBean.setModelo(bean.getModelo()); + chaveBean.setSerie(bean.getSerie()); + chaveBean.setTipoEmissao(bean.getTipoEmissao()); + chaveBean.setNumeroDocumentoFiscal(bean.getNumeroDocumentoFiscal()); + chaveBean.setCbp(bean.getCbp()); + + String chave = getChaveBean(correlationId, chaveBean); + String url = null; + + try { + url = qrcodeController.getURL(bean.getAmbiente(), bean.getUf()); + } catch (Exception ex) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("exception", ex.toString()); + jsonBuilder.add("app", app); + + JsonObject json = jsonBuilder.build(); + + logger.error(json.toString(), ex); + + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(json).build(); + } + + StringBuilder retorno = new StringBuilder(); + retorno.append(url); + retorno.append("?").append("chbpe").append("=").append(chave); + retorno.append("&").append("tpamb").append("=").append(bean.getAmbiente()); + + JsonObjectBuilder json = Json.createObjectBuilder(); + json.add("qrcode", retorno.toString()); + + return Response.ok(json.build()).build(); + } + + public String getChaveBean(final String correlationId, ChaveBean bean) { + final JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); + + String chave = "NA"; + String beanJsonString = null; + + try { + beanJsonString = om.writeValueAsString(bean); + } catch (Exception ex) { + String info = ex.toString(); + + if (ex.getCause() != null) { + info = ex.getCause().getClass().getSimpleName() + ": " + ex.getCause().getMessage(); + } + + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("exception", info); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + logger.warn(jsonBuilder.build().toString(), ex); + + return "NA"; + } + + try { + JsonObject obj = qrcodeController.getChaveBean(correlationId, beanJsonString); + chave = obj.getString("chbpe"); + + } catch (ProcessingException ex) { + jsonBuilder.add("correlation-id", correlationId); + jsonBuilder.add("message", "Exception trying to get the response from ".concat(bpechaveURL)); + jsonBuilder.add("exception", ex.toString()); + jsonBuilder.add("bean", bean.toString()); + jsonBuilder.add("app", app); + + logger.warn(jsonBuilder.build().toString(), ex); + } + + return chave; + } +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/rest/RestApplication.java b/bpe-qrcode/src/main/java/br/com/sample/rest/RestApplication.java new file mode 100755 index 0000000..249c7c8 --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/rest/RestApplication.java @@ -0,0 +1,9 @@ +package br.com.sample.rest; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/") +public class RestApplication extends Application { + +} diff --git a/bpe-qrcode/src/main/java/br/com/sample/rest/ServiceHealthCheck.java b/bpe-qrcode/src/main/java/br/com/sample/rest/ServiceHealthCheck.java new file mode 100755 index 0000000..45ec4b4 --- /dev/null +++ b/bpe-qrcode/src/main/java/br/com/sample/rest/ServiceHealthCheck.java @@ -0,0 +1,28 @@ +package br.com.sample.rest; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.health.Health; +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.HealthCheckResponseBuilder; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +@Health +@ApplicationScoped +public class ServiceHealthCheck implements HealthCheck { + @Inject + @ConfigProperty(name = "app.name") + private String app; + + @Override + public HealthCheckResponse call() { + HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named(app); + + responseBuilder.withData("memory", Runtime.getRuntime().freeMemory()); + responseBuilder.withData("availableProcessors", Runtime.getRuntime().availableProcessors()); + + return responseBuilder.state(true).build(); + } +} diff --git a/bpe-qrcode/src/main/resources/META-INF/microprofile-config.properties b/bpe-qrcode/src/main/resources/META-INF/microprofile-config.properties new file mode 100755 index 0000000..d7acb41 --- /dev/null +++ b/bpe-qrcode/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1 @@ +app.name=bpe-qrcode \ No newline at end of file diff --git a/bpe-qrcode/src/resources/project-defaults.yml b/bpe-qrcode/src/resources/project-defaults.yml new file mode 100755 index 0000000..e28c077 --- /dev/null +++ b/bpe-qrcode/src/resources/project-defaults.yml @@ -0,0 +1,10 @@ +thorntail: + jaeger: + service-name: bpe-qrcode + sampler-type: const + sampler-parameter: 1 + fluentd: + hostname: localhost + level: INFO + port: 24224 + tag: bpe-qrcode \ No newline at end of file diff --git a/bpe-qrcode/src/resources/project-istio.yml b/bpe-qrcode/src/resources/project-istio.yml new file mode 100755 index 0000000..fd203af --- /dev/null +++ b/bpe-qrcode/src/resources/project-istio.yml @@ -0,0 +1,7 @@ +thorntail: + jaeger: + service-name: bpe-qrcode + sampler-type: const + sampler-parameter: 1 + enable-b3-header-propagation: true + remote-reporter-http-endpoint: 'http://jaeger-collector.istio-system:14268/api/traces' diff --git a/bpe-qrcode/src/test/java/test/rest/QRCodeEndPointTest.java b/bpe-qrcode/src/test/java/test/rest/QRCodeEndPointTest.java new file mode 100755 index 0000000..82472a4 --- /dev/null +++ b/bpe-qrcode/src/test/java/test/rest/QRCodeEndPointTest.java @@ -0,0 +1,84 @@ +package test.rest; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.json.JsonObject; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.net.URL; + + +@RunWith(Arquillian.class) +public class QRCodeEndPointTest { + @ArquillianResource + private URL webappUrl; + + WebTarget target; + + ObjectMapper om = new ObjectMapper(); + + @Before + public void before() throws Exception { + target = ClientBuilder.newClient().target(webappUrl.toURI()); + } + + @Deployment + public static WebArchive createTestArchive() { + File[] files = Maven.resolver().loadPomFromFile("pom.xml") + .importRuntimeDependencies().resolve().withTransitivity().asFile(); + + WebArchive war = ShrinkWrap.create(WebArchive.class) + .addAsLibraries(files) + .addPackages(true, "br.com.trevezani.bpechave") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + + return war; + } + + @Test + @RunAsClient + @InSequence(1) + public void testQRCode() throws IOException { + final Response response = target.path("qrcode") + .path("2") + .path("23") + .path("20190621") + .path("04406541659") + .path("63") + .path("001") + .path("1") + .path("13") + .path("123") + .request(MediaType.APPLICATION_JSON_TYPE) + .get(); + + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + + JsonObject obj = response.readEntity(JsonObject.class); + + Assert.assertNotNull("QRCode inválido", obj); + + System.out.println("Validando o retorno: ".concat(obj.toString())); + + Assert.assertEquals("QRCode diferente: ".concat(obj.getString("qrcode")), + "https://dfe-portal.svrs.rs.gov.br/bpe/qrCode?chbpe=23196200004406541659630010000000131000001232&tpamb=2", obj.getString("qrcode")); + } +} \ No newline at end of file diff --git a/extra/kubernates/networking/bpeapi-destinationrule-v11-v12.yml b/extra/kubernates/networking/bpeapi-destinationrule-v11-v12.yml new file mode 100755 index 0000000..68d3bd1 --- /dev/null +++ b/extra/kubernates/networking/bpeapi-destinationrule-v11-v12.yml @@ -0,0 +1,16 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: bpe-api + namespace: bpe +spec: + host: bpe-api + subsets: + - name: v10 + labels: + version: v10 + - name: v11 + labels: + version: v11 + + diff --git a/extra/kubernates/networking/bpeapi-gateway.yml b/extra/kubernates/networking/bpeapi-gateway.yml new file mode 100755 index 0000000..9eacf99 --- /dev/null +++ b/extra/kubernates/networking/bpeapi-gateway.yml @@ -0,0 +1,35 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: bpe-gateway + namespace: bpe +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bpe + namespace: bpe +spec: + hosts: + - "*" + gateways: + - bpe-gateway + http: + - match: + - uri: + prefix: /api + route: + - destination: + host: bpe-api + port: + number: 8080 \ No newline at end of file diff --git a/extra/kubernates/networking/bpeapi-ingress-default.yml b/extra/kubernates/networking/bpeapi-ingress-default.yml new file mode 100755 index 0000000..7a37ffc --- /dev/null +++ b/extra/kubernates/networking/bpeapi-ingress-default.yml @@ -0,0 +1,9 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: bpe-ingress + namespace: bpe +spec: + backend: + serviceName: bpe-api + servicePort: 8080 diff --git a/extra/kubernates/networking/bpeapi-virtualservice-gateway-100.yml b/extra/kubernates/networking/bpeapi-virtualservice-gateway-100.yml new file mode 100755 index 0000000..a380cb9 --- /dev/null +++ b/extra/kubernates/networking/bpeapi-virtualservice-gateway-100.yml @@ -0,0 +1,20 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bpe-gateway + namespace: bpe +spec: + hosts: + - "*" + gateways: + - bpe-gateway + http: + - match: + - uri: + prefix: /api + route: + - destination: + host: bpe-api + subset: v11 + port: + number: 8080 \ No newline at end of file diff --git a/extra/kubernates/networking/bpeapi-virtualservice-gateway-90-10.yml b/extra/kubernates/networking/bpeapi-virtualservice-gateway-90-10.yml new file mode 100755 index 0000000..5c2149f --- /dev/null +++ b/extra/kubernates/networking/bpeapi-virtualservice-gateway-90-10.yml @@ -0,0 +1,27 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bpe-gateway + namespace: bpe +spec: + hosts: + - "*" + gateways: + - bpe-gateway + http: + - match: + - uri: + prefix: /api + route: + - destination: + host: bpe-api + subset: v10 + port: + number: 8080 + weight: 90 + - destination: + host: bpe-api + subset: v11 + port: + number: 8080 + weight: 10 diff --git a/extra/kubernates/networking/bpeqrcode-destinationrule-v11-v12.yml b/extra/kubernates/networking/bpeqrcode-destinationrule-v11-v12.yml new file mode 100755 index 0000000..08f59c8 --- /dev/null +++ b/extra/kubernates/networking/bpeqrcode-destinationrule-v11-v12.yml @@ -0,0 +1,19 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: bpe-qrcode + namespace: bpe +spec: + host: bpe-qrcode + subsets: + - name: v11 + labels: + version: v11 + - name: v12 + labels: + version: v12 + + + + + diff --git a/extra/kubernates/networking/bpeqrcode-virtualservice-100.yml b/extra/kubernates/networking/bpeqrcode-virtualservice-100.yml new file mode 100755 index 0000000..6022176 --- /dev/null +++ b/extra/kubernates/networking/bpeqrcode-virtualservice-100.yml @@ -0,0 +1,14 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bpe-qrcode + namespace: bpe +spec: + hosts: + - bpe-qrcode + http: + - route: + - destination: + host: bpe-qrcode + subset: v12 +--- \ No newline at end of file diff --git a/extra/kubernates/networking/bpeqrcode-virtualservice-90-10.yml b/extra/kubernates/networking/bpeqrcode-virtualservice-90-10.yml new file mode 100755 index 0000000..8cdc141 --- /dev/null +++ b/extra/kubernates/networking/bpeqrcode-virtualservice-90-10.yml @@ -0,0 +1,19 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bpe-qrcode + namespace: bpe +spec: + hosts: + - bpe-qrcode + http: + - route: + - destination: + host: bpe-qrcode + subset: v11 + weight: 90 + - destination: + host: bpe-qrcode + subset: v12 + weight: 10 +--- \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeapi-deployment-default.yml b/extra/kubernates/plataform/bpeapi-deployment-default.yml new file mode 100755 index 0000000..227f046 --- /dev/null +++ b/extra/kubernates/plataform/bpeapi-deployment-default.yml @@ -0,0 +1,34 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: bpe-api + version: 1.0.0 + name: bpe-api-1.0.0 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-api + version: 1.0.0 + template: + metadata: + labels: + app: bpe-api + version: 1.0.0 + spec: + containers: + - env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + name: bpe-api + image: :5000/bpe-api:1.0.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + restartPolicy: Always + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeapi-deployment.yml b/extra/kubernates/plataform/bpeapi-deployment.yml new file mode 100755 index 0000000..dc00f71 --- /dev/null +++ b/extra/kubernates/plataform/bpeapi-deployment.yml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: bpe-api + version: v11 + name: bpe-api-v11 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-api + version: v11 + template: + metadata: + labels: + app: bpe-api + version: v11 + annotations: + sidecar.istio.io/inject: "true" + spec: + containers: + - name: bpe-api + image: 192.168.1.9:5000/bpe-api:1.0.11 + imagePullPolicy: IfNotPresent + env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + - name: ambiente + valueFrom: + configMapKeyRef: + name: bpe-config + key: ambiente + ports: + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 8778 + name: jolokia + protocol: TCP + - containerPort: 9779 + name: prometheus + protocol: TCP + securityContext: + privileged: false + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeapi-service.yml b/extra/kubernates/plataform/bpeapi-service.yml new file mode 100755 index 0000000..6e617a9 --- /dev/null +++ b/extra/kubernates/plataform/bpeapi-service.yml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: bpe-api + namespace: bpe + labels: + app: bpe-api + service: bpe-api +spec: + ports: + - name: http + port: 8080 + selector: + app: bpe-api \ No newline at end of file diff --git a/extra/kubernates/plataform/bpechave-deployment-default.yml b/extra/kubernates/plataform/bpechave-deployment-default.yml new file mode 100755 index 0000000..8640908 --- /dev/null +++ b/extra/kubernates/plataform/bpechave-deployment-default.yml @@ -0,0 +1,34 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: bpe-chave + version: 1.0.0 + name: bpe-chave-1.0.0 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-chave + version: 1.0.0 + template: + metadata: + labels: + app: bpe-chave + version: 1.0.0 + spec: + containers: + - env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + name: bpe-chave + image: :5000/bpe-chave:1.0.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + restartPolicy: Always + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpechave-deployment.yml b/extra/kubernates/plataform/bpechave-deployment.yml new file mode 100755 index 0000000..7ea7697 --- /dev/null +++ b/extra/kubernates/plataform/bpechave-deployment.yml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: bpe-chave + version: v11 + name: bpe-chave-v11 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-chave + version: v11 + template: + metadata: + labels: + app: bpe-chave + version: v11 + annotations: + sidecar.istio.io/inject: "true" + spec: + containers: + - name: bpe-chave + image: 192.168.1.9:5000/bpe-chave:1.0.11 + imagePullPolicy: IfNotPresent + env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + - name: ambiente + valueFrom: + configMapKeyRef: + name: bpe-config + key: ambiente + ports: + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 8778 + name: jolokia + protocol: TCP + - containerPort: 9779 + name: prometheus + protocol: TCP + securityContext: + privileged: false + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpechave-service.yml b/extra/kubernates/plataform/bpechave-service.yml new file mode 100755 index 0000000..9902f9c --- /dev/null +++ b/extra/kubernates/plataform/bpechave-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: bpe-chave + namespace: bpe + labels: + app: bpe-chave +spec: + ports: + - name: http + port: 8080 + selector: + app: bpe-chave \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeqrcode-deployment-default.yml b/extra/kubernates/plataform/bpeqrcode-deployment-default.yml new file mode 100755 index 0000000..1f61085 --- /dev/null +++ b/extra/kubernates/plataform/bpeqrcode-deployment-default.yml @@ -0,0 +1,34 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + app: bpe-qrcode + version: 1.0.0 + name: bpe-qrcode-1.0.0 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-qrcode + version: 1.0.0 + template: + metadata: + labels: + app: bpe-qrcode + version: 1.0.0 + spec: + containers: + - env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + name: bpe-qrcode + image: :5000/bpe-qrcode:1.0.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + protocol: TCP + restartPolicy: Always + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeqrcode-deployment.yml b/extra/kubernates/plataform/bpeqrcode-deployment.yml new file mode 100755 index 0000000..7a854fb --- /dev/null +++ b/extra/kubernates/plataform/bpeqrcode-deployment.yml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: bpe-qrcode + version: v11 + name: bpe-qrcode-v11 + namespace: bpe +spec: + replicas: 1 + selector: + matchLabels: + app: bpe-qrcode + version: v11 + template: + metadata: + labels: + app: bpe-qrcode + version: v11 + annotations: + sidecar.istio.io/inject: "true" + spec: + containers: + - name: bpe-qrcode + image: 192.168.1.9:5000/bpe-qrcode:1.0.11 + imagePullPolicy: IfNotPresent + env: + - name: JAVA_OPTIONS + value: -Xms15m -Xmx15m -Xmn15m + - name: ambiente + valueFrom: + configMapKeyRef: + name: bpe-config + key: ambiente + ports: + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 8778 + name: jolokia + protocol: TCP + - containerPort: 9779 + name: prometheus + protocol: TCP + securityContext: + privileged: false + imagePullSecrets: + - name: service-registry \ No newline at end of file diff --git a/extra/kubernates/plataform/bpeqrcode-service.yml b/extra/kubernates/plataform/bpeqrcode-service.yml new file mode 100755 index 0000000..cda15fc --- /dev/null +++ b/extra/kubernates/plataform/bpeqrcode-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: bpe-qrcode + namespace: bpe + labels: + app: bpe-qrcode +spec: + ports: + - name: http + port: 8080 + selector: + app: bpe-qrcode \ No newline at end of file diff --git a/extra/kubernates/plataform/namespace-bpe.json b/extra/kubernates/plataform/namespace-bpe.json new file mode 100755 index 0000000..032eb44 --- /dev/null +++ b/extra/kubernates/plataform/namespace-bpe.json @@ -0,0 +1,10 @@ +{ + "apiVersion": "v1", + "kind": "Namespace", + "metadata": { + "name": "bpe", + "labels": { + "name": "bpe" + } + } +} \ No newline at end of file diff --git a/extra/kubernates/telemetry/elastic.yaml b/extra/kubernates/telemetry/elastic.yaml new file mode 100755 index 0000000..e5438e7 --- /dev/null +++ b/extra/kubernates/telemetry/elastic.yaml @@ -0,0 +1,46 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: elasticsearch +spec: + selector: + matchLabels: + component: elasticsearch + template: + metadata: + labels: + component: elasticsearch + spec: + containers: + - name: elasticsearch + image: docker.elastic.co/elasticsearch/elasticsearch:6.5.4 + env: + - name: discovery.type + value: single-node + ports: + - containerPort: 9200 + name: http + protocol: TCP + resources: + limits: + cpu: 500m + memory: 4Gi + requests: + cpu: 500m + memory: 4Gi + +--- + +apiVersion: v1 +kind: Service +metadata: + name: elasticsearch + labels: + service: elasticsearch +spec: + type: NodePort + selector: + component: elasticsearch + ports: + - port: 9200 + targetPort: 9200 \ No newline at end of file diff --git a/extra/kubernates/telemetry/fluentd-daemonset.yaml b/extra/kubernates/telemetry/fluentd-daemonset.yaml new file mode 100755 index 0000000..c5837f4 --- /dev/null +++ b/extra/kubernates/telemetry/fluentd-daemonset.yaml @@ -0,0 +1,54 @@ +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: fluentd + namespace: kube-system + labels: + k8s-app: fluentd-logging + version: v1 + kubernetes.io/cluster-service: "true" +spec: + template: + metadata: + labels: + k8s-app: fluentd-logging + version: v1 + kubernetes.io/cluster-service: "true" + spec: + serviceAccount: fluentd + serviceAccountName: fluentd + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule + containers: + - name: fluentd + image: fluent/fluentd-kubernetes-daemonset:v1.3-debian-elasticsearch + env: + - name: FLUENT_ELASTICSEARCH_HOST + value: "elasticsearch.logging" + - name: FLUENT_ELASTICSEARCH_PORT + value: "9200" + - name: FLUENT_ELASTICSEARCH_SCHEME + value: "http" + - name: FLUENT_UID + value: "0" + resources: + limits: + memory: 200Mi + requests: + cpu: 100m + memory: 200Mi + volumeMounts: + - name: varlog + mountPath: /var/log + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + terminationGracePeriodSeconds: 30 + volumes: + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers \ No newline at end of file diff --git a/extra/kubernates/telemetry/fluentd-rbac.yaml b/extra/kubernates/telemetry/fluentd-rbac.yaml new file mode 100755 index 0000000..b1b0591 --- /dev/null +++ b/extra/kubernates/telemetry/fluentd-rbac.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: fluentd + namespace: kube-system + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: fluentd + namespace: kube-system +rules: + - apiGroups: + - "" + resources: + - pods + - namespaces + verbs: + - get + - list + - watch + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: fluentd +roleRef: + kind: ClusterRole + name: fluentd + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: fluentd + namespace: kube-system \ No newline at end of file diff --git a/extra/kubernates/telemetry/kibana.yaml b/extra/kubernates/telemetry/kibana.yaml new file mode 100755 index 0000000..367a82d --- /dev/null +++ b/extra/kubernates/telemetry/kibana.yaml @@ -0,0 +1,41 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: kibana +spec: + selector: + matchLabels: + run: kibana + template: + metadata: + labels: + run: kibana + spec: + containers: + - name: kibana + image: docker.elastic.co/kibana/kibana:6.5.4 + env: + - name: ELASTICSEARCH_URL + value: http://elasticsearch:9200 + - name: XPACK_SECURITY_ENABLED + value: "true" + ports: + - containerPort: 5601 + name: http + protocol: TCP + +--- + +apiVersion: v1 +kind: Service +metadata: + name: kibana + labels: + service: kibana +spec: + type: NodePort + selector: + run: kibana + ports: + - port: 5601 + targetPort: 5601 \ No newline at end of file diff --git a/extra/logging/docker-compose.yml b/extra/logging/docker-compose.yml new file mode 100755 index 0000000..1191c3c --- /dev/null +++ b/extra/logging/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.7" +services: + agreggrator: + build: ./fluentd + ports: + - "24224:24224" + - "24224:24224/udp" + volumes: + - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.3.2 + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms1g -Xmx1g" + user: 'elasticsearch' + volumes: + - elasticsearch-data:/usr/share/elasticsearch/data + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + ports: + - "9200:9200" + kibana: + image: docker.elastic.co/kibana/kibana:7.3.2 + links: + - elasticsearch + ports: + - "5601:5601" + environment: + - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 + depends_on: + - elasticsearch +volumes: + elasticsearch-data: \ No newline at end of file diff --git a/extra/logging/fluentd/Dockerfile b/extra/logging/fluentd/Dockerfile new file mode 100755 index 0000000..eb554e7 --- /dev/null +++ b/extra/logging/fluentd/Dockerfile @@ -0,0 +1,18 @@ +FROM fluent/fluentd:v1.5-1 + +# Use root account to use apk +USER root + +RUN apk add --no-cache --update geoip-dev \ + && apk add --no-cache --update --virtual .build-deps build-base ruby-dev \ + && echo 'gem: --no-document' >> /etc/gemrc \ + && gem install fluent-plugin-elasticsearch fluent-plugin-woothee fluent-plugin-ua-parser fluent-plugin-geoip-filter fluent-plugin-multi-format-parser \ + && gem sources --clear-all \ + && apk del .build-deps \ + && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem + +COPY fluent.conf /fluentd/etc/ +COPY entrypoint.sh /bin/ + +ENV FLUENT_UID=0 +#USER fluent \ No newline at end of file diff --git a/extra/logging/fluentd/entrypoint.sh b/extra/logging/fluentd/entrypoint.sh new file mode 100755 index 0000000..876b424 --- /dev/null +++ b/extra/logging/fluentd/entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +#source vars if file exists +DEFAULT=/etc/default/fluentd + +if [ -r $DEFAULT ]; then + set -o allexport + . $DEFAULT + set +o allexport +fi + +# If the user has supplied only arguments append them to `fluentd` command +if [ "${1#-}" != "$1" ]; then + set -- fluentd "$@" +fi + +# If user does not supply config file or plugins, use the default +if [ "$1" = "fluentd" ]; then + if ! echo $@ | grep ' \-c' ; then + set -- "$@" -c /fluentd/etc/${FLUENTD_CONF} + fi + + if ! echo $@ | grep ' \-p' ; then + set -- "$@" -p /fluentd/plugins + fi +fi + +exec "$@" diff --git a/extra/logging/fluentd/fluent.conf b/extra/logging/fluentd/fluent.conf new file mode 100755 index 0000000..d8c86df --- /dev/null +++ b/extra/logging/fluentd/fluent.conf @@ -0,0 +1,55 @@ +# fluentd/conf/fluent.conf +# +# log_level ERROR +# + + + @type forward + port 24224 + bind 0.0.0.0 + tag bpe + + + + @type parser +# format /^(? + + + @type copy + + @type elasticsearch + host elasticsearch + port 9200 + logstash_format true + logstash_prefix bpe + logstash_dateformat %Y%m%d + include_tag_key true + tag_key @log_name + flush_interval 1s + + + #@type memory # file #or memory + @type file + path /tmp/fluentd*.buffer + flush_mode interval + retry_type exponential_backoff + flush_thread_count 4 + flush_interval 1s + retry_forever + retry_max_interval 30 + chunk_limit_size 2M + queue_limit_length 8 + overflow_action block + + + + @type stdout + + diff --git a/extra/test/docker-compose.yml b/extra/test/docker-compose.yml new file mode 100755 index 0000000..771cfe6 --- /dev/null +++ b/extra/test/docker-compose.yml @@ -0,0 +1,135 @@ +version: '3' +services: + jaeger: + image: jaegertracing/all-in-one:1.8 + ports: + - "5775:5775/udp" + - "6831:6831/udp" + - "6832:6832/udp" + - "5778:5778" + - "16686:16686" + - "14268:14268" + - "9411:9411" + environment: + - COLLECTOR_ZIPKIN_HTTP_PORT=9411 + networks: + mp-net: + ipv4_address: 172.18.0.5 + + agreggrator: + build: ./fluentd + ports: + - "24224:24224" + - "24224:24224/udp" + volumes: + - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf + networks: + mp-net: + ipv4_address: 172.18.0.6 + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.3.2 + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms1g -Xmx1g" + user: 'elasticsearch' + volumes: + - elasticsearch-data:/usr/share/elasticsearch/data + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + ports: + - "9200:9200" + networks: + mp-net: + ipv4_address: 172.18.0.7 + + kibana: + image: docker.elastic.co/kibana/kibana:7.3.2 + links: + - elasticsearch + ports: + - "5601:5601" + environment: + - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 + depends_on: + - elasticsearch + networks: + mp-net: + ipv4_address: 172.18.0.8 + + mp-bpe-api: + image: bpe-api:1.0.10 + ports: + - "8080:8080" + - "5010:5006" + depends_on: + - jaeger + networks: + mp-net: + ipv4_address: 172.18.0.11 + links: + - jaeger + environment: + - bpeqrcode.api.url=http://mp-bpe-qrcode:8080 + - bpechave.api.url=http://mp-bpe-chave:8080 + - JAEGER_AGENT_HOST=jaeger + - JAEGER_SERVICE_NAME=bpe-api + - JAEGER_REPORTER_LOG_SPANS=true + - JAEGER_SAMPLER_TYPE=const + - JAEGER_SAMPLER_PARAM=1 + - thorntail.fluentd.hostname=172.18.0.6 + mp-bpe-qrcode: + image: bpe-qrcode:1.0.10 + ports: + - "8081:8080" + - "5011:5006" + depends_on: + - jaeger + networks: + mp-net: + ipv4_address: 172.18.0.12 + links: + - jaeger + environment: + - bpechave.api.url=http://mp-bpe-chave:8080 + - JAEGER_AGENT_HOST=jaeger + - JAEGER_SERVICE_NAME=bpe-qrcode + - JAEGER_REPORTER_LOG_SPANS=true + - JAEGER_SAMPLER_TYPE=const + - JAEGER_SAMPLER_PARAM=1 + - thorntail.fluentd.hostname=172.18.0.6 + mp-bpe-chave: + image: bpe-chave:1.0.10 + ports: + - "8082:8080" + - "5012:5006" + depends_on: + - jaeger + networks: + mp-net: + ipv4_address: 172.18.0.13 + links: + - jaeger + environment: + - JAEGER_AGENT_HOST=jaeger + - JAEGER_SERVICE_NAME=bpe-chave + - JAEGER_REPORTER_LOG_SPANS=true + - JAEGER_SAMPLER_TYPE=const + - JAEGER_SAMPLER_PARAM=1 + - thorntail.fluentd.hostname=172.18.0.6 + +volumes: + elasticsearch-data: + +networks: + mp-net: + driver: bridge + ipam: + config: + - subnet: 172.18.0.0/16 \ No newline at end of file diff --git a/extra/test/fluentd/Dockerfile b/extra/test/fluentd/Dockerfile new file mode 100755 index 0000000..eb554e7 --- /dev/null +++ b/extra/test/fluentd/Dockerfile @@ -0,0 +1,18 @@ +FROM fluent/fluentd:v1.5-1 + +# Use root account to use apk +USER root + +RUN apk add --no-cache --update geoip-dev \ + && apk add --no-cache --update --virtual .build-deps build-base ruby-dev \ + && echo 'gem: --no-document' >> /etc/gemrc \ + && gem install fluent-plugin-elasticsearch fluent-plugin-woothee fluent-plugin-ua-parser fluent-plugin-geoip-filter fluent-plugin-multi-format-parser \ + && gem sources --clear-all \ + && apk del .build-deps \ + && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem + +COPY fluent.conf /fluentd/etc/ +COPY entrypoint.sh /bin/ + +ENV FLUENT_UID=0 +#USER fluent \ No newline at end of file diff --git a/extra/test/fluentd/entrypoint.sh b/extra/test/fluentd/entrypoint.sh new file mode 100755 index 0000000..876b424 --- /dev/null +++ b/extra/test/fluentd/entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +#source vars if file exists +DEFAULT=/etc/default/fluentd + +if [ -r $DEFAULT ]; then + set -o allexport + . $DEFAULT + set +o allexport +fi + +# If the user has supplied only arguments append them to `fluentd` command +if [ "${1#-}" != "$1" ]; then + set -- fluentd "$@" +fi + +# If user does not supply config file or plugins, use the default +if [ "$1" = "fluentd" ]; then + if ! echo $@ | grep ' \-c' ; then + set -- "$@" -c /fluentd/etc/${FLUENTD_CONF} + fi + + if ! echo $@ | grep ' \-p' ; then + set -- "$@" -p /fluentd/plugins + fi +fi + +exec "$@" diff --git a/extra/test/fluentd/fluent.conf b/extra/test/fluentd/fluent.conf new file mode 100755 index 0000000..d8c86df --- /dev/null +++ b/extra/test/fluentd/fluent.conf @@ -0,0 +1,55 @@ +# fluentd/conf/fluent.conf +# +# log_level ERROR +# + + + @type forward + port 24224 + bind 0.0.0.0 + tag bpe + + + + @type parser +# format /^(? + + + @type copy + + @type elasticsearch + host elasticsearch + port 9200 + logstash_format true + logstash_prefix bpe + logstash_dateformat %Y%m%d + include_tag_key true + tag_key @log_name + flush_interval 1s + + + #@type memory # file #or memory + @type file + path /tmp/fluentd*.buffer + flush_mode interval + retry_type exponential_backoff + flush_thread_count 4 + flush_interval 1s + retry_forever + retry_max_interval 30 + chunk_limit_size 2M + queue_limit_length 8 + overflow_action block + + + + @type stdout + +