Observabilité et Circuit Breaker avec Spring

Il y a quelques mois déjà, je discutais avec un collègue d’ observabilité, opentracing, … avec Quarkus. On est tombé sur un super exemple réalisé par Antonio Concalves. Ce projet démontre les capacités de Quarkus sur les sujets suivants:

  • Circuit Breaker
  • Observabilité
  • OpenTracing
  • Tests

Et la on peut se demander quid de Spring? Je me doutais que ces fonctionnalités étaient soient disponibles par défaut soient facilement intégrables vu la richesse de l’écosystème.

J’ai donc réalisé un clone de ce projet basé sur Spring Boot/Cloud. Je ne vais pas détailler plus que ça les différentes fonctionnalités, vous pouvez vous référer au fichier README. Il est suffisamment détaillé pour que vous puissiez exécuter et les mettre en œuvre.

Architecture de l’application

Vous trouverez ci-dessous un schéma d’architecture de l’application au format C4.


Circuit Breaker

Lors des appels entre le bookstore et le booknumberservice, il peut être intéressant d’ implémenter un circuit breaker pour pallier aux indisponibilités de ce dernier.
Avec Spring, on peut utiliser Resilience4J au travers de Spring Cloud. Tout ceci se fait de manière programmatique

Il faut tout d’abord configurer les circuit breakers au travers d’une classe Configuration.

   @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> createDefaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(timeoutInSec)).build())
                .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
                .build());
    }

    /**
     * Creates a circuit breaker customizer applying a timeout specified by the <code>booknumbers.api.timeout_sec</code> property.
     * This customizer could be reached using this id: <code>slowNumbers</code>
     * @return the circuit breaker customizer to apply when calling to numbers api
     */
    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> createSlowNumbersAPICallCustomizer() {
        return factory -> factory.configure(builder -> builder.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
                .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(timeoutInSec)).build()), "slowNumbers");
    }

Grâce à ces instanciations, on référence les différents circuit breakers.

Maintenant, on peut les utiliser dans le code de la manière suivante:

public Book registerBook(@Valid Book book) {
        circuitBreakerFactory.create("slowNumbers").run(
                () -> persistBook(book),
                throwable -> fallbackPersistBook(book)
        );

        return bookRepository.save(book);
    }

Maintenant, il ne reste plus qu’à créer une méthode de « fallback » utilisée si un service est indisponible. Cette dernière nous permettra, par exemple, de mettre le payload dans un fichier pour futur traitement batch.

Observabilité

L’observabilité est sans contexte la pierre angulaire (oui, rien que ça…) de toute application cloud native. Sans ça, pas de scalabilité, de redémarrage automatique,etc.
Les architectures de ce type d’applications sont idempotentes. On a donc besoin d’avoir toutes les informations à notre disposition. Heureusement, Spring fournit par le biais d’ Actuator toutes les informations nécessaires. Ces dernières pourront soit être utilisées par Kubernetes (ex. le livenessProbe) ou agrégées dans une base de données Prometheus.

Pour activer certaines métriques d’actuator, il suffit de :

Ajouter la/les dépendance(s)

    dependencies {
[...]
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        implementation 'io.micrometer:micrometer-registry-prometheus'
     [...]
    }

Spécifier la configuration adéquate:

management:
  endpoints:
    enabled-by-default: true
    web:
      exposure:
        include: '*'
    jmx:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
      enabled: true
      probes:
        enabled: true
    shutdown:
      enabled: true
    prometheus:
      enabled: true
    metrics:
      enabled: true
  health:
    livenessstate:
      enabled: true
    readinessstate:
      enabled: true
    datasource:
      enabled: true
  metrics:
    web:
      client:
        request:
          autotime:
            enabled: true

OpenTracing

Sur les applications distribuées, il peut s’avérer compliqué de concentrer les logs et de les corréler. Certes, avec un ID de corrélation, on peut avoir certaines informations. Cependant, il faut que les logs soient bien positionnées dans le code. On peut également passer à travers de certaines informations (ex. connexion aux bases de données, temps d’exécution des APIS,…). Je ne vous parle pas des soucis de volumétrie engendrées par des index Elasticsearch/Splunk sur des applications à forte volumétrie.

Depuis quelques temps, le CNCF propose un projet (encore en incubation) : OpenTracing. Ce dernier fait désormais partie d’OpenTelemetry.
Grâce à cet librairie, nous allons pouvoir tracer toutes les transactions de notre application microservices et pouvoir réaliser une corrélation « out of the box » grâce à l’intégration avec Jaeger.

