Das kannste schon so machen

Preview:

Citation preview

Das kannste schon so machen…

André Goliath

Disclaimer:This talk is bad

Because I had no timeBecause of the issues this talk is about

(makes sense, right?)

That being said…

Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies

Jenkins & NPM

Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies

Jenkins & NPM

You all know I´m a nice, calm, relaxed, chilled, error-forgiving

guy, right?

@ControllerAdvicepublic class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler { …

@ExceptionHandler({Exception.class}) private ResponseEntity<Object> handleAllUnknownExceptions(Exception ex) { return handleExceptionInternal(ex, null, null, HttpStatus.INTERNAL_SERVER_ERROR, null); }

@Override @ResponseBody protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {

BaseResponse errorMessage = createErrorMessage(ex); HttpStatus returnStatus = status != null ? status : HttpStatus.INTERNAL_SERVER_ERROR;

ResponseStatus exResponseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);

if (exResponseStatus != null) { returnStatus = exResponseStatus.value(); } return new ResponseEntity<>(errorMessage, headers, returnStatus); }

}

@Configuration@EnableWebMvcpublic class DispatcherServletConfigurer{

@Bean public FSLDispatcherServletHandlerErrorConfigurator getDispatcherServletPostProcessor(){ return new FSLDispatcherServletHandlerErrorConfigurator(); }

public class FSLDispatcherServletHandlerErrorConfigurator implements BeanPostProcessor {

public Object postProcessBeforeInitialization(Object bean, String beanName) throws …{ if (bean instanceof DispatcherServlet) { DispatcherServlet disp = ((DispatcherServlet) bean); disp.setThrowExceptionIfNoHandlerFound(true); } return bean; }… }

That´s so Spring Boot 1.2.x!(1.2 was released in Dec 2014, 1.3 in Nov 2015)

spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false

(you still need the @ControllerAdvice though)

NETFLIX OSS

ConfigserverSpring Cloud ConfigService Registry eurekaReverse Proxy zuulCircuit Breaker hystrix

Client

Reverse Proxy(ZUUL)

Service Registry(EUREKA) Config Server

So how do you deliver the configuration

for all your microservices and environments?

HINT: NOT IN ONE BIG ZIP FILE

C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml

C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml

C:\YOURSTUFF\CONFIG-GOOD\\|-- development.yml|-- production.yml|-- uat.yml| +---service-a| service-a-development.yml| service-a-production.yml| service-a-uat.yml| +---service-b| service-b-development.yml| service-b-production.yml| service-b-uat.yml| \---service-c service-c-development.yml service-c-production.yml service-c-uat.yml

C:\YOURSTUFF\CONFIG-BAD\\+---development| global.yml| service-a.yml| service-b.yml| service-c.yml| | +---production| global.yml| service-a.yml| service-b.yml| service-c.yml| \---uat global.yml service-a.yml service-b.yml service-c.yml

C:\YOURSTUFF\CONFIG-GOOD\\|-- development.yml|-- production.yml|-- uat.yml| +---service-a| service-a-development.yml| service-a-production.yml| service-a-uat.yml| +---service-b| service-b-development.yml| service-b-production.yml| service-b-uat.yml| \---service-c service-c-development.yml service-c-production.yml service-c-uat.yml

Never usedashes In

service names!

What is that zuul anyway?And what does it do?

AND HOW DO WE USE IT?

@SpringBootApplication@Controller@EnableZuulProxypublic class ZuulApplication {

public static void main(String[] args) { new SpringApplicationBuilder(ZuulApplication.class) .web(true).run(args); }}

ZUUL DOES MUCH MORE THINGS THEN WE SEE!

NOTE TO SELF:SPRING DOES NOT USE SEMANTIC

VERSIONING!

Lessons learnedfrom working with Spring

NEVER TRUST DEFAULT VALUES

READ THE FRIENDLY MANUAL…

… AND ESPECIALLYTHE RELEASE NOTES!

Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies

Jenkins & NPM

private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { template.setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) } return template; }}

private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}

org.springframework.ws.client.WebServiceIOException: I/O error: null; nested exception is org.apache.http.client.ClientProtocolException

at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:543)

...Caused by: org.apache.http.client.ClientProtocolException

at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:909)

... 32 moreCaused by: org.apache.http.ProtocolException: Content-Length header already present

... 39 more

private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}

SSL Protocol Error: Handshake failure

private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .useSystemProperties() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); } template.setMessageSender(senderForProxy); } return template; }}

400(a.k.a. „Bad Request“)

400(a.k.a. least helpful HTTP

response code of all times.)

…5 Hours of HTTP traffic comparison later…

SOAP-Namespaces?

Am I missing any HTTP header?Malformed XML?

No Proxy allowed? Still SSL issues?

…5 Hours of HTTP traffic comparison later…

Am I missing any HTTP header?

I am sending one header too much.

Am I missing any HTTP header?

private WebServiceTemplate attachProxy(WebServiceTemplate template) { if (config.getUseProxy()) { if (senderForProxy == null) { HttpClient client = HttpClients.custom() .useSystemProperties() .setProxy(new HttpHost(config.getProxyHost(), config.getProxyPort())) .addInterceptorFirst( new HttpComponentsMessageSender .RemoveSoapHeadersInterceptor() ) .build(); senderForProxy = new HttpComponentsMessageSender(client); senderForProxy.setAcceptGzipEncoding(false); } template.setMessageSender(senderForProxy); } return template; }}

It took me about 5 full days to get this right.

Lessons learnedfrom the proxy disaster

Have the samecommunication infrastructure

on every(!) test setup

No Proxy? Make your own.var http = require('http'), httpProxy = require('http-proxy');

var proxy = httpProxy.createProxyServer({});

var interceptingServer = http.createServer(function (req, res) { // define your custom logic to handle the request // and then proxy the request. proxy.web(req, res, {target: 'http://MyActualTargetService.com'});});

console.log("proxy listening on port 5050")interceptingServer.listen(5050);

https://github.com/nodejitsu/node-http-proxy

Talking about JavaScript…

Spring Boot & Netflix OSS StackWebServiceTemplate & Proxies

Jenkins & NPM

Node Package Manager v2is bad. Like, really bad.

So what’s the big deal?

npm install

…on Senacor Hardware: 15 min…on Clients Dev. Machine: 20 min…on Jenkins:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software

Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software

Filesystem Inodes IUsed IFree IUse% Mounted on.../dev/mapper/datavg-lv_optsoftware 32768000 32428987 39013 99% /opt/software

Filesystem Size Used Avail Use% Mounted on.../dev/mapper/datavg-lv_optsoftware 492G 22G 446G 5% /opt/software

Filesystem Inodes IUsed IFree IUse% Mounted on.../dev/mapper/datavg-lv_optsoftware 32768000 32428987 39013 99% /opt/software

I lost track when the deepest node_modules pathwas about 2000 chars long…

npm dedupe would help,but only if npm install worked at least once…

Beware:Npm3 will be the default packagemanager starting with nodejs 5.x,and is a breaking change:

Lessons learned:We started the project when NodeJS 4.x and npm 3.xwere still unstable.That time is gone. Go for it.

Thank You!

André GoliathSenior Technical Consultantandre.goliath@senacor.de

Recommended