Tuesday, May 11, 2021

How to get headless chromium to launch from a pipeline using ubi8 image

My goal was to be able to run unit tests from a pipeline for the Angular's "Tour of Heroes" tutorial application which use Karma Jasmine framework. In this case the pipeline was built using Tekton to deploy to a Red Hat OpenShift cluster. 

Step 1: Change Karma Browser Configuration to use Headless Chromium

Launching the unit tests locally was not an issue because I had Chrome installed locally, but in order to get this to work in a pipeline we need to switch to a Headless browser configuration. This can be accomplished by updating karma.conf.js as follows. This configuration prunes all interactivity, not all of these settings are necessary, but these will work both locally and from the pipeline task:

   reporters: ['progress'],

    port: 9876,

    colors: true,

    logLevel: config.LOG_INFO,

    autoWatch: false,

    browserNoActivityTimeout: 30000,

    browsers: ['ChromiumHeadlessNoSandbox'],

    customLaunchers: {

      ChromiumHeadlessNoSandbox: {

          base: 'ChromiumHeadless',

          flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-translate', '--disable-extensions', '--remote-debugging-port=9223']

      }

    },    

    singleRun: true,

    restartOnFileChange: false


Step 2: Add Puppeteer to the project

With these changes the local tests were running headless successfully, however they were still failing because they still need a browser binary downloaded. Our pipeline was using the ubi8/nodejs-12 image to run npm tasks. All of the npm tasks (e.g. install, lint, build) were running successfully, except for the test task. One easy solution would have been to install chromium into a modified image using a Dockerfile with ubi8/nodejs-12 as the base. Unfortunately the chrome download url was not whitelisted from the pipeline server and could not go that route. 

This led us to using puppeteer. Puppeteer is a node library which allows you to test using headless chromium. One of the features that we needed is that it downloads the chromium binary.

Step 2.1: Add puppeteer as a dev dependency

Puppeteer can be easily added as a development dependency by adding it to package.json within devDependencies section:

   "puppeteer": "^9.1.0",

Step 2.2: Export download host for puppeteer

This may not be an issue locally, but in case npm install gets stuck downloading puppeteer, this can be addressed by adding this download host environment variable prior to running npm install (ensure this is added to the pipeline task as well):


      export PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors 


Step 2.3: Update karma configuration to use puppeteer

Update karma.conf.js with the following changes:

  • Require puppeteer
  • Export the path to the Chromium executable
  • Wait for chromium to launch (i.e. to ensure it is downloaded if applicable)

 const puppeteer = require('puppeteer');

  process.env.CHROMIUM_BIN = puppeteer.executablePath();

  (async () => {

    const browser = await puppeteer.launch({

      args: ['--no-sandbox', '--disable-setuid-sandbox'],

    });

  })();

Step 3: Add required Linux libraries to ubi8 image

At this point npm test should execute successfully with puppeteer and headless chromium. However tests were failing in our pipeline due to missing Linux libraries in the ubi8 required to run chromium:

06 05 2021 20:58:47.098:ERROR [launcher]: Cannot start ChromiumHeadless /workspace/source/node_modules/puppeteer/.local-chromium/linux-869685/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

To troubleshoot this error the following commands were instrumental:

Command #1 (from troubleshooting puppeteer)

This command will help troubleshoot which libraries are missing in one shot versus adding one library at a time and getting a different error. You can get the path to local-chromium by echoing the output of puppeteer.executablePath() - it should be very similar to the one below except for the linux version number:

ldd /workspace/source/node_modules/puppeteer/.local-chromium/linux-869685/chrome-linux/chrome | grep not

Command #2 (from troubleshooting puppeteer)

The second command that was helpful was to run yum whatprovides on each missing library from the Dockerfile building the custom image. The only caveat is that in a few cases what provides resolved to the i686 library and that did not provide the missing library instead I had to switch to the x86_64 library version.

yum what provides libnss3.so

Magic Dockerfile

The hardest part of this task was to arrive to the correct Dockerfile. After iterating through the commands above, we arrived to the right dockerfile what allowed Puppeteer running headless chromium successfully:

FROM registry.access.redhat.com/ubi8/nodejs-12:latest

USER root

RUN yum install -y alsa-lib.x86_64 atk.x86_64 cups-libs.x86_64 gtk3.x86_64 \

    libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 \

    libXext.x86_64 libXi.x86_64 libXrandr.x86_64 libXScrnSaver.x86_64 \

    libXtst.x86_64 pango.x86_64 xorg-x11-fonts-Type1 libdrm-2.4.101-1.el8.x86_64 \

    mesa-libgbm-20.1.4-1.el8.x86_64 libxshmfence-1.3-2.el8.x86_64 nss.i686 \

    && yum update -y && yum clean all 

USER 1001

Hopefully this guides saves some time for others trying to get this to work on a ubi8 image!



Thursday, May 16, 2019

Spring Integration demo for exposing a SOAP Web Service which consumes another Web Service