Pour activer la fonctionnalité il suffit d’ajouter la dépendance au classpath:

implementation 'io.opentracing.contrib:opentracing-spring-jaeger-cloud-starter:3.3.1'

et de configurer l’URL de Jaeger dans l’application

# Default values
opentracing:
  jaeger:
    udp-sender:
      host: localhost
      port: 6831
    enabled: true

Une fois l’application reconstruite et redémarrée, vous pourrez visualiser les transactions dans JAEGER:

Conclusion

Je ne vais pas exposer l’implémentation des tests unitaires et d’intégration. Si vous voulez voir comment j’ai réussi à mocker simplement les appels REST à une API distante, vous pouvez regarder cette classe pour voir une utilisation du MockServer.
Aussi, n’hésitez pas à cloner, tester ce projet et me donner votre retour. J’essaierai de le mettre à jour au fur et à mesure de mes découvertes (par ex. OpenTelemetry).

Ajouter un mode « maintenance » à votre API grâce à Spring boot

Photo by Pixabay on Pexels.com

Quand vous avez une API, et a fortiori une application, il peut être parfois nécessaire de passer l’application en mode « maintenance ».
Pour certaines applications il est parfois inutile de le traiter au niveau applicatif, car ça peut être pris géré par certaines couches de sécurité ou frontaux web par ex. (Apache HTTPD, WAF,…)

Kubernetes a introduit ( ou popularisé ) les notions de « probes » et plus particulièrement les livenessProbes et readinessProbes.
Le premier nous indique si l’application est en état de fonctionnement, le second nous permet de savoir si cette dernière est apte à recevoir des requêtes (ex. lors d’un démarrage).

Je vais exposer dans cet article comment utiliser au mieux ces probes et les APIs SPRING pour intégrer dans une API un mode « maintenance »

Stack utilisée

Dans l’exemple que j’ai développé, j’ai pu utiliser les briques suivantes:

  • OpenJDK 11.0.10
  • Spring Boot 2.5.0 (web, actuator)
  • Maven 3.8.1

Bref, rien de neuf à l’horizon 🙂

Configuration de Spring Actuator

Pour activer les différents probes, vous devez activer Actuator.

Dans le fichier pom.xml, vous devez ajouter le starter correspondant:

<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Puis vous devez déclarer ces differentes propriétés:

management.endpoints.enabled-by-default=true
management.health.livenessstate.enabled=true
management.health.readinessstate.enabled=true
management.endpoint.health.show-details=always
management.endpoint.health.probes.enabled=true
management.endpoint.health.enabled=true

Après avoir redémarré votre application, vous pourrez connaître son statut grâce à un appel HTTP

curl -s http://localhost:8080/actuator/health/readiness 

Comment récupérer le statut des probes?

Avec Spring, vous pouvez modifier les différents statuts avec les classes ApplicationEventPublisher et ApplicationAvailability.

Par exemple, pour connaître le statut "Readiness" vous pouvez exécuter le code suivant:

 @ApiResponses(value = {
 @ApiResponse(responseCode = "200", description = "Checks if the application in under maitenance")})
 @GetMapping
 public ResponseEntity<MaintenanceDTO> retreiveInMaintenance() {
        var lastChangeEvent = availability.getLastChangeEvent(ReadinessState.class);
        return ResponseEntity.ok(new MaintenanceDTO(lastChangeEvent.getState().equals(ReadinessState.REFUSING_TRAFFIC), new Date(lastChangeEvent.getTimestamp())));
    }

Et la modification ?

Grâce à la même API, on peut également modifier ce statut dans via du code:

@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Put the app under maitenance")})
@PutMapping
public ResponseEntity<Void> initInMaintenance(@NotNull @RequestBody String inMaintenance) {
        AvailabilityChangeEvent.publish(eventPublisher, this, Boolean.valueOf(inMaintenance) ? ReadinessState.REFUSING_TRAFFIC : ReadinessState.ACCEPTING_TRAFFIC);
        return ResponseEntity.noContent().build();
}

Filtre les appels et indiquer que l’application est en maintenance

Maintenant qu’on a codé les mécanismes de récupération du statut de l’application et de la mise en maintenance, on peut ajouter le mécanisme permettant de traiter ou non les appels entrants.
Pour ça on va utiliser un bon vieux filtre servlet.

