Category Archives for computers

Add mobx to your React project

Mobx helps you manage the state.

I set up mobx to be used as an import to your (functional) components. I do this, rather than using createContext() because the latter one only allows you to use it inside components, not functions.

To set up mobx you’ll need to:

  1. install mobx
  2. create store
  3. configure store and components

In this example, I make use of the function autoStore() in the constructor of the store to save the state to localStorage whenever there is a change to the state.
This makes that state is saved across page-refreshes.

install mobx

Install with:

yarn add mobx mobx-react

create store

Create your store by creating file src/stores/applicationStore.js.

// file src/stores/applicationStore.js
import {action, computed, decorate, observable } from 'mobx'
import autoStore from '../libs/autoStore'

class ApplicationStore {
    greet = 'hello world'

    constructor() {
        // store changes to the state in localStorage
        autoStore(this)
    }

    setGreet(newGreet) {
        this.greet = newGreet
    }
}

decorate(ApplicationStore, {
    greet: observable,

    setGreet: action
})

const store = new ApplicationStore()
export default store

File ./src/libs/autoStore.js takes care of storing the state in localStorage.

// file ./src/libs/autoStore.js
import { toJS, autorun, set } from 'mobx'

export default function (_this) {
  let firstRun = true

  // will run on change
  autorun(() => {
    // on load check if there's an existing store on 
    // localStorage and extend the store
    if (firstRun) {
      const existingStore = window.localStorage.getItem('store')

      if (existingStore) {
        set(_this, JSON.parse(existingStore))
      }
    }

    // from then on serialize and save to localStorage
    const serializedThis = toJS(_this)
    window.localStorage.setItem(
       'store', 
       JSON.stringify(serializedThis)
    )
  })

  firstRun = false
}

configure store and components

Configure your components by wrapping them with the observer() function of mobx.

By doing this, mobx knows whenever something changes that concerns the state.

class component example:

// file ./src/components/greet.js

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import store from '../stores/ApplicationStore'

class Greet extends Component {
  render() {
    return <div>{store.greet}</div>
  }
}

export default observer(Greet)

Functional component example:

// file ./src/components/SayHello.js

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import store from '../stores/ApplicationStore'

const SayHello = () => {
   return <div>{store.greet}</div>
}

export default observer(SayHello)

Resources

Take a look at these pages. They provide useful information about working with mobx.

Caprover doesn’t set MySQL user or database

The problem: one-click app MySQL won’t create database or user

In caprover, formerly captainduckduck, I had the issue that the database and a user were not created by setting environment variables MYSQL_USER and MYSQL_DATABASE.

While building, this message was displayed by Docker:

[Warning] One or more build-args [MYSQL_USER, MYSQL_DATABASE] were not consumed

So appearently, Caprover does not support setting the environment variables for (only?) MySQL anymore.

Selecting MySQL from the oneclick-apps gives you the following options.
Note the absence of setting extra environment variables.

adding a MySQL one-click-app in Caprover

You can only set the root password.

When you start this new app, only the root password is set. If you now set the environment variables, MySQL will not create the database or user. It does this only on first startup, after creating the one-click-app for MySQL.

Solution: supply Dockerfile with the environment variables set

My workaround? Don’t use a one-click app and supply a Dockerfile directly inside Caprover instead.

This is what I used:

  1. Create a new app (and select ‘has persistent data‘)
  2. Open the newly created app by clicking on its name in the Apps overview
  3. Click tab ‘Deployment
  4. Scroll down to ‘Method 4: Deploy plain Dockerfile
  5. Insert and edit the following content and click on ‘Deploy Now
ENV MYSQL_ROOT_PASSWORD=S3cretR00t
ENV MYSQL_DATABASE=dbname_for_app
ENV MYSQL_USER=app_user
ENV MYSQL_PASSWORD=An0therS3cret
adding Dockerfile contents directly into your app

When you deploy your new database app now, the database and the user will be created.

Help your future self: set environment variables after the fact

TIP: after this, you won’t see the Dockerfile contents anymore. So in the future it might be unclear what values were set.
In order to overcome this, set the environment variables as well over at App Configs > Environmental variables:

MYSQL_ROOT_PASSWORD=S3cretR00t
MYSQL_DATABASE=dbname_for_app
MYSQL_USER=app_user
MYSQL_PASSWORD=An0therS3cret
add the environment variables in ‘bulk mode’

That’s it! Now let’s hope we’ll be able to set environment variables in the one-click setup some day soon again.

Bash: use colored text in script

I often use these handy helperfunction to write colored text in my scripts.

# Bash text-colors
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color