Even in 2019, we often still need to develop SOAP based web services due to the need to integrate with legacy applications still using them. It was hard to find code samples that use Spring Integration with Java DSL using Spring Boot to expose/consume SOAP based web services. I put together an example which uses all of the above:
  1. initial branch shows an initial implementation of a web service exposed using spring-ws, Spring Boot and Java DSL. This was loosely based on the "Producing a SOAP web service" getting started guide.
  2. inboundgateway branch takes the initial branch and converts it to using Spring Integration classes (i.e. MarshallingWebServiceInboundGateway and MessageChannel). Credit to tomask79's spring boot web service integration repo which was one of few sample codes I found to expose a SOAP service using Spring Integration with Java DSL. In particular this commit will show you how easy it is to go from Spring-WS to a Spring Integration implementation.
  3. outboundgateway branch introduces a MarshallingWebServiceOutboundGateway to call into another SOAP web service to get order details. It also introduces the use of @EnableIntegrationGraphController annotation to build a visualization of the flow using spring-flow-si

The visualization tool output is fairly impressive:


However, I'm not convinced Spring Integration is the best fit for this particular use case, i.e. integration flows primarily between web services and some JMS services. Here are some of the things I did not like:
  1. Code flow becomes hard to follow. Flows are connected primarily via channels. I introduced a ChannelNames class with constants to make it easier to follow the flow, but even with this, I had to find usages of the constant and then navigate to those classes.
  2. The request/response web service methods had to be decoupled into a "request" (request channel) and "response" (reply channel) method. I posted this question in StackOverflow and even though this method could be combined using a MessageGateway, it is not the ideal way of implementing this with Spring Integration. Even with the diagram above, you cannot tell that orderInboundGateway is a 2-way flow, instead it appears a one-way flow.
Don't get me wrong, I liked several aspects of Spring Integration and I would find it useful for other scenarios, but it seems for this one, the complexity introduced outweighs some of the benefits. 

Please chime in the comments if you've successfully implemented similar scenarios with Spring Integration!

Saturday, December 03, 2016

Can running help heal Plantar Fasciitis?

PF stands for Plantar Fasciitis, but in my opinion it should just be called "Pain in the Foot" because that's really what it is, just an annoying pain in the foot that won't go away for months. I hope you never have it, but if you do, here are some helpful tips and suggestions to help you heal and get better soon!

How did I get it?

It is relatively easy to self diagnose plantar fasciitis. If after reading common symptoms, you feel like "that's exactly what I have!", then you most likely have plantar fasciitis: "stabbing pain (in the foot) that usually occurs with your very first steps in the morning. Once your foot limbers up, the pain of plantar fasciitis normally decreases, but it may return after long periods of standing or after getting up from a seated position."

For me one of my burning questions was how did I get it? and how do I prevent from making it worse and prevent from getting it again after healing? I'm not exactly sure how I got it, but I know it got noticeably worse after returning from a 2 week vacation. I am a frequent runner. I run 4-6 days a week and I try very hard to not go over 3 days without running. In this last vacation I went 7 days without running. I think I had symptoms before my vacation, I just did not realize that it was plantar fasciitis because I never had it before. Upon returning from vacation as I attempted to get back to my normal running routine, it was pretty evident I had plantar fasciitis. I only had it on my right foot, but I've heard is possible to get it on both feet at the same time (ouch!).

What I tried?