Ce dernier aura la tâche de laisser passer les requêtes entrantes si l’application n’est pas en maintenance et de déclencher une MaintenanceException le cas échéant qui sera traité par la gestion d’erreur globale de l’application ( traité via un @RestControllerAdvice).

Pour que l’exception soit bien traitée par ce mécanisme, il faut le déclencher via le HandlerExceptionResolver.

@Component
public class CheckMaintenanceFilter implements Filter {
    private final static Logger LOGGER = LoggerFactory.getLogger(CheckMaintenanceFilter.class);
    @Autowired
    private ApplicationAvailability availability;

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver exceptionHandler;

    /**
     * Checks if the application is under maintenance. If it is and if the requested URI is not '/api/maintenance', it throws a <code>MaintenanceException</code>
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     * @throws info.touret.spring.maintenancemode.exception.MaintenanceException the application is under maintenance
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (availability.getReadinessState().equals(ReadinessState.REFUSING_TRAFFIC) &&
                !((HttpServletRequest) request).getRequestURI().equals(API_MAINTENANCE_URI)) {
            LOGGER.warn("Message handled during maintenance [{}]", ((HttpServletRequest) request).getRequestURI());
            exceptionHandler.resolveException((HttpServletRequest) request, (HttpServletResponse) response, null, new MaintenanceException("Service currently in maintenance"));
        } else {
            chain.doFilter(request, response);
        }
    }

}

Enfin, voici la gestion des erreurs de l’API:

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * Indicates that the application is on maintenance
     */
    @ResponseStatus(HttpStatus.I_AM_A_TEAPOT)
    @ExceptionHandler(MaintenanceException.class)
    public APIError maintenance() {
        return new APIError(HttpStatus.I_AM_A_TEAPOT.value(),"Service currently in maintenance");
    }

