Don’t let CloudFormation delete your RDS!

Once an RDS instance is restored from a snapshot, the snapshot name must remain in the CF template on subsequent deployments. Removing it will tear down the database and create a new, empty database. For Aurora, both the cluster and all its instances will get replaced if the snapshot name changes or is removed.

Attempting to delete a database via CLI results in:

AmazonRDSException Please specify FinalSnapshotIdentifier or SkipFinalSnapshot (Service: AmazonRDS; Status Code: 400; Error Code: InvalidParameterCombination)

That is to say, you cannot programmatically delete a database from the RDS CLI without this ‘are you sure’ check. Rather it is the CF template where you are most likely to accidentally request a database deletion via replacement, by accidentally removing the snapshot id from the database definition.

In the Cloudformation CLI, you can list changesets for a CF stack and then describe the proposed changeset, which will show which resources are going to be replaced (replacement: true), which gives you a change to back out of a replacement if incorporated into the CF template execution process.

Do not rely on DeletionPolicy for RDS to mitigate against this. An RDS deletion policy of ‘retain’ on the database only retains it when the stack is deleted. It does NOT retain it when just the database is deleted. So DeletionPolicy Retain does not protect you against snapshot name changes tearing down your database.

An RDS deletion policy of snapshot will create a snapshot when the CF stack is deleted so you can at least restore to a new database. Snapshot will be of type ‘manual’. But again, this does not protect you against snapshot name changes tearing down your database, because it only works when the whole CF stack is deleted.

TLDR; a CF changeset that causes an RDS teardown and setup does not respect a ‘Retain’ or ‘Snapshot’ deletion policy, either for the cluster or any of the instances, because it is not technically a delete, but a modify.

Therefore, RDS databases should always protect themselves against deletion and modification by using IAM deny policies over and above RDS deletion policies.

Advertisements

Logging SOAP client messages from CXF in Spring Boot

Since getting this to work was more troublesome that it should have been, here are the details.

