Friday, July 7, 2023

How to provide Angular Environment Configuration after Build Time

When you want to deploy a containerized Spring Boot application to Kubernetes and provide environment specific configuration during deployment time (e.g. with a Build Pipeline), this is very easy: you just have to set operating system environment variables in the context where your container process runs and these environment variables have to match your Spring Boot configuration properties in order to provide the configuration you want to use (https://docs.spring.io/spring-boot/docs/3.1.1/reference/htmlsingle/#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables).

But this approach does not work with Web Applications which for example are build with Angular and run in a Browser. For example, you can use the official Nginx Docker Image to deploy an Angular app to Kubernetes and you could set operating system environment variables which then can be accessed by the Nginx process in the container . So far, no problem. But how do you want to access such environment variables in a Browser, which runs on a completely different machine than Nginx? The only way to communicate from the Browser with Nginx is via HTTP requests. Furthermore, the default Angular environment.ts configuration can only be used to provide configuration at build time, which means that this configuration will be part of the Docker Image.

Therefore, you have to "inject" a file into your Nginx container, which holds the environment specific configuration. Such a file can then be loaded from the Browser via a HTTP GET request and processed by your Angular app. It makes much sense, that such a configuration file contains JSON data, because this is easy to process with Angular. One important aspect when you are building "cloud native" apps is that you want to build your Docker Image only once and then use it for all environments (e.g. local, dev, prod). To make this work, you have to separate configuration from code, which should automatically be the case when you have a clean and modular design. To separate configuration from code is also one factor in the Twelve-Factor App (https://12factor.net/config). One generic way to "inject" a file into a container at Deployment time is by using Kubernetes Volume Mounts in combination with a Kubernetes ConfigMap (if you're using Kubernetes; see https://kubernetes.io/docs/concepts/storage/volumes/#configmap).

The recommended way to load the configuration into your Angular app is by providing an APP_INITIALIZER which will load the configuration when your Angular App bootstraps (https://angular.io/api/core/APP_INITIALIZER). Because of the asynchronous nature of Angular and the underlying Observer Pattern, the configuration is only accessible through an Observable (https://angular.io/guide/observables). This means that when you make a GET request with the Angular HttpClient, you will get an Observable that holds the configuration as a response. As a consequence, you have to transform this Observable in all areas of your code where you need to access your configuration. Let's say we have a RemoteConfigService which will load the configuration when the APP_INITIALIZER is invoked. The RemoteConfigService can now provide access to the configuration by declaring a getter named getAppConfig with the following signature:

getAppConfig: Observable<AppConfig>

When you want to access a certain property of your JSON configuration, you can use the pipe/switchMap pattern (from rxjs) to transform the Observable. The following method demonstrates how to do that:

getPropertyFromConfig(): Observable<string> {
    return this.remoteConfigService.getAppConfig().pipe(
        switchMap(config => of(config.myPropertyName)));
}

The return value is another Observable which holds the property value. You can directly access the Observable inside an Angular HTML template by using the "async pipe" (https://angular.io/api/common/AsyncPipe).

Wednesday, February 10, 2021

Closures in Python3

Let's write a closure that implements the behavior of a simple counter.

def create_counter():
    value = 0
    def counter(x):
        nonlocal value
        value += x
        return value
 
    return counter
 
c1 = create_counter()
c2 = create_counter()
 
print(c1(3))
print(c1(4))
print(c2(1))
print(c2(7))


The only non-obvious thing here, is the use of the nonlocal statement. Without using the nonlocal statement, we would get the following error:

UnboundLocalError: local variable 'value' referenced before assignment

The reason for this is:

"...the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope."

See https://docs.python.org/3/reference/simple_stmts.html#nonlocal

Wednesday, August 26, 2020

Unlock your Android Smartphone with a USB-Mouse

What do you do, when you can't unlock your Android Smartphone anymore, because the screen glass is broken? The Situation gets even worse, if you have data on that Smartphone. In case your data is stored on an external SD-Card, its not possible to read the SD-Card from another Smartphone or Laptop. This is due to the fact, that by default every Android device encrypts the SD-Card so that the data can only be accessed by the device itself.

You could replace the display glass of your Smartphone, but depending on your model, this can get quite expensive. Fortunately, there is another alternative: You can connect a USB-Mouse with the help of an USB OTG Adapter.

In my case, I managed to destroy the screen glass of my Motorola Moto e4 XT1762. Therefore, I bought an ednet Micro USB 2.0 OTG Adapter for 7,90€.



Plug'n'Play

Sunday, September 29, 2019

Injecting external configuration into Spring Boot and Docker

First, in order to use the configuration from an application.yml oder application.properties, its handy to abstract that with a Spring Component class.

@Component
@ConfigurationProperties("address")
public class AddressConfiguration {
    private String city;
    private String street;

    public AddressConfiguration(String city, String street) {
        this.city = city;
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public String getStreet() {
        return street;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setStreet(String street) {
        this.street = street;
    }
}


The above class maps to the following application.yml:

address:
  city: "New York"


The name that is specified for the ConfigurationProperties annotation must match with the root element name of your configuration, that you want to load. As you can see, the application.yml doesn't contain an entry for street. You can set additional entries (or overwrite existing ones) by supplying a SPRING_APPLICATION_JSON environment variable:

export SPRING_APPLICATION_JSON='{"address":{"street":"Broadway"}}'

If you are running Spring Boot inside a Docker container, you can pass the exported SPRING_APPLICATION_JSON environment variable to the container by providing the -e flag:

docker run -e SPRING_APPLICATION_JSON="$SPRING_APPLICATION_JSON"

Thursday, November 15, 2018

Raspbian Edimax USB WLAN Adapter

In order to get the Edimax USB WLAN Adapter working on Debian / Raspbian, proceed as follows.

(1) Use lsusb to list all USB devices:

$ lsusb

 Bus 001 Device 004: ID 7392:7811 Edimax Technology Co., Ltd EW-7811Un 802.11n Wireless Adapter [Realtek RTL8188CUS]

The Edimax USB WLAN Adapter uses the Realtek RTL8188CUS chipset.

(2) To figure out which driver is used and hence which module needs to be loaded, we can use the system message log:

$ dmesg | grep rtl

[   16.919884] usbcore: registered new interface driver rtl8192cu

Now we know the module name: 8192cu

(3) To load the module during system boot, create the following file with the given content:

$ sudo touch /etc/modprobe.d/8192cu.conf
$ sudo echo "options 8192cu rtw_power_mgnt=0 rtw_enusbss=0" > /etc/modprobe.d/8192cu.conf

(4) Enable the wlan0 device (eth0 will be disabled with this configuration):

#auto eth0
#iface eth0 inet dhcp
 

auto wlan0
iface wlan0 inet dhcp
wpa-ap-scan 1
wpa-scan-ssid 1
wpa-ssid "your-ssid"
wpa-psk "your-wlan-passphrase"


(5) Reboot your PI

Sunday, August 19, 2018

Install VirtualBox on Debian Stretch 9.5

Prerequisites

Add the backports repository to /etc/apt/sources.list:

deb http://ftp.de.debian.org/debian/ stretch-backports main contrib
deb-src http://ftp.de.debian.org/debian/ stretch-backports main contrib


Installation

$ apt-get update
$ apt-get install virtualbox
$ apt-get install virtualbox-ext-pack
$ apt-get install linux-headers-$(uname -r)


Build Kernel Module

dpkg-reconfigure virtualbox-dkms
$ dpkg-reconfigure virtualbox


Links

Saturday, April 28, 2018

Cleaning up Docker containers with xargs

The Linux/UNIX tools landscape is always worth investigating, while you're trying to find a solution for a problem. Because, if you're lucky you don't have to write a script or anything similar: you can just chain existing tools together to build up your custom solution.

Thanks to Dump Tiger and Bjørn, I got to know the xargs command.

One thing that I don't like so much, when I'm starting/stopping Docker containers quite often, is that they'll polute your disc space (depending on the image size).

docker ps -a | grep 'Exited (' | cut -d ' ' -f1 | xargs docker rm

The pipe shown above does the following:
  1. List all Docker containers
  2. Filter the list, so that only those lines that contain the string 'Exited (' will be returned
  3. From all returned lines, cut of the first row (the container ID) by splitting each line on all whitespaces
  4. Now that we've a list of container IDs, we can pipe each container ID into docker rm by using xargs