function echoRed() {
  TEXT=$1
  printf "${RED}${TEXT}${NC}\n"
}

function echoGreen() {
  TEXT=$1
  printf "${GREEN}${TEXT}${NC}\n"
}

echoGreen "This text is green"
echoRed "This text is red"
echo "This is regular text"

XPATH: search element by text

When I write selenium/kantu end-to-end test I often need to use xpath to find certain elements.
And while it’s definitely not the fastest, searching elements by the text in it, is easy and fast to use. It’s also more descriptive to an untrained eye.

I often refer to this post on StackOverflow which has it written down quite neatly: https://stackoverflow.com/a/2994336

It basically comes down to this:

Literal match (= must match exactly and completely):

//*[text()='match']
//button[text()='Save']

This matches: elements containing (just) the text ‘match’ and a button with (just) the text ‘Save’

Do you need to strip whitespace from texts in elements before you do the matching, then use this:

//*/text()[normalize-space(.)='match']/parent::*

Partly matching:

If it’s ok to be not so strict, use this more loosely matching:

//*[contains(text(),'match')]

This matches texts like: ‘this match comes up‘ and ‘matches this’

If your text must match with words beginning with the text or lines starting or ending with that text, use this xpath 2.0 expression:

//*[matches(text(),'(^|\W)match($|\W)','i')]

Search element with specific class

//*[contains(@class, 'Test')]

PRO-tip: use the inspector to test your xpath.

open the inspector and search (<C-f> or <Command+F>)

Docker opschonen: vrije ruimte terugkrijgen

Als je Docker een tijdje gebruikt hebt, dan kan het zeker lonen om de boel eens op te schonen. Door items te verwijderen die je niet meer nodig hebt kun je een hoop ruimte vrijmaken.

TL;DR

Voer deze commando’s uit om alles op te ruimen

docker images --no-trunc | grep '<none>' \
    | awk '{ print $3 }' \
    | xargs docker rmi
docker ps --filter status=dead --filter status=exited -aq \
  | xargs docker rm -v
docker volume ls -qf dangling=true | xargs docker volume rm
Continue reading

Watch files and execute command upon change

Find yourself executing the same command over and over again after applying changes to certain files? Pywatch will be you best friend!

Meet pywatch: a cool little app that watches directories and files. Whenever it finds a file that changed, it executes the command you provided.

TL;DR

As an example; I use this to build a Docker image whenever I save a change to my Dockerfile.

pywatch "docker build . -t pauledenburg/behat" Dockerfile

Or execute tests whenever I make a change to one of the sourcefiles.

commandToExecute='docker exec -i hangman_app_1 behat -c tests/behat/behat.yml'
find ./tests -name "*.php" -o -name "*.feature" \
  | xargs pywatch "$commandToExecute"

This keeps an eye on all *.php and *.feature files under ./tests.

When one of these files changes, it executes $commandToExecute which resolves to executing behat in a Docker container.

Install

Download the pywatch app from github: https://github.com/cmheisel/pywatch.

Then unzip and install with python.

unzip pywatch-master.zip
cd pywatch-master
sudo python setup.py install

Advanced usage

Nice one: run tests when files change and create a Mac notifier whenever the tests fail.

This way you can keep the tests running in the background and you’ll be notified whenever a test failed.

find src tests -name "*.php" -o -name "*.feature" \
  | xargs pywatch "./dev test phpunit" \
  | grep "([0-9]* failed)" \
  | sed -e 's/.*(\([0-9]* failed\)).*/\1/' \
  | while read failure; 
    do 
      terminal-notifier -message "Test output: $failure" -title "Tests Failed!"
    done

 

 

Set up NGINX as a proxy for your Docker containers

Recently I’m a fan of serving docker containers over serving Virtual Hosts using a webserver.

In order to use regular domainnames without ports, I set up Nginx to receive the request on the domainname and let it forward the request to the relevant Docker container on the specific port it is running on.

Example

Imagine I have a Docker webserver-container hosting my app. It runs on my server exposing port 8080. I use the URL app.pauledenburg.com.

I don’t want people to use http://app.pauledenburg.com:8080 but just the URL without the port

http://app.pauledenburg.com

 .

I use nginx for this:

