Publié le 27 Avril 2017

J'ai deux noms de domaine différents que je veux faire pointer vers la même installation de wordpress.

Par exemple: www.mondomaine.fr et blog.mondomaine.fr

Je ne parle pas l'option multisite de wordpress, ici. Les 2 domaines sont complétement équivalent.

Le problème vient de la configuration de wordpress, dans Settings / General il faut spécifier l'adresse wordpress (wordpress address) avec une URL unique. Il n'est pas possible de rentrer 2 noms de domaines différents.

Par exemple si j'utilise www.mondomaine.fr ici, alors lorsque j'utilise blog.mondomaine.fr, tous les liens pointent vers www.mondomaine.fr, ce qui est assez embêtant.

Heureusement il existe une solution toute simple à ce problème: Editer le fichier wp-config.php et ajouter les 2 lignes suivantes (n'importe où mais avant le require_once à la fin).

define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);

Ceci a pour effet de griser les 2 options de configuration "wordpress address" et "site address" dans "settings / general". 

Voir les commentaires

Rédigé par Bliz

Publié dans #Php, #Wordpress

Repost 0

Publié le 23 Mars 2017

On a parfois besoin de vérifier quelle est la base de donnée courante avant d'effectuer quelques commandes. 

Dans MySQL cela s'effectue simplement avec la commande suivante:

SELECT database();

qui retourne le nom de la base de donnée courante. 

Voir les commentaires

Rédigé par Bliz

Publié dans #MySQL

Repost 0

Publié le 9 Mars 2017

Pour vérifier que mes micro services sont accessible j'ai implémenté un endpoint qui répond simplement avec un statut 200 (OK) si le service est accessible.

L'idée est de pouvoir tester si le service est accessible en utilisant un script shell.

Cela peut se faire en utilisant cURL avec la commande suivante:

curl -s -o /dev/null -I -w "%{http_code}" http://mon.micro.service.local/api/health

Remplacer l'URL par celle de votre service. Le résultat de cette commande est uniquement l'affichage du statut HTTP de la réponse.

On peut ensuite intégrer cette commande dans un script, pour, par exemple, attendre que le service soit accessible avant de lancer un test ou autre.  