The first thing I tried based on the fact that running is a common cause of plantar fasciitis was to stop running for a few days. That didn't help, and in fact it seemed to make it worse. When I told a runner friend about my problem, he told me he had it before and that I needed to do stretching exercises to strengthen my fascia. I think I tried almost everything that was suggested to me. From my experience the first step is to get the pain under control, then focus on what will heal you in the long term. Here is a summary of the things I tried and that helped me the most:

  • Icing
    • This was one of the recommendations from my orthopedist and also from a fellow runner that went through this. Icing helps specially with relief. I learned that you don't necessarily have to do it right after running, you can do it at the end of the day, but you should do it at least 5 to 20 minutes per day.
  • Ibuprofen
    • Pain killers are a must for relief. Usually 1-2 per day was enough for me, but the goal is gradually wean off from taking them, so that you know the pain is going away because you're healing. Keeping a log can help you track improvement (e.g. level of discomfort and whether you took pain killers that day).
  • Heel cups
    • I was a bit skeptic about this, but a runner friend recommended it as well as my orthopedist. I was specifically recommended these ones by Dr. Scholl's Pain Relief Orthotics for Heel. You can find them at Target and most pharmacy stores and easily identify them by the "Plantar Fasciitis" label on them. I ended up buying 2-3 pairs and just putting them on the shoes I wore the most. My friend recommended me using them on my running shoes as well, which I tried, but abandoned after a few days as it felt awkward while running.
  • Peppermint oil
    • This was probably the most unconventional thing I tried from "typical" PF remedies. Specifically I tried Doterra oils. They have a product call Deepblue which is special for muscular pain relief, but the most effective for relief for me was a mix of their peppermint oil with lavender oil (one drop of each mixed with fractionated coconut oil).
  • Stretching exercises.
    • This helped me heal the most, although not immediately. The stretch exercise I would recommend the most is stretching your calf by leaning towards a wall or post. This is an exercise you should be doing as a runner anyway, both before and after running, but you can also do this throughout the day. The other 2 exercises I recommend are shown on this picture: pulling your toes towards you and picking up a towel with your toes.

  • Foot Rolling exercises
    • I first tried a foot massage roller, however I wouldn't recommend buying one unless you already have one. Instead what worked best for me was putting a bottle of water on the freezer, and then use that for rolling your foot. This way you kill two birds with one stone: you are effectively icing while rolling your foot at the same time!
  • Night splint
    • I was hesitant to try this, but my orthopedist recommended it. What the night splint helps with is to keep your feet from stretching over night which is what triggers the morning pain. The night splint keeps your foot at a 90 degree angle which is extremely hard to maintain consciously once you fall asleep. Using the splint can be very uncomfortable at first, but you will gradually get used to it. The Futuro Night Plantar Fasciitis is what I used.
  • Reduce pace/long distance running
    • This should be an obvious one, but "your mileage may vary" on this one. For me this meant going from a 9 min/mi pace to about 10 min/mi and from 30+ miles/week to 20+ miles/week. The great news is that I didn't have to stop running altogether and in fact going multiple days without running seemed to make things worse. This also meant that I had to compromise from running my fifth consecutive Pittsburgh Full Marathon. I could have probably done it, but did not want to risk getting worse and opted for running the Half Marathon instead, which ended up being a wise decision.
  • See a doctor (specially if you are not getting better)
    • When I reached out to my primary doctor he sent me a list of exercises to try first and asked me to visit him if I didn't get better. Since I wasn't getting better I decided to see an orthopedist in my area. The orthopedist did an x-ray to rule out I did not have a bone fracture, which I didn't. Other than that, there was not much value in seeing the doctor. He did not even asked how I got it. I had to volunteer the fact that I was a runner and even then he did not ask how much/frequent I ran. His estimate is that it would take me 2 months to heal, he was off by 3 months, but I did follow on a couple of his recommendations (night splint and icing/stretching more frequently), which eventually helped.
  • Try changing running shoes
    • After not getting better, I tried this suggestion and went into a running store for a shoe fitting, which I had never done before. This turned out to be a great suggestion. If you've read some of my earlier posts you'll find out that I'm a big proponent of minimalist running shoes. For the past few years I've been running with the same model of running shoes: Nike Free 3.0 (different generations of the 3.0 model), which are almost zero drop minimalist shoes from Nike. I tried multiple shoes and the ones that fit the best by far were the Mizuno Wave Rider 18. These shoes have a much ticker sole that I would have ever considered, but they have much better support and really liked how they feel when running and still use them even after healing.
  • (Lots of) Patience and keeping a log
    • Be (very) patient. There are days in which you feel you're doing better and then for no obvious reason you start feeling worse again. That's what bothered me the most about this. I could take a couple days of rest and not feel any better. I also went for a few long runs an felt great. Sometimes there was no obvious correlation into how I felt and what I tried. I think keeping a daily log would have helped. In this log you should track how you felt that day, whether you took pain killers how much you ran and any activities (other than running) you performed. There could be a lot of variation from day to day, but the goal is to feel better each week while still doing some activity and reducing the amount of pain killers you take.

How can you tell you're getting better?

Another burning question was how to tell I was actually getting better and whether I would ever get back to "normal". Healing completely takes time, in most cases months. In my case it was about 6 months before I could say I was back to normal. But by month 4, I could say I was mostly healed, i.e. the pain and discomfort was mostly gone, but I could still occasionally feel discomfort and mild pain which was concerning as I was afraid to get worse again. Keeping a running log certainly helps. In my case I use the Nike Running app. During my healing months (Jan-Apr) I was still able to get around 100 miles on average, which is pretty good, but I had to compromise on pace. My average pace gradually improved getting back to normal by April:

  • Jan: 9'59", Feb: 9'54", Mar: 9'24", Apr: 9'01", May: 9'03"




The pain was not completely gone by April. I still remember feeling some discomfort in June when walking barefoot. But by July/August I don't remember having any bad days. For me the ultimate proof that I was healed was to be able to run a marathon again without any pain, which I was able to do on August 28th in Mexico City!




Can running really heal plantar fasciitis? 

Running by itself won't heal you, but it can definitely help heal as long as your don't over do it (by running too much or too fast) and I have empirical evidence to support this. The key to healing PF is by strengthening the fascia. Stretching exercises will help the most with this. This is what is most contradictory about PF. Resting is typically needed to heal muscle injuries. With PF resting too much can actually make the pain worse and resting on its own won't help you heal. Running can be a way to strengthen the fascia, as long as you don't over do it and do it properly (i.e. with a good running form, appropriate running shoes, etc.). Because healing can usually take months, you need to be VERY patient. Do not feel discouraged if you are not improving immediately. The pain and discomfort will eventually go away. Learn to listen to your body and you will gradually learn what can help you the most!