    /**
     * Any other exception
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({RuntimeException.class, Exception.class})
    public APIError anyException() {
        return new APIError(HttpStatus.INTERNAL_SERVER_ERROR.value(),"An unexpected server error occured");
    }
}

Conclusion

On a pu voir comment intéragir simplement avec les APIS SPRING pour gérer le statut de l’application pour répondre à cette question :Est-elle disponible ou non?
Bien évidemment, selon le contexte, il conviendra d’ajouter un peu de sécurité pour que cette API ne soit pas disponible à tout le monde 🙂

Le code exposé ici est disponible sur Github. Le Readme est suffisamment détaillé pour que vous puissiez tester et réutiliser le code.

Utiliser GPG dans WSL2

Photo by Pixabay on Pexels.com

Pourquoi utiliser GPG ? Par exemple pour signer les commits GIT. Maintenant comment faire quand on est sous Windows 10 et qu’on souhaite utiliser le sous système Linux (WSL2)?

Sous GNU/Linux, l’installation et l’utilisation avec git est très simple. Avec WSL2,… il faut un peu d’huile de coude 🙂

Je vais tâcher de décrire dans cet article les différentes manipulations nécessaires pour:

  • Importer une clé GPG existante
  • Utiliser GPG pour signer mes commits dans WSL2

Importer une clé GPG existante

Export de la clé GPG

Identifier l’ ID de la clé

Lancez la commande suivante:

gpg --export ${ID} > public.key
gpg --export-secret-key ${ID} > private.key

Import

gpg --import public.key
gpg --import private.key

Vérification

Pour vérifier que la clé est bien configurée, vous pouvez lancer la commande suivante:

gpg --list-secret-keys --keyid-format LONG   alexandre@....
sec   rsa4096/CLE_ID 2019-12-20 [SC]
      ********************
uid                [  ultime ] Alexandre <alexandre@....>
ssb   rsa4096/SUB 2019-12-20 [E]

Si la clé n’est pas reconnue comme ultime ou comme de confiance, il faudra l’éditer:

gpg --edit-key CLE_ID
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu
Your decision? 

Si vous ne voulez pas trop vous compliquer, je vous conseille de répondre 5.

Configuration GPG pour WSL2

Avant de configurer l’agent GPG, vous pouvez vous référer à cet article pour configurer GIT et GPG. La configuration est équivalente.

Ensuite, créez le fichier ~/.gnupg/gpg.conf avec le contenu suivant:

# Uncomment within config (or add this line)
# This tells gpg to use the gpg-agent
use-agent
# Set the default key
default-key CLE_ID

Puis créez le fichier ~/.gnupg/gpg-agent.conf avec le contenu ci-dessous:

default-cache-ttl 34560000
max-cache-ttl 34560000
pinentry-program /usr/bin/pinentry-curses

Le cache ici est défini en secondes. Il est mis ici à 400 jours.

Ce dernier fichier fait référence au programme pinentry. Vous pouvez vérifier sa présence grâce à la commande:

ls /usr/bin/pinentry-curses 

Si vous ne l’avez pas, vous pouvez l’installer grâce à la commande suivante:

sudo apt install pinentry-curses

Maintenant, on peut configurer l’environnement BASH en modifiant le fichier ~/.bashrc

# enable GPG signing
export GPG_TTY=$(tty)
if [ ! -f ~/.gnupg/S.gpg-agent ]; then
    eval $( gpg-agent --daemon --options ~/.gnupg/gpg-agent.conf )
fi
export GPG_AGENT_INFO=${HOME}/.gnupg/S.gpg-agent:0:1

Redémarrez ensuite WSL2 pour que ça soit pris en compte.

A la première utilisation de GPG ( par ex. lors d’un commit, vous aurez une interface Ncurses qui apparaîtra dans votre prompt WSL2. Vous aurez à renseigner le mot de passe de votre clé.

Installer Ubuntu 20.04 LTS sur un DELL Inspiron 13 5000

Les confinements se suivent et se ressemblent. Me voilà à installer Ubuntu sur un nouvel ordinateur.
A l’instar de l’ancien laptop que j’ai acheté pour mon aînée, j’ai acheté un DELL pour ma deuxième fille.
J’ai opté pour un DELL Inspiron 5301.


A l’instar de mon autre laptop, je j’ai pas pris de risques. J’ai opté pour un DELL qui est pleinement compatible avec Ubuntu. Oui j’aurai pu installer un ordinateur avec Ubuntu pré-installé, mais je n’ai pas eu le temps de faire un choix « serein ».


Configuration du BIOS

Voila les paramètres que j’ai appliqué:

Dans le menu "Storage" puis "SATA Operation": vous devez sélectionner AHCI au lieu de RAID.
Dans le menu "Change boot mode settings >UEFI Boot Mode" , vous devez désactiver le Secure Boot.

Une fois réalisé, vous pouvez redémarrer en appuyant sur la touche F12. Si vous n’arrivez pas à revenir sur le BIOS pour indiquer de booter sur votre clé USB, vous obtiendrez un écran d’erreur Windows dû à la configuration AHCI. Personnellement, en redémarrant une ou deux fois, j’ai obtenu un écran de démarrage avancé qui m’a permis de sélectionner le périphérique (ma clé USB) sur lequel démarrer.

Maintenant vous pouvez accéder à l’installeur Ubuntu et profiter.

Installation

J’ai eu plusieurs fois des popup « erreur rencontré ». Ce n’était pas bloquant. J’ai continué.

Tout s’est déroulé sans encombre. Le matériel est très bien reconnu.

Les seuls logiciels que j’ai installé sont pour l’instant : VLC, Minecraft ( obligatoire dans la famille ) et Chromium.

Music Scores As Code

Derrière ce nom pompeux qui peut effrayer, je vais essayer d’expliquer dans cet article comment on peut versionner facilement ses partitions et les publier sur le web.

En cherchant comment mettre de la documentation technique avec des diagrammes PlantUml dans des repos GITLAB et générés avec des pipelines, je me suis mis dans la tête de faire la même chose avec des partitions 🙂

Depuis plusieurs années, j’utilise lilypond pour créer mes partitions. C’est un peu difficile de s’y mettre, mais une fois la syntaxe assimilée, la saisie d’une partition est beaucoup plus efficace. Le rendu des partitions est vraiment optimisé.
Si vous voulez plus de détails sur le pourquoi du comment je vous conseille cette page.

Vous trouverez des exemples sur le site.

J’ai donc eu l’idée de:

  • Stocker ces partitions sur un repo github (jusque là rien d’exceptionnel)
  • Générer automatiquement les partitions au format PDF, PNG et MIDI via une github action (ça commence à devenir intéressant…)
  • Les publier avec les github pages (tant qu’à faire 🙂)

Stockage

Pourquoi stocker dans un référentiel de sources tel que Github ? Pour les non informaticiens : les partitions sont stockées au format texte.

\version "2.12.1"

\header {
  title="Try a little tenderness"
  composer="Harry Woods, Jimmy Campbell & Reg Connely"
  subtitle = "Commitments Version"
  %poet = "Poete"
  instrument = "Piano"
  editor = "L'éditeur"
  %meter=\markup {\bold {"Remarque sur le rhythme"}}
  style = "Soul"
  maintainer = "Alexandre Touret"
  maintainerEmail = "alexandre.touret@free.fr"
  maintainerWeb = "http://blog.touret.info"     
  lastupdated = ""
  source = "Music room"
  footer = "Footer"
  copyright =\markup {\fontsize #-1.5
 "Delivered by A TOURET"}
}
upper=
\relative c'{
  \clef treble
  \time 4/4
  \tempo 4=176
  \key g \major
  
  d'2 (b4 e
  d2 b4 a 
  g2 g2 
  <e g,>2) <fis, c' d> 
  \bar "||"

GIT et GITHUB permettent de versionner facilement et pouvoir faire facilement un retour arrière en cas d’erreur.
Aussi, GITHUB offre des fonctionnalités « sociales » et collaboratives qui facilitent la revue des modifications ( en cas de travail à plusieurs ).
Bref, ça offre la sécurité d’une sauvegarde et la possibilité d’un retour arrière en cas d’erreur.

Générer les partitions avec une github action

Les github actions sont des outils permettant:

GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

J’ai donc décidé de créer un workflow qui permet de générer les partitions au format lilypond.

J’ai mis à disposition le code sur github sous licence GNU GPLv3. Elle est utilisable telle quelle.

Pour créer l’action, il faut créer un fichier action.yml à la racine du repo. Voici le contenu

name: 'Lilypond Generator'
description: 'Run Lilypond tool with the given set of arguments to generate music sheets'
author: '@alexandre-touret'

inputs:
  args:
    description: 'Arguments for Lilyponid'
    required: true
    default: '-h'

runs:
    using: 'docker'
    image: 'Dockerfile'
    args:
      - ${{ inputs.args }}

branding:
  icon: 'underline'
  color: 'blue'

Vous aurez compris que ce fichier fait référence à une image Docker. Cette dernière n’est ni plus ni moins qu’une Debian avec lilypond d’installé.

Pour l’utiliser dans un repo github, on peut créer une action qui l’utilise. Voici un exemple:

jobs:
  build_sheets:
    runs-on: ubuntu-latest
    env:
        LILYPOND_FILES: "*.ly"
    steps:
      - name: Checkout Source 
        uses: actions/checkout@v1
      - name: Get changed files
        id: getfile
        run: |
          echo "::set-output name=files::$(find ${{github.workspace}} -name "${{ env.LILYPOND_FILES }}" -printf "%P\n" | xargs)"
      - name: LILYPOND files considered echo output
        run: |
          echo ${{ steps.getfile.outputs.files }}
      - name: Generate PDF music sheets
        uses: alexandre-touret/lilypond-github-action@master
        with:
            args: -V -f --pdf ${{ steps.getfile.outputs.files }}

A la dernière ligne on peut passer les arguments nécessaires à lilypond.

Publication

La c’est l’étape la plus facile :). Il suffit d’activer les github pages et de commiter et pusher les partitions générées

 - name: Push Local Changes
        run: |
          git config --local user.email "${{ secrets.GIT_USERNAME }}"
          git config --local user.name "${{ secrets.GIT_EMAIL }}"
          git add .
          git commit -m "Add changes" -a
      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

Il suffit de créer une page index.md à la racine et d’ajouter des liens vers les partitions générées ( dans mon cas, ça se passe dans le répertoire /docs ).
Vous pouvez trouver un exemple ici.

Conclusion

Voila comment on peut générer un site avec des partitions crées avec Lilypond.
Vous trouverez les différents liens ci-dessous. Peut être que je publierai cette action sur le marketplace une fois que j’aurai publié une documentation digne de ce nom :).

Améliorer le temps de démarrage de Debian 10

Mon PC Lenovo a un SSD. Le temps de démarrage est actuellement de 11 sec. Ça commence à faire pas mal… J’ai eu donc envie de me pencher sur l’optimisation du démarrage ( encore une fois) . Voici comment gagner (facilement) quelques secondes au démarrage.

Tout d’abord, vous devez analyser les services qui prennent du temps au démarrage. Vous pouvez le faire avec cette commande:

systemd-analyze plot > plot.svg

J’ai obtenu le graphique suivant:

Configuration GRUB

La première manipulation à réaliser est de désactiver le timeout de GRUB. Pour celà, vous pouvez modifier la variable GRUB_TIMEOUT dans le fichier /etc/default/grub:

GRUB_TIMEOUT=0

Ensuite, vous devez mettre à jour la configuration GRUB en exécutant cette commande:

sudo update-grub2

Au prochain reboot, vous ne verrez plus le menu GRUB.

Configuration NetworkManager

Dans mon cas, le service NetworkManager-wait-online.service prenait près de 9 secondes. Après avoir lu plusieurs billets et rapports de bug, je me suis aperçu que je pouvais le désactiver au boot. Vous pouvez le faire en lançant la commande suivante

sudo systemctl disable NetworkManager-wait-online.service

Configuration Apt

Un autre service qui prenait pas mal de temps était apt-daily.timer qui vérifiait au boot qu’il y avait des mises à jour de l’OS. Après quelques recherches, j’ ai vu qu’on pouvait soit le désactiver ( ce qui n’est pas recommandé pour les mises à jour de sécurité ) soit décaler la recherche. J’ai choisi cette solution. Vous devez donc exécuter la commande suivante:

sudo systemctl edit apt-daily.timer

Et renseigner le contenu suivant:

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
AccuracySec=1h
RandomizedDelaySec=30min

Ce service sera donc lancé 15 minutes après le boot. Ce qui est largement suffisant.

[EDIT] Vous pouvez appliquer la même configuration pour le service apt-daily-upgrade en exécutant la commande:

sudo systemctl edit apt-daily-upgrade.timer

Ensuite, vous pouvez recharger la configuration en exécutant cette commande:

sudo systemctl daemon-reload

Résultats

Après ces quelques manipulations qui peuvent prendre 5 minutes grand maximum, j’ai réussi à optimiser le boot en réduisant le démarrage à 5 secondes!

Vous pourrez trouver le détail ci-dessous:

Répéter avec JjazzLab tout seul dans son garage

Avec les contraintes liées au confinement, les répétitions se font de plus en plus rares. Pour ne pas perdre la main, il y a quelques logiciels qui permettent de jouer d’un instrument et d’ improviser tout en ayant une bande son en fond musical.

Il y a plusieurs logiciels payants/propriétaires sur différentes plateformes:

J’ai découvert ce dernier récemment en naviguant sur le site Linux Mao. Il a l’avantage d’être gratuit (le moteur est sous licence LGPL 3.0, pas le logiciel en tant que tel), de fonctionner sous GNU/LINUX, d’ offrir un son pas mal du tout et de permettre la configuration de la dynamique au fur et à mesure du morceau.

Je vais expliquer comment l’installer sur Debian.

Configuration Midi

Activation des périphériques virtuels MIDI

Créer un fichier /etc/modules.load.d/midi.conf avec le contenu suivant:

snd-virmidi

Ensuite créer le fichier /etc/modprobe.d/midi.conf avec le contenu suivant:

options snd-virmidi midi_devs=1

Logiquement à ce stade, lors du prochain reboot, vous aurez un périphérique virtuel MIDI activé. En attendant vous pouvez lancer la commande suivante

$ sudo modprobe snd-virmidi midi_devs=1

Synthétiser du MIDI

Pour faire fonctionner ce logiciel, il faut installer une banque de son ( au format SF2) et un logiciel permettant de l’utiliser pour synthétiser du MIDI.
La banque de son recommandée est disponible via ce lien. Téléchargez là et copiez la dans un répertoire accessible.

Pour le second, il vous faudra installer fluidsynth. Voic les quelques commandes à lancer:

$ sudo apt install fluid-synth qsynth

Petite vérification…

Avant d’ aller plus loin dans la configuration de fluidsynth, vous pouvez vous assurer que tout est OK en récupérant un fichier MIDI et en lançant la commande suivante:

$ fluidsynth -a pulseaudio -m alsa_seq -l -i /opt/JJazzLab-2.0-Linux/JJazzLab-SoundFont.sf2  MIDI_sample.mid

Normalement vous devriez avoir du son.

Configurer fluidsynth

Lancez qsynth et cliquez sur le bouton « configuration »

Vous trouverez ci-dessous la configuration que j’ai appliqué. Elle diffère légèrement de celle présentée dans la documentation.

Pensez à redémarrer fluidsynth après application de ces nouveaux paramètres.

Configurer aconnect

Disclaimer: La c’est la partie la plus obscure…

Il faut maintenant « brancher » la sortie du synthétiseur virtuel MIDI à fluidsynth pour que le son MIDI soit interprété par ce dernier à travers sa banque de son. Ce n’est pas intuitif, je vous avais prévenu …
Je ne vous parle pas de la pseudo interface graphique à aconnect. La ligne de console est plus parlante ( c’est pour dire ) .

Exécutez la commande suivante:

$ aconnect -lo                                            
client 14: 'Midi Through' [type=noyau]
    0 'Midi Through Port-0'
client 24: 'Virtual Raw MIDI 2-0' [type=noyau,card=2]
    0 'VirMIDI 2-0     '
client 128: 'FLUID Synth (JJLAB)' [type=utilisateur,pid=17838]
    0 'Synth input port (JJLAB:0)'

Dans mon cas, je vais avoir à connecter le client 24:0 au synthétiseur 128:0 grâce à la commande :

$ aconnect 24:0 128:0

Maintenant, si on relance la commande aconnect -lo on obtient le résultat suivant:

client 14: 'Midi Through' [type=noyau]
    0 'Midi Through Port-0'
client 24: 'Virtual Raw MIDI 2-0' [type=noyau,card=2]
    0 'VirMIDI 2-0     '
	Connexion À: 128:0
client 128: 'FLUID Synth (JJLAB)' [type=utilisateur,pid=17838]
    0 'Synth input port (JJLAB:0)'
	Connecté Depuis: 24:0

Attention, cette commande devra être lancée ( ainsi que fluidsynth) avant chaque démarrage de jjazzlab.

Installation de Jjazzlab

Téléchargez les binaires sur ce site, puis décompressez l’archive dans le répertoire /opt par ex.

Vous devez également installer java

$ sudo apt install openjdk-11-jdk

Ensuite, vous devez créer le fichier ~/.local/share/applications/jjazzlab.desktop avec le contenu suivant:

[Desktop Entry]
Type=Application
Name=JJazzLab
GenericName=JJazzLab
Icon=
Exec="/opt/JJazzLab-2.0-Linux/bin/jjazzlab"
Terminal=false
Categories=Audio;Music;Player;AudioVideo;

Maintenant vous pouvez directement démarrer JJazzlab via le menu.

Configuration

Une fois jjazzlab démarré, vous devez aller dans le menu « Tools>Options » et sélectionnez les valeurs suivantes:

Ouvrez un fichier example (ex. sunny )

Cliquez sur le menu décrit par un clavier

Puis configurez comme suit:

Maintenant vous pouvez télécharger les standards fournis sur le site et improviser dessus 🙂

Erreur 139 à l’exécution d’un container docker

Voici un rapide article sur un problème rencontré récemment. Lors de l’exécution d’un container docker, j’ai eu une erreur SIGSEGV 139. Un crash avec aucune log.

Bref que du bonheur 🙂



Avant d’aller plus loin voici mon environnement:

Après quelques recherches, je me suis rendu compte qu’on pouvait reproduire ce comportement en exécutant cette commande:

docker run -it gcc:4.8.5

Une des raisons trouvées serait un problème de compatibilité avec le noyau 4.8.5 (oui ça remonte…).
Une solution est d’activer l’émulation vsyscall.


Voici la configuration à effectuer:
Dans le fichier /etc/default/grub, ajouter la ligne suivante:

GRUB_CMDLINE_LINUX_DEFAULT="quiet vsyscall=emulate"

Puis lancer les commandes suivantes:

$ sudo update-grub 
$ sudo reboot

Maintenant le container devrait pouvoir s’exécuter correctement.

Installer Ubuntu 18.04 LTS sur un Dell Inspiron 14-3493

Suite aux premières annonces de distanciation sociale ( avant que le confinement soit effectif ) j’ai acheté en catastrophe un PC portable. Les critères étaient : 8Go de RAM, un disque SSD … et la compatibilité GNU/LINUX :).

N’ayant pas trop de temps pour chercher la bonne affaire ( technologique et financière ), j’ ai acheté un Dell Inspiron 14-3493.



Je n’ai pas pris trop de risques. Bien que livré avec Windows 10, ce modèle est déjà certifié compatible Ubuntu.
L’installation d’Ubuntu se passe très bien. C’est plié en moins de 30mn. Du coup, je ne la détaillerai pas dans cet article – si vous êtes intéressé, vous pouvez consulter cet article. Pour les pré-requis, c’est une autre paire de manches …

Voilà les différentes actions que j’ai réalisé au préalable

Redémarrer l’ordinateur et accéder au BIOS

Là, j’ai un peu galéré pour accéder au BIOS. La seule manipulation que j’ai trouvé et de lancer le menu « Démarrage avancé » puis sélectionner « Utiliser un périphérique ».

Vous pouvez donc sélectionner le disque dur. Au boot en appuyant sur la touche F12 et/ou F2, vous pouvez accéder au BIOS.

Configuration du BIOS

Voila les paramètres que j’ai appliqué:

Dans le menu "SATA Operation": vous devez sélectionner AHCI au lieu de RAID.
Dans le menu "Change boot mode settings >UEFI Boot Mode" , vous devez désactiver le Secure Boot.

Une fois réalisé, vous pouvez redémarrer en appuyant sur la touche F2 et/ou F12. Si vous n’arrivez pas à revenir sur le BIOS pour indiquer de booter sur votre clé USB, vous obtiendrez un écran d’erreur Windows dû à la configuration AHCI. Personnellement, en redémarrant une ou deux fois, j’ai obtenu un écran de démarrage avancé qui m’a permis de sélectionner le périphérique (ma clé USB) sur lequel démarrer.

Maintenant vous pouvez accéder à l’installeur Ubuntu et profiter 🙂

Après l’installation

Je n’ai rien fait de particulier si ce n’est configurer le trackpad. Pour cela, j’ai installé gnome-tweaks. Mis à part ça, tout fonctionne très bien!

Passer votre application Java8 en Java11

Java 8 est encore largement utilisé dans les entreprises aujourd’hui. Il y a même certains frameworks qui n’ont pas encore sauté le pas.
Je vais essayer d’exposer dans cette article les étapes à réaliser pour migrer (simplement) votre application JAVA8 en JAVA 11.

Dans cet article, je prendrai comme postulat que l’application se construit avec Maven.

Pré-requis

Tout d’abord vérifiez votre environnement d’exécution cible! Faites un tour du coté de la documentation et regardez le support de JAVA.

Si vous utilisez des FRAMEWORKS qui utilisent des FAT JARS, faites de même (ex. pour spring boot, utilisez au moins la version 2.1.X).

Ensuite, vous aurez sans doute à mettre à jour maven ou gradle. Préférez les dernières versions.

Configuration maven

Les trois plugins à mettre à jour obligatoirement sont :

Maven compiler plugin

<plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>11</release>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

maven surefire / failsafe plugin

Pour ces deux plugins, ajouter la configuration suivante:

 <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
        <configuration>
        [...]
          <argLine>--illegal-access=permit</argLine>
          [...]
        </configuration>
      </plugin>

Mise à jour des librairies

Bon,la il n’y a pas de magie. Vous devez mettre à jour toutes vos librairies. Mis à part si vous utilisez des librairies exotiques, la plupart supportent JAVA 11 maintenant.

C’est une bonne opportunité de faire le ménage dans vos fichiers pom.xml 🙂

APIS supprimées du JDK

Si vous faites du XML, SOAP ou que vous utilisiez l’API activation, vous devez désormais embarquer ces librairies. Le JDK ne les inclut plus par défaut.

Par exemple:

 <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

Modularisation avec JIGSAW

Bon là … je vous déconseille de partir directement sur la modularisation, surtout si vous migrez une application existante. Bien que la modularité puisse aider à réduire vos images docker en construisant vos propres JRE et d’améliorer la sécurité, elle apporte son lot de complexité.
Bref pour la majorité des applications, je vous déconseille de l’intégrer.

Conclusion

Avec toutes ces manipulations, vous devriez pouvoir porter vos applications sur JAVA11. Il y aura sans doute quelques bugs. Personnellement, j’en ai eu avec CGLIB vs Spring AOP sur une classe instrumentée avec un constructeur privé. Sur ce coup j’ai contourné ce problème ( je vous laisse deviner comment 🙂 ).