Thanks to the magic of Docker Compose, you can put this docker-compose.yml
file into a folder:
version: "2.1"
services:
openmrs-referenceapplication-mysql:
restart: "always"
image: mysql:5.6
command: "mysqld --character-set-server=utf8 --collation-server=utf8_general_ci"
environment:
MYSQL_DATABASE: ${MYSQL_DB:-openmrs}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Admin123}
MYSQL_USER: ${MYSQL_USER:-openmrs}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Admin123}
healthcheck:
test: "exit 0"
volumes:
# - ./dbdump:/docker-entrypoint-initdb.d #uncomment this if you need to use a backup sql to initialize the databse
- openmrs-referenceapplication-mysql-data:/var/lib/mysql
openmrs-referenceapplication:
restart: "always"
image: openmrs/openmrs-reference-application-distro:demo
# image: openmrs/openmrs-reference-application-distro:demo
depends_on:
- openmrs-referenceapplication-mysql
ports:
- "127.0.0.1:8080:8080" #when using without nginx use 8080:8080 instead
environment:
DB_DATABASE: ${MYSQL_DB:-openmrs}
DB_HOST: openmrs-referenceapplication-mysql
DB_USERNAME: ${MYSQL_USER:-openmrs}
DB_PASSWORD: ${MYSQL_PASSWORD:-Admin123}
DB_CREATE_TABLES: "true"
DB_AUTO_UPDATE: "true"
MODULE_WEB_ADMIN: "true"
_JAVA_OPTIONS: -Xmx1g -Xms1g # change this depending on the server config
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/openmrs/"]
timeout: 20s
volumes:
- openmrs-referenceapplication-data:/usr/local/tomcat/.OpenMRS/
- /usr/local/tomcat/.OpenMRS/modules/ # do not store modules in data
- /usr/local/tomcat/.OpenMRS/owa/ # do not store owa in data
volumes:
openmrs-referenceapplication-mysql-data:
openmrs-referenceapplication-data:
and you can have a demo OpenMRS running at http://localhost:8080 with a single comand:
$ docker-compose up -d
The first time you bring up OpenMRS, it can take while for the database to be initialized. In my case, it takes at least 4-5 minutes each time it’s started.
To improve startup time from a given state, I created a couple bash scripts, one to backup named values and another to restore them:
backup-volumes.sh
#!/bin/bash
docker-compose pause
dirname=${PWD##*/}
for nv in `docker volume ls -q`
do
if [[ $nv = ${dirname}* ]]; then
f=${nv//${dirname}_/}
echo -n "Backing up $f ..."
docker run -it --rm \
-v $nv:/data -v $PWD:/backup alpine \
tar -cjf /backup/$f.tar.bz2 -C /data ./
echo "done"
fi
done
docker-compose unpause
restore-volumes.sh
#!/bin/bash
dirname=${PWD##*/}
for f in `ls *.tar.bz2`
do
nv="${dirname}_${f%.tar.bz2}"
echo -n "Restoring $nv ..."
docker run -it --rm \
-v $nv:/data -v $PWD:/backup alpine \
sh -c "rm -rf /data/* /data/..?* /data/.[!.]* ; tar -C /data/ -xjf /backup/$f"
echo "done"
done
Using the backup script to take a “snapshot” of OpenMRS, I’m able to restore that state with the restore script and start OpenMRS in about have the time (~2 minutes).
./backup-volumes.sh
docker-compose down -v
)./restore-volumes.sh
docker-compose
(not docker deploy
), which prepends named volumes with the current directory name..tar.bz
. If you are working in a local copy of a git repo, you might want to add *.tar.bz
to your .gitignore
… and you shouldn’t create any other archives ending in .tar.bz
in the project folder if you don’t want the restore script to turn them into named volumes.Just got back from a wonderful trip to South Dakota with Lorrie. I wanted to see Mount Rushmore before it became this:
Today, I was playing with Markdown in a README.md file for a repository and thought it’d be helpful if I could see my changes in real time (this was a junk repo I was going to delete, so I wasn’t worried about a bunch of commits). Just thought I’d blog this for my own future reference.
Create a script to commit changes and reload Safari…
#!/bin/bash
# Commit changes
git add README.md
git commit -m "formatting"
git push
# Reload Safari
osascript -e 'tell first window of application "Safari" to do JavaScript "window.location.reload(true)" in current tab'
Install fswatch (Mac’s version of inotifywait), a tool to monitor for changes to a file or folder.
brew install fswatch
With the following command, any change to our file will get committed and the page in Safari will be reloaded.
fswatch -o README.md | xargs -n1 ./update.sh
I have always loved Chuck Swindoll‘s famous quote:
“Life is 10% what happens to you and 90% of how you react to it.”
It underscores how so much in life depends on perspective. When I started working in clinic, I was stressed by crunch of chart reviews, seeing patients, answering pages, and writing notes while constantly feeling rushed and falling behind. I would leave clinic exhausted with a hard knot between by shoulders. Then one clinic day, I decided to try an experiment. I would work as effectively as I could, but I would consciously avoid worrying about the chaos around me. Whether or not the charts stacked up, I was going to see people as efficiently and effectively as I could, so worrying about the stack of charts wasn’t going to help. Surprisingly, I accomplished the same amount of work that day (in fact, nothing changed about my clinic whatsoever), but I left clinic completely relaxed. I realized simply changing my point of view could massively reduce my level of stress (and increase happiness).
Today, I listened to a Work In Progress talk from Dr. Rich Frankel at Regenstrief and he mentioned Judy Brown’s “Cone in the box.” What a wonderful lesson in perspective: two people looking at the same object and one sees a circle while the other sees a triangle. Who’s right? Are they both right? Are they both wrong? Not surprisingly, it depends on your perspective.
The next time you find yourself arguing with someone about whether it’s a circle or a triangle, take a moment to realize you might both be right (or wrong, depending on your perspective).
“We don’t see things as they are, we see them as we are.” –Anaïs Nin
For another example of how your perspective can change what you see, wait for a large moon on the horizon and try the One-Eyed Pinky Trick. 🙂
I got an email this morning from Luis in Düsseldorf about a suggestion to improve OpenMRS. I help Luis with his ticket and bring it to the attention of the OpenMRS Google Code-In team. Teenagers from Cameroon, Uruguay, and New Jersey discuss the ticket with a mentor in Indianapolis. No doubt, one of these bright young students will submit a pull request soon.
It’s a small, wonderful world full of awesome people!
Another typical day in the OpenMRS community… 🙂
At the recent OpenMRS Worldwide Summit #OMRS15, I was helping out with the Saptarshi’s introductory tutorial and realized that the OpenMRS Standalone requires Java 7, meaning that it fails to run on Java 8. Yikes! But my Mac runs Java 8. How do I get Java 7 on my laptop without making a mess of things?
jenv to the rescue! jenv provides an easy way to manage multiple Java versions. Not only can you easily switch between Java versions, but you can configure different folders to run specific versions of Java. So, for example, you can run Java 7 for the OpenMRS Standalone and run Java 8 everywhere else.
Step zero. Install Homebrew. I already had this installed. I used to use Macports to install utilities on my Mac, but it was fairly invasive. Homebrew installs most everything under your user account, so it doesn’t mess with Mac’s view of the world and rarely, if ever, requires the use of sudo.
Step one. Install jenv.
brew install jenv
Step two. Install Java 7.
Grab the latest version of Java 7 SDK from Oracle’s Java 7 archive. For me, this meant navigating to the Java SE Development Kit 7u80 downloads, accepting the license agreement, and then downloading and installing from the dmg package for Mac OS X x64.
Step three. Tell jenv about Java 7.
jenv add /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/
If your version number differs, then your command may differ slightly. You can always navigate into /Library/Java/JavaVirtualMachines/ to find your installed version folders.
Done!
Now you can navigate into your OpenMRS Standalone folder, set the preferred Java version with a command like:
jenv local oracle64-1.7.0.80
and then execute the standalone with:
jenv exec java -jar openmrs-standalone.jar
I recently decided to try switching from Chrome to Safari for a while… to see if it might buy me a little more battery life on my aging MacBook Pro. One of the immediate drawbacks I discovered was realizing how accustomed I had become to the Tab Stack extension for Chrome. It’s a simple workaround for MRU (most recently used) tab ordering that moves the active tab to the left after a brief delay (the delays lets you scan through tabs without re-ordering them). It’s a bit hacky and I’m sure a lot of people wouldn’t care for the approach, but I’m used to it and immediately noticed its absence in Safari.
I googled around and didn’t find an equivalent extension for Safari… so I made one and submitted it to Apple’s gallery. I’ve added an extra hack to mitigate Safari’s insistence on clearing the address bar when tabs are moved (move new tabs immediately) as a version 1.1.
I use Citrix XenApp to connect to a virtual desktop for hospital apps and, being a keyboard junkie, I prefer to have a hotkey to logout from the Citrix session on my Mac. I keep having to reinvent this, so I’m “microblogging” it for future me.
Right-click on the desktop and create a shortcut
From then on (until the desktop gets reset), pressing ⌘⌥L will logout of Citrix XenApp.
Can you picture a world without tablets, desktops and laptops? It’s only a matter of time.
SanDisk has introduced a 200 GB microSD card. That’s 200 GB in a mere 15x11mm package. With processors like Qualcomm’s Snapdragon 810 and beyond, it’s not hard to imagine reaching a point where your phone can provide all the computing power you need. The phone has several advantages:
Tablets, laptops and desktops (as we know them today) disappear altogether, once your phone, backed by the unlimited resources of the cloud, can provide all the computing power you need. All that is missing are the interfaces to that computing power. Tablets need only provide the convenience of a touch screen interface. Laptops and desktops can be replace with commodity keyboards and monitors, drawing all the computing experience from your phone. I just hope I can get some sleep when the two-finger typist behind me on the plane is using their tray table as a keyboard.
My wife and I take a week vacation around July 4th each year to relax at our cottage in Michigan. Last year, I dipped my toes back into carpentry with mentorship from a kind neighbor and replaced our wood platform. This year I decided it was time to replace our old picnic table. I wanted an octagonal picnic table and settled on plans from Woodcraft Magazine Issue 58: April/May 2014 by Bill Sands (downloaded from Sawtooth Ideas). The deciding factor was Laney Shaughnessy‘s four part Build an Octagon Picnic Table YouTube series detailing each step of the plans. Menards had the cedar wood (16 8-foot 2x6s, 8 8-foot 2x4s, and one 8-foot 2×2), sawhorses, exterior screws, back saw, chisel, pocket hole jig, hand router + 1/4-inch roundover bit, sander, and wood glue. My neighbor had a mitre saw and a cozy garage that helped when it was raining. It took most of the week and I must’ve watched Laney’s videos a few dozen times in the process for guidance and encouragement, but – thanks to Bill Sands’ great plans and Laney Shaughnessy’s awesome videos – I was able to make a nice new cedar octagonal picnic table from scratch: