This repository holds tyhe files for the OpenLMIS Cold Chain Equipment Service. OpenLMIS 3.x Independent Service.
- Docker 1.11+
- Docker Compose 1.6+
All other dependencies, such as Java, are delivered automatically via the Docker image. It is unnecessary to install them locally to run the service, though often helpful to do so for the sake of development. See the Tech section of openlmis/dev for a list of these optional dependencies.
- Fork/clone this repository from GitHub.
git clone https://github.com/OpenLMIS/openlmis-cce.git <openlmis-your-service-name>
- Respectively change all instances of
openlmis-cce
andcce
within the project toopenlmis-your-service-name
andyour-service-name
. - Change all instances of the default version number ("0.0.1") in the project to your version number.
- Change the gradle build file to add any dependencies (e.g. JPA, PostgreSQL).
- Add Java code to the template.
- Add an environment file called
.env
to the root folder of the project, with the required project settings and credentials. For a starter environment file, you can use this one. e.g.
cd <openlmis-your-service-name>
curl -o .env -L https://raw.githubusercontent.com/OpenLMIS/openlmis-ref-distro/master/settings-sample.env
- Develop w/ Docker by running
docker-compose run --service-ports <your-service-name>
. See Developing w/ Docker. - You should now be in an interactive shell inside the newly created development
environment, start the Service with:
gradle bootRun
- Go to
http://<yourDockerIPAddress>:8080/
to see the service name and version. Note that you can determine yourDockerIPAddress by runningdocker-machine ip
. - Go to
http://<yourDockerIPAddress>:8080/api/
to see the APIs.
Gradle is our usual build tool. This template includes common tasks that most Services will find useful:
clean
to remove build artifactsbuild
to build all source.build
, after building sources, also runs unit tests. Build will be successful only if all tests pass.generateMigration -PmigrationName=<yourMigrationName>
to create a "blank" database migration file. The file will be generated undersrc/main/resources/db/migration
. Put your migration SQL into it.test
to run unit testsintegrationTest
to run integration testssonarqube
to execute the SonarQube analysis.
The test results are shown in the console.
While Gradle is our usual build tool, OpenLMIS v3+ is a collection of Independent Services where each Gradle build produces 1 Service. To help work with these Services, we use Docker to develop, build and publish these.
OpenLMIS utilizes Docker to help with development, building, publishing and deployment of OpenLMIS Services. This helps keep development to deployment environments clean, consistent and reproducible and therefore using Docker is recommended for all OpenLMIS projects.
To enable development in Docker, OpenLMIS publishes a couple Docker Images:
- openlmis/dev - for Service development. Includes the JDK & Gradle plus common build tools.
- openlmis/postgres - for quickly standing up a shared PostgreSQL DB
In addition to these Images, each Service includes Docker Compose instructions to:
- standup a development environment (run Gradle)
- build a lean image of itself suitable for deployment
- publish its deployment image to a Docker Repository
Launches into shell with Gradle & JDK available suitable for building Service. PostgreSQL connected suitable for testing. If you run the Service, it should be available on port 8080.
Before starting the development environment, make sure you have a .env
file as outlined in the
Quick Start instructions.
> docker-compose run --service-ports <your-service-name>
$ gradle clean build
$ gradle bootRun
The specialized docker-compose.builder.yml is geared toward CI and build servers for automated building, testing and docker image generation of the service.
Before building the deployment image, make sure you have a .env
file as outlined in the Quick
Start instructions.
> docker-compose -f docker-compose.builder.yml run builder
> docker-compose -f docker-compose.builder.yml build image
TODO
A brief overview of the purpose behind each docker related file
Dockerfile
: build a deployment ready image of this service suitable for publishing.docker-compose.yml
: base docker-compose file. Defines the basic composition from the perspective of working on this singular vertical service. These aren't expected to be used in the composition of the Reference Distribution.docker-compose.override.yml
: extends thedocker-compose.yml
base definition to provide for the normal usage of docker-compose inside of a single Service: building a development environment. Wires this Service together with a DB for testing, a gradle cache volume and maps tomcat's port directly to the host. More on how this file works: https://docs.docker.com/compose/extends/docker-compose.builder.yml
: an alternative docker-compose file suitable for CI type of environments to test & build this Service and generate a publishable/deployment ready Image of the service.docker-compose.prod.yml
: Docker-compose file suitable for production. Contains nginx-proxy image and virtual host configuration of each service.
- Enter desired
VIRTUAL_HOST
for each service in thedocker-compose.prod.yml
file. - Start up containers
> docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
- The application should be available at port 80.
Logging is implemented using SLF4J in the code, Logback in Spring Boot, and routed to an external Syslog server. There is a default configuration XML (logback.xml) in the resources folder. To configure the log level for the development environment, simply modify the logback.xml to suit your needs.
Configuring log level for a production environment is a bit more complex, as the code has already been packaged into a Spring Boot jar file. However, the default log configuration XML can be overridden by setting the Spring Boot logging.config property to an external logback.xml when the jar is executed. The container needs to be run with a JAVA_OPTS environment variable set to a logback.xml location, and with a volume with the logback.xml mounted to that location. Some docker compose instructions have been provided to demonstrate this.
- Build the deployment image. (See Build Deployment Image)
- Get a logback.xml file and modify it to suit your log level configuration.
- Modify
docker-compose.builder.yml
to point to your logback.xml location. a. Undervolumes
, where it shows two logback.xml locations separated by a colon, change the location before the colon. - Run the command below.
> docker-compose -f docker-compose.builder.yml run --service-ports cce
Internationalization is implemented by the definition of two beans found in the Application
class, localeResolver and messageSource. (Alternatively, they could be defined in an application
context XML file.) The localeResolver determines the locale, using a cookie named lang
in the
request, with en
(for English) as the default. The messageSource determines where to find the
message files.
Note there is a custom message source interface, ExposedMessageSource, with a corresponding class ExposedMessageSourceImpl. These provide a method to get all the messages in a locale-specific message file.
See the MessageController class for examples on how to get messages.
Additionally, Transifex has been integrated into the development and
build process. In order to sync with the project's resources in Transifex, you must provide
values for the following keys: TRANSIFEX_USER
, TRANSIFEX_PASSWORD
.
For the development environment in Docker, you can sync with Transifex by running the
sync_transifex.sh
script. This will upload your source messages file to the Transifex project
and download translated messages files.
The build process has syncing with Transifex seamlessly built-in.
To debug the Spring Boot application, use the --debug-jvm
option.
$ gradle bootRun --debug-jvm
This will enable debugging for the application, listening on port 5005, which the container has exposed. Note that the process starts suspended, so the application will not start up until the debugger has connected.
If the service is being deployed against a database which has data, and that data has been modified outside of the operation of the Service (or sometimes when upgrading this Service), you'll want to run the Service at least once with the following profile:
spring_profiles_active=refresh-db
This will ensure that the database works well with this Service.
An audit log is one of the most effective forms of tracking temporal information. Any time something significant happens you write some record indicating what happened and when it happened.
spring_profiles_active=init-audit-log
This will enable audit logging.
By default when this service is started, it will clean its schema in the database before migrating
it. This is meant for use during the normal development cycle. For production data, this obviously
is not desired as it would remove all of the production data. To change the default clean & migrate
behavior to just be a migrate behavior (which is still desired for production use), we use a Spring
Profile named production
. To use this profile, it must be marked as Active. The easiest way to
do so is to add to the .env file:
spring_profiles_active=production
This will set the similarly named environment variable and limit the profile in use. The expected use-case for this is when this service is deployed through the Reference Distribution.
A basic set of demo data is included with this service, defined under
./src/main/resources/db/demo-data/
. This data may be optionally loaded by using the demo-data
Spring Profile. Setting this profile may be done by setting the spring.profiles.active
environment variable.
When building locally from the development environment, you may run:
$ export spring_profiles_active=demo-data
$ gradle bootRun
To see how to set environment variables through Docker Compose, see the Reference Distribution
The following environment variables are common to our services. They can be set either directly in compose files for images or provided as an environment file. See docker-compose.yml in the reference distribution for example usage. Also take a look at the sample .env file we provide.
- BASE_URL - The base url of the OpenLMIS distribution. Will be used in generated links pointing to this distribution, as well as for communication between services. Each service should communicate with others using BASE_URL as the base in order to avoid direct communication, which might not work in more complex deployments. Services should also use this variable if they wish to generate a link to the application. This should be an url, for example: https://example.openlmis.org
- VIRTUAL_HOST - This is used by the nginx server as the virtual host under which the services are made avialble. This should be a host, for example: example.openlmis.org
- CONSUL_HOST - Identifies the IP address or DNS name of the Consul server. Set this to the host or IP under which the distribution is available and Consul listens for connections. Services should register with Consul under this address. This should be a host or an IP, for example 8.8.8.8.
- CONSUL_PORT - The port used by the Consul server - services should use this port to register with Consul. This should be a port number, for example 8500. 8500 is used by default.
- REQUIRE_SSL - Whether HTTPS is required. If set to
true
, nginx will redirect all incoming HTTP connections to HTTPS. By default SSL will not be required - either leave it blank or set tofalse
if you wish to allow HTTP connections. - LOCALE - Default localized system language. It will be applied to all running services, if this variable is missing default "en" value will be used.
These variables are used by services for their connection to the database (none of these have defaults):
- DATABASE_URL - The JDBC url under which the database is accessible. Our services use
jdbc:postgresql://db:5432/open_lmis
for connecting to the PostgreSQL database running in a container. - POSTGRES_USER - The username of the database user that the services should use. This variable is also used by our PostgreSQL container to create a user.
- POSTGRES_PASSWORD - The password of the database user that the services should use. This variable is also used by our PostgreSQL container to create a user.
These variables are used by our builds in order to integrate with the Transifex translation management system:
- TRANSIFEX_USER - The username to use with Transifex for updating translations.
- TRANSIFEX_PASSWORD - The password to use with Transifex for updating translations.