server {
    listen 80;
    server_name app.pauledenburg.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

And now add SSL to it 🙂

Complete ELK-stack example with Docker

I wanted a quick setup for an Elasticsearch Logstach and Kibana (ELK-)stack to work with. But searching on the internet gave me too many long-winded not really working examples.

That’s why I created this page. Use it to quickly get up-and-running with an ELK-stack of your own.

Create the file docker-compose.yml

# file: docker-compose.yml
version: "3"

services:
  elk:
    image: sebp/elk
    ports:
      - "5601:5601"
      - "9200:9200"
      - "5044:5044"
    environment:
      - MAX_MAP_COUNT=262145
      - ELASTICSEARCH_START=1
      - LOGSTASH_START=1
      - KIBANA_START=1
      - TZ="Europe/Amsterdam"
    volumes:
      - elk-data:/var/lib/elasticsearch

volumes:
  elk-data:

Now start up with docker-compose up -d. That’s it!

5601: endpoint for Kibana
9200: endpoint for elastic search

Add some security

Don’t leave your elastic-search open for everyone.

Add some basic security by adding a .htpasswd config to your webserver.

$ sudo sh -c "echo -n 'myelasticuser:' >> /etc/nginx/.htpasswd"
$ sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
Password:
Verifying - Password:

Add it to your webserver, like nginx.

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /var/www/html;
    index index.html index.htm;

    server_name localhost;

    location / {
        try_files $uri $uri/ =404;
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

Reload nginx.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

$ sudo service nginx reload

Some notes

I chose the Docker image of sebp because he’s got great documentation. Go check it out!

Especially the part with the Frequently Encountered Issues.

There, you’ll see that you’ll:

  • need 4GB of memory for the Docker container
  • need to set the amount of virtual memory on linux by setting the max map count:sudo sysctl -w vm.max_map_count=262144

Free SSL certificates with LetsEncrypt

Getting your website on https can be done in a matter of minutes. So there is no excuse anymore to go without it. Not even on your test and dev websites.

As this example is on CentOS, it really goes for any other linux distro.

Excellent, tailor-made instructions per webserver and OS are found on the website of Certbot:
https://certbot.eff.org/

Here, a short recap of that for my own archive.

You’ll need the repel repository for this. After that, install the certbot software.

$ sudo yum install epel-release
$ sudo yum install certbot-nginx

 

Getting your website secured with SSL is now as simple as answering some questions on the following command.

Note: I’m using a method which takes a bit of downtime because LetsEncrypt is in the middle of an update. Read all about it

$ sudo certbot --authenticator standalone --installer nginx --pre-hook "service nginx stop" --post-hook "service nginx start"

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer nginx
 
Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: yoursite.pauledenburg.com
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 2


Running pre-hook command: service nginx stop
Error output from service:
Redirecting to /bin/systemctl stop nginx.service
 
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for es.git.innospense.com
Waiting for verification...
Cleaning up challenges
Running post-hook command: service nginx start
Error output from service:
Redirecting to /bin/systemctl start nginx.service
 
Deployed Certificate to VirtualHost /etc/nginx/sites-enabled/yoursite.pauledenburg.com.conf for set(['yoursite.pauledenburg.com'])
 
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/yoursite.pauledenburg.com.conf
 
-------------------------------------------------------------------------------
Congratulations! You have successfully enabled https://yoursite.pauledenburg.com
 
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=yoursite.pauledenburg.com
-------------------------------------------------------------------------------
 
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/es.git.innospense.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/es.git.innospense.com/privkey.pem
   Your cert will expire on 2018-04-24. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:
 
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

 

Things which might throw you an error

python-urllib3 version

First caveat for CentOS7 is that you need specific version 1.21 for urllib3. I had 1.22 installed via yum which gave me the following error.

ImportError: No module named 'requests.packages.urllib3'

You can see the currently installed version with pip:

pip freeze | grep urllib

To resolve this, first remove the old version it with yum and then add it with pip:

sudo yum remove python-urllib3 
sudo pip install -Iv https://github.com/shazow/urllib3/archive/1.21.1.tar.gz

pyOpenSSL version

Just like urllib3, pyOpenSSL was of an unsupported version.

sudo yum remove pyOpenSSL
sudo pip install pyOpenSSL

Error message stating that the CA can’t be satisfied

After running

certbot --nginx

you get the following error:

Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA.

Due to legal reasons there currently is no

From the github certbot website:

If you’re serving files for that domain out of a directory on Nginx, you can run the following command:

# Webroot method
$ sudo certbot --authenticator webroot --installer nginx \
  --webroot-path <path to served directory> -d <domain>

If you’re not serving files out of a directory (for instance if you are using proxy_pass), you can temporarily stop your server while you obtain the certificate and restart it after Certbot has obtained the certificate. This would look like:

# Temporary outage method
$ sudo certbot --authenticator standalone --installer nginx \
  -d <domain> --pre-hook "service nginx stop" --post-hook "service nginx start"