First, the following dependencies will be required (I am using 2.7.18):

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-api</artifactId>
	<version>${cxf.runtime.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-transports-http</artifactId>
	<version>${cxf.runtime.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-frontend-jaxws</artifactId>
	<version>${cxf.runtime.version}</version>
</dependency>

Next, we need a Spring configuration class that sets up the required CXF classes:


@Configuration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml", "classpath:META-INF/cxf/cxf-extension-soap.xml" })
public class CxfConfig {

	@Autowired
	private SpringBus springBus;

	@PostConstruct
	public void activateLoggingFeature() {
           springBus.getInInterceptors().add(logInInterceptor());
    	   springBus.getInFaultInterceptors().add(logInInterceptor());
    	   springBus.getOutInterceptors().add(logOutInterceptor());
    	   springBus.getOutFaultInterceptors().add(logOutInterceptor());
	}

	@Bean
	public LoggingFeature loggingFeature() {
    	   LoggingFeature logFeature = new LoggingFeature();
    	   logFeature.setPrettyLogging(true);
    	   logFeature.initialize(springBus);
    	   springBus.getFeatures().add(logFeature);
    	   return logFeature;
	}

	public AbstractLoggingInterceptor logInInterceptor() {
	    return new LoggingInInterceptor();
	}

	public AbstractLoggingInterceptor logOutInterceptor() {
		LoggingOutInterceptor logOutInterceptor = new LoggingOutInterceptor();
		logOutInterceptor.setPrettyLogging(true);
		return logOutInterceptor;
	}

}

Finally, we need to add CXF components to the logging framework config (e.g. logback.xml)

...
   <logger name="org.apache.cxf" level="INFO"/>
...
---------------------------
ID: 12
Address: ... something ....
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>

     ... data here ....

  </soap:Body>
</soap:Envelope>

--------------------------------------

Reactor Pattern and its relation to Observer

The semantics of RxJava refer to the Observer pattern.  What exactly is the relation?

Here’a nice simple example from the Couchbase documentation:

Observable
    .just("doc1", "doc2", "doc3";)
    .flatMap(bucket::get)
    .subscribe(document -> System.out.println("Got: " + document));

You begin with any kind of stream, for which you want map each member to something new.  Syntactically, this is just the same as the Java 8 streaming API, which also has map and flatMap, and also allows a fork/join. Whilst in Java, the stream functions over a collection, in Rx, the stream is designed to handle events occurring over time, terminating on the receipt of a completion event.

This requires that mapping items (in the example, calling bucket.get for each item) in the stream will return Observables, rather than results or values.  The point of this is that we can add one or more subscribers that will get notified when the result of each element mapping is complete. A Reactor framework will typically allow subscribers for specific observable events – success and failure, and completion of the event stream, etc. These can be handled according to the type of Observable (HTTP request, TCP request, database call etc.).

This is an implementation of the Observer pattern, where observers (subscribers) register for specific event notifications. It is particularly relevant for microservices, where intermediate results are to be collected and then assembled into a final result.

Unable to find contextual data of type: javax.servlet.ServletContext

The combination of Spring Boot, RestEasy and Swagger 2 is not exactly a happy combination. Both Spring Boot and Swagger seems to prefer Jersey to RestEasy.  However, in my case as in others, RestEasy is mandated by factors outside my control.

Starting with Andy Wilkinson’s Spring Boot RestEasy (https://github.com/wilkinsona/spring-boot-resteasy), and then adding the latest Swagger 2 libraries (io.swagger), I was plagued by the error: Unable to find contextual data of type: javax.servlet.ServletContext

It seems the new io.swagger.jaxrs.listing.ApiListingResource causes RestEasy 3.0.9 to require a ThreadLocal reference to ServletContext which basically is not there, hence the error, which does not occur with the older com.wordnik.swagger.jaxrs.listing.ApiListingResource.

To get around this, I basically had to supply RestEasy with a thread local ServletContext myself, using a Jax-rs ContainerRequestFilter. The full project source is here: https://github.com/aosullivan/springboot-resteasy-swagger

The key Filter is as follows:

@ConditionalOnWebApplication
@Component
@Provider
@ServerInterceptor
public class ResteasyServletContext implements ContainerRequestFilter {

    @Inject 
    ServletContext sc;
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
		ResteasyProviderFactory.getContextDataMap().put(ServletContext.class, sc);
    }

}

Following this, everything seemed to work, and I could bring up swagger-ui and access the Jax-rs endpoints through it.

This condition is needed to support the spring SpringJUnit4ClassRunner, if you use that, or other contexts where the web container is not actually instantiated:

@ConditionalOnWebApplication

I get CORS issues when accessing swagger-ui from Chrome, which I can get around using the Chrome CORS plugin, https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en.  This didn’t happen under Jersey.

Configuring DateFormat with Spring Boot and RestEasy

This is so finely tuned, I pity the fool who has to make it work (me).

A couple of things to check. First, ensure you Application (with main method) is in a package a level above components to be autowired, especially the @Producer. Also, ensure it has these annotations:

@ComponentScan
@SpringBootApplication

Second, create a configuration type which is both a @Provider and a @Component.

Ensure that class imports of configuration classes such as ObjectMap are only from the package com.fasterxml.jackson. Don’t import anything from Jackson1, org.codehaus.jackson. Don’t mix Jackson1 and 2 and keep 1 out of the implementation.

I’m including the imports so there is no ambiguity about this.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaMapper;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.springframework.stereotype.Component;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

@Provider
@Component
public class DateObjectMapperProvider implements ContextResolver<ObjectMapper> {
    private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public ObjectMapper getContext(Class<?> type) {
        dateFormat.setLenient(false);
        dateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
        
        final ObjectMapper result = new JodaMapper();
        result.setDateFormat(dateFormat);
        return result;
    }

}

Maven dependencies, including Swagger. I have not included Spring.


<swagger.version>1.3.12</swagger.version>
<resteasy.version>3.0.9.Final</resteasy.version>
...
                         <dependency>
				<groupId>org.jboss.resteasy</groupId>
				<artifactId>resteasy-spring</artifactId>
				<version>${resteasy.version}</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.resteasy</groupId>
				<artifactId>resteasy-jackson2-provider</artifactId>
				<version>${resteasy.version}</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.resteasy</groupId>
				<artifactId>resteasy-validator-provider-11</artifactId>
				<version>${resteasy.version}</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.resteasy</groupId>
				<artifactId>resteasy-multipart-provider</artifactId>
				<version>${resteasy.version}</version>
			</dependency>
			<dependency>
				<groupId>org.jboss.resteasy</groupId>
				<artifactId>resteasy-jaxb-provider</artifactId>
				<version>${resteasy.version}</version>
			</dependency>

			<dependency>
				<groupId>com.wordnik</groupId>
				<artifactId>swagger-jaxrs_2.10</artifactId>
				<version>${swagger.version}</version>
			</dependency>
			<dependency>
				<groupId>com.wordnik</groupId>
				<artifactId>swagger-core_2.10</artifactId>
				<version>${swagger.version}</version>
			</dependency>
			
			<dependency>
				<groupId>com.mangofactory</groupId>
				<artifactId>swagger-springmvc</artifactId>
				<version>1.0.2</version>
			</dependency>
	
			<dependency>
				<groupId>org.ajar</groupId>
				<artifactId>swagger-spring-mvc-ui</artifactId>
				<version>0.4</version>
			</dependency>			

		<dependency>
		<groupId>com.fasterxml.jackson.datatype</groupId>
			<artifactId>jackson-datatype-joda</artifactId>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
		</dependency>

Set it up this way and you should be golden.

Concise List Creation in Java

I came across some interesting code today to set up a list of objects in Java that I thought was worth highlighting for its conciseness.

List<ServerAddress> list = new ArrayList<>() {{
        add(new ServerAddress("127.0.0.1", 27017));
        add(new ServerAddress("127.0.0.1", 27027));
        add(new ServerAddress("127.0.0.1", 27037));
    }
}

Essentially we subclass a new list instance as an anonymous inner class with an initializer block (since, being anonymous, it cannot have a constructor). In that initializer, we call add on the list for each item we wish to add. I thought this was a good, concise way of creating the populated list, allowing fluent API style without the need for external libraries like op4j.