while [ $(curl -s -o /dev/null -I -w "%{http_code}" http://mon.micro.service.local/api/health) -ne 200 ]
do
   echo "Waiting for micro-service"
   sleep 5
done
echo "Service started"

Tant que la commande cURL ne retourne pas 200 (OK) on attend 5 secondes et on réessaye. Quand on sort de la boucle while, le service est accessible.

Voir les commentaires

Rédigé par Bliz

Publié dans #Linux, #Script

Repost 0

Publié le 24 Janvier 2017

Dans la version 1.13.0 de Docker j'ai rencontré des problèmes de DNS avec des adresses qui parfois ne pouvaient être résolues (environ une fois sur deux par moment).

Pour éviter ce problème j'ai simplement changé le DNS utilisé par le docker daemon.

Sous linux il faut éditer le fichier /etc/docker/daemon.json. Sur OS X si vous utilisez docker native il suffit de se rendre dans Préfèrences / Daemon / Advanced tab.

Ensuite il faut ajouter la configuration des DNS, par exemple:

{
   "dns": ["8.8.8.8", "8.8.4.4"]
}

Puis il faut redémarrer le docker daemon, directement depuis l'interface de docker native sous mac, ou avec la commande suivante sous linux:

sudo service docker restart

Pour moi ça a suffit à résoudre les erreurs de résolutions d'adresses.

Voir les commentaires

Rédigé par Bliz

Publié dans #docker

Repost 0

Publié le 4 Janvier 2017

Si dans votre projet sbt vous avez plusieurs classes principales, vous avez surement besoin d'executer ces différents programmes sans pour autant vouloir changer votre build.sbt.

Une classe principale est un objet (scala object) qui contient une méthode main telle que

def main(args: Array[String]): Unit = { ... }

ou  bien une class (ou objet) qui étend le trait App.

object MonAppli extends App { ... }

Pour spécifier l'application à exécuter avec sbt il faut utiliser la commande runMain:

sbt "runMain mon.package.MonAppli"

 

Voir les commentaires

Rédigé par Bliz

Publié dans #Scala

Repost 0

Publié le 17 Décembre 2016

Et bien on ne peut pas définir de constructeur en Scala simplement car cela n'existe pas mais il y a un concept équivalent: les paramètres de classe.

En revanche on peut définir les paramètres directement après le nom de la classe, ce qui donne quelque chose comme ceci:

class Animal(pattes: Int, couleur: String) {
...
}

Comme il n'y a pas de constructeur on peut placé le code du constructeur directement dans le corps de la classe:

class Animal(pattes: Int, couleur: String) {
   private val _pattes: Int
   private val _couleur: String

   println(s"Nouvel animal à $pattes pattes de couleur $couleur")
   _pattes = pattes
   _couleur = couleur
}

Ça marche mais ça fait très "java" niveau style. En fait Scala permet d'effectuer la même chose beaucoup plus simplement.

class Animal(val pattes: Int, val couleur: String) {
   println(s"Nouvel animal à $pattes pattes de couleur $couleur")
}

Quelle est la différence ? Simplement le mot-clé val juste devant chaque paramètre. La différence est que maintenant la classe Animal a une propriété pattes et une propriété couleur accessible publiquement. Comme il s'agit d'un val, cette propriété n'est pas modifiable, il nest donc pas gênant quelle soit publique.

Il est tout à fait possible de la garder privée en utilisant le mot-clé private:

class Animal(private val pattes: Int, private val couleur: String) { ...

Si on veut une propriété modifiable on remplace val par var. Attention dans ce cas, à la visibilité de la propriété qui est par défaut publique.

Enfin il y a le cas particulier des case classes ou il n'est pas nécessaire d'utiliser val car les attributs d'une case class sont immuable et publiquement accessible (à moins d'utiliser private).

case class Animal(pattes: Int, couleur: String)
 

Voir les commentaires

Rédigé par Bliz

Publié dans #Scala

Repost 0

Publié le 23 Novembre 2016

En scala l'utilisation des expressions régulières combinée avec le pattern matching permet de simplifier l'extraction de groupes à l'intérieur des regex.

Par exemple imaginons que nous devons extraire les composants d'une date au format aaaa-mm-dd (soit année-mois-jour).

Il nous faut tout d'abord une regex pour extraire les 3 composants: (\d{4})-(\d{2})-(\d{2}). On utilise 3 groupes (les parenthèses) composés de 4 puis 2 digits et séparé par des -.

Ensuite il n'y a plus qu'a combiner cette regex avec un pattern matching. Ce qui donne:

// la date à parser
val str = "2016-11-23"
// la regex pour extraire les composants
val date = """(\d{4})-(\d{2})-(\d{2})""".r

str match {
   case date(annee, mois, jour) => println(s"Date $jour/$mois/$annee")
   case _ => println("date invalide")
}

 

Voir les commentaires

Rédigé par Bliz

Publié dans #Scala

Repost 0

Publié le 10 Octobre 2016

Play ne supporte pas nativement la serialisation d'enum vers json. (Je pense qu'il s'agit d'une sombre histoire de compatibilité avec la version Java de Play).

Qu'à cela ne tienne on peut facilement écrire un json format qui fonctionne pour n'importe quelle Enumeration en quelques lignes:

import play.api.libs._

object EnumFormat {
   def formatEnum[E <: Enumeration](enum: E): Format[E#Value] = {
      // méthode pour gérer les erreurs en cas de valeur d'enum inconnue
      def readError(json: JsValue) =
         ValidationError("Can't parse {}, expected one of {}",
             json,
             enum.values.map(_.toString).mkString(", ")
        )

      new Format[E#Value] = {
         override def reads(json: JsValue): JsResult[E#Value] =
            json.validate[String]
              .map(s => Try(enum.withName(s)).toOption)
              .collect(readError(json)) { case Some(e) => e }

         override def writes(e: E#Value): JsValue =
           JsString(e.toString)
   }
}

 

Ensuite il n'y a plus qu'à utiliser EnumFormat.format pour définir un format json pour n'importe quelle enum:

object MyEnum extends Enumeration {
  // Enum avec Oui et Non comme valeur
   val Oui, Non = Value
  implicit val format = EnumFormat.format(MyEnum)
}

Voir les commentaires

Rédigé par Bliz

Publié dans #Scala

Repost 0

Publié le 10 Octobre 2016

Play ne fournit pas par défaut de format pour sérialiser une map en Json. Bien sûr si vous utiliser une Map[String, V] et que vous avez un format implicitement disponible pour le type V alors vous pouvez sérialiser votre map sans effort supplémentaire.

 

En revanche lorsque les clés sont d'un type non-standard. Par exemple pour sérialiser une map dont les clés sont aussi une case class. Dans ce cas autant écrire un format qui supporte n'importe quel type the map: Map[K, V].

 

Pour cela on utilise une case class qui va comporter 2 champs: 1 pour la clé et un pour la valeur. Ce qui donnera le json suivant:

 

[
  {
    "key": {....},
    "value": {...}
  }, {
    "key": {...},
    "value": {....}
  },
  ...
]

 

Il faut donc définir la case class suivante avec les champs key et value:

case class Entry[K, V](key: K, value: V)

 

Ensuite il faut écrire le format qui permettra de sérialiser notre map vers/depuis json:

import play.api.libs.json._
import play.api.libs.functional.syntax._

object MapFormat {
   def format[K, V](implicit formatKey: Format[K], formatValue: Format[V]) =
     new Format[Map[K, V]] {
        // on définit un format qui permet de sérialiser notre case class Entry
        implicit def formatEntry = (
          (__ \ "key").format[K] ~
          (__ \ "value").format[V]
        )(Entry.apply, unlift(Entry.unapply[K, V]))
       
// Apparemment Json.format[Entry[K, V]] ne fonctionne pas
       // (Assertion error at runtime)


      // gère la transformation Map[K, V] vers json

     override def writes(entries: Map[K, V]): JsValue =
        // on transforme notre map en sequence d'Entry et on sérialise vers json
        Json.toJson(entries.map { case (key, value) => Entry(key, value)})

      // gère la transformtion json -> Map[K, V]
      override
def reads(json: JsValue): JsResult[Map[K, V]] =
         // parse le json en List[Entry[K, V]]
         // puis extrait les paires clé/valeur pour en faire une map

         Json.fromJson[List[Entry[K, V]]](json).map(
           _.map(entry => entry.key -> entry.value).toMap
        )
   }
}

 

L'utilisation est la suivante:

// définit les type pour les clés et les valeurs
case class MyKey(underlying: String)

case class MyValue(underlying: String)
// ainsi que les format qui vont avec
implicit val formatKey = Json.format[MyKey]
implicit val formatValue = Json.format[MyValue]
implicit val mapFormat = MapFormat.format[MyKey, MyValue]
// définit notre map
val myMap = Map(
   MyKey("1") -> MyValue("A"),
   MyKey("2") -> MyValue("B")
)
val json = Json.toJson(myMap)

Ce qui produit le json suivant:

[
  {
    "key": {
     
"underlying": "1"
   },
    "value": {
     
"underlying": "A"
   }
  }, {
    "key": {
     
"underlying""2"
   },
    "value": {
     
"underlying": "B"
   }
  }
]

Ici les types MyKey and MyValue sont intentionnellement trop simple. Mais ce qui est bien c'est que le format fonctionne avec n'importe quel type du moment qu'il y a un format disponible.

Et enfin les formats pour les types MyKey et MyValue sont normalement définis dans les companions object pour éviter des problèmes d'import.

Voir les commentaires

Rédigé par Bliz

Publié dans #Scala

Repost 0

Publié le 26 Septembre 2016

Il peut être intéressant de limiter les nombres de cores CPU disponible pour un conteneur.

Par exemple on peut vouloir n'utiliser qu'un seul core pour les conteneurs docker de façon à laisser assez de CPU disponible pour l'hôte.

docker permet de préciser les cores CPU utilisable par un conteneur grâce à l'option --cpus-set.

Cette option accept soit une liste de nombres et/ou d'intervalles.

Par exemple

--cpus-set 0 # CPU 0
--cpus-set 0-3 # CPU 0, 1, 2 et 3
--cpus-set 0,2-4 # CPU 0, 2, 3 et 4

et dans une commande docker run ça donne quelque chose comme:

docker run --cpus-set 0 <image> <commande>

Voir les commentaires

Rédigé par Bliz

Publié dans #docker

Repost 0