Mar 10 2021

Pourquoi Ansible Met à Jour les Paquets en Hold et Comment y Remédier

Publié par sous Ansible

J’écrivais un nouveau rôle Ansible pour mettre à jour toutes mes VMs pour réaliser un apt update suivi d’un apt upgrade. J’utilise toujours une vieille version de Rancher qui ne fonctionne qu’avec la version 18.06 du paquet docker-ce sur lequel j’aimerais appliquer un apt hold.

Une première tâche met le paquet en hold c’est-à-dire en interdit la mise à jour avec le module Ansible Dpkg, comme recommandé sur de nombreux sites web.
Une deuxième et troisième étapes exécutent un apt update et apt full upgrade de mon système avec le module Ansible apt.

- name: keep docker from being updated on Rancher nodes
  dpkg_selections:
    name: docker-ce
    selection: hold
- name: apt update cache
  apt:
    update_cache: yes
  changed_when: False

- name: apt full-upgrade
  apt:
    upgrade: full


J’ai ensuite lancé mon playbook plein de confiance et, constaté que docker-ce avait été mis à jour! Bizarrement, les distributions Ubuntu semblent impactées, alors que ca fonctionne bien sur la famille Debian.


La page du module Ansible apt mentionne « Option full, lance une full-upgrade aptitude ».
Vérifions le paquet en hold après la 1re étape:

$ dpkg -l | grep docker
hi  docker-ce 18.06.3~ce~3-0~ubuntu. amd64. Docker: the open-source application container engine


La même chose avec aptitude:

$ aptitude search ~i | grep docker
i  docker-ce - Docker: the open-source application container engine

h pour hold est MANQUANT!


apt-get et aptitude semblent reposer sur des fonctions hold différentes, d’où « dpkg –selections » qui ne permet pas de s’assurer qu’aptitude (la commande qui se charge des upgrades) ne touchera pas aux paquets « holdés ».


Et maintenant?
Nous avons de la chance, le module Ansible apt propose un moyen de forcer la mise à jour avec apt-get au lieu d’aptitude

- name: apt full-upgrade
  apt:
    upgrade: full
    force_apt_get: yes


Problème résolu !

 

Aucune Réponse

Mar 05 2021

Modifier le DEFINER et la Sécurité des Procédures/Fonctions Mysql

Publié par sous Mysql

La sécurité des procédures et fonctions Mysql est paramétrée sur DEFINER par défaut, comme décrit dans le chapitre « Create Procedure and create function chapter » sur mysql.com.
Pourquoi est-ce important? N’importe qui ayant le privilège EXECUTE peut lancer la procédure ou la fonction avec les droits du DEFINER. Ce n’est peut-être pas souhaitable.

Une erreur peut survenir lorsque que quelqu’un essaie d’exécuter la procédure/fonction dont le « definer » ou auteur a été supprimé.
ERROR 1449 (HY000): The user specified as a definer (‘definer’@’localhost’) does not exist
On peut alors en venir à devoir changer le definer et/ou le type de sécurité sur de nombreuses procédures et fonctions.
Il est intéressant de noter qu’un utilisateur supprimé n’est pas gênant pour Mysql lors d’un dump ou d’une restauration contrairement aux vues pour lesquelles une erreur est retournée.


Tout d’abord, on peut jeter un oeil global aux procédures et fonctions avec les 2 commandes basiques:

SHOW FUNCTION STATUS;
SHOW PROCEDURE STATUS;

On peut aussi ajouter LIKE ‘ma_proc’, ou WHERE Db LIKE ‘ma_base’ pour filtrer les résultats.


Il est toujours possible de modifier un à un les definers et la sécurité avec Mysql Workbench, ou en les recréant en SQL mais le plus rapide est de les changer tous d’un coup en ligne de commande (restreindre la mise à jour en adaptant le WHERE):

UPDATE mysql.proc SET security_type='INVOKER'
WHERE security_type='DEFINER';


On peut aussi mettre à jour le DEFINER avec la requête suivante:

UPDATE mysql.proc SET definer='root@localhost'
WHERE NOT definer='root@localhost';

 

Aucune Réponse

Oct 18 2020

Enregistrer un Slave Jenkins avec Ansible

Publié par sous Ansible,Jenkins

Nous avons vu précédemment comment ajouter un esclave Jenkins en appelant une API REST avec Curl. Automatisons ceci avec Ansible pour avoir un nouveau noeud disponible en quelques minutes!

Vous aurez tout d’abord besoin d’un utilisateur Jenkins et son token associé avec les bons droits. « Agent connect » et « create » devraient suffire. J’appellerai cet utilisateur « node » tout simplement. Connectez-vous sur Jenkins avec cet utilisateur et créez un nouveau token.

Slave Jenkins avec Ansible


Les détails du nouveau noeud doivent être passés à l’URL REST. Intégrons ces paramètres dans un template Jinja2 comme ceci:
 

{
   "name": "{{ jenkins_node }}",
   "nodeDescription": "slave {{ jenkins_node }}",
   "numExecutors": "{{ jenkins_numExecutors }}",
   "remoteFS": "{{ jenkins_remoteFS }}",
   "labelString": "{{ jenkins_label }}",
   "mode": "EXCLUSIVE",
   "": [
      "hudson.slaves.JNLPLauncher",
      "hudson.slaves.RetentionStrategy$Always"
   ],
   "launcher": {
      "stapler-class": "hudson.slaves.JNLPLauncher",
      "$class": "hudson.slaves.JNLPLauncher",
      "workDirSettings": {
         "disabled": true,
         "workDirPath": "",
         "internalDir": "remoting",
         "failIfWorkDirIsMissing": false
      },
      "tunnel": "",
      "vmargs": ""
   },
   "retentionStrategy": {
      "stapler-class": "hudson.slaves.RetentionStrategy$Always",
      "$class": "hudson.slaves.RetentionStrategy$Always"
   },
   "nodeProperties": {
      "stapler-class-bag": "true",
      "hudson-slaves-EnvironmentVariablesNodeProperty": {
         "env": [
            {
               "key": "JAVA_HOME",
               "value": "{{ java_home }}"
            }
         ]
      },
      "_comment:": {
         "hudson-tools-ToolLocationNodeProperty": {
           "locations": [
               {
                  "key": "hudson.model.JDK$DescriptorImpl@JAVA-8",
                  "home": "/usr/bin/java"
               }
            ]
         }
      }
   }
}

 
Adaptez le modèle selon vos besoins, si vous souhaitez un agent SSH par exemple.

Les variables qui vont être remplacées dans le template peuvent être définies dans le fichier « default » suivant:

jenkins_slave_user: jenkins-slave
jenkins_token: xxxxxxde2152xxxxxxaa339exxxxxx48d6
jenkins_user: node
jenkins_url: https://jenkins.domain.lan
jenkins_node: "{{ansible_hostname}}"
jenkins_numExecutors: 4
jenkins_remoteFS: /home/jenkins-slave
jenkins_label: "label_1 label_2 label_3"
java_home: /usr/lib/jvm/java-8-openjdk-amd64/

 
jenkins_user se connectera au master et créera le nouveau noeud, en s’authentifiant avec le jenkins_token créé précédemment.
jenkins_slave_user est l’utilisateur système qui lancera le service Jenkins sur le node.

Nous pouvons maintenant ajouter une tâche Ansible à notre rôle. Nous appelons tout d’abord l’API REST:

- name: création du noeud sur le maître Jenkins
  uri:
    url: "{{jenkins_url}}/computer/doCreateItem?name={{ jenkins_node }}&type=hudson.slaves.DumbSlave"
    method: POST
    body_format: form-urlencoded
    force_basic_auth: yes
    user: "{{ jenkins_user }}"
    password: "{{jenkins_token }}"
    body: "json={{ lookup('template', 'node.json.j2', convert_data=False) }}"
    return_content: yes
    status_code: 200, 302, 400
  register: webpage

 
J’ai ajouté le code de retour 400 au cas où le noeud existe déjà mais vous pouvez l’enlever si vous préférez que ca s’arrête dans ce cas. Je le passe en échec si l’erreur n’est pas ‘already exists’:

- name: continue au cas où l'agent existe déjà
  fail:
  when: >
          webpage.status == '400'
          and 'already exists' not in webpage.x_error

 
Le service agent Jenkins a besoin d’une clé du master pour démarrer. La clé est disponible dans la page de l’agent au format XML.

- name: récupération du contenu de la page de l'agent
  uri:
    url: "{{jenkins_url}}/computer/{{jenkins_node}}/slave-agent.jnlp"
    method: POST
    body_format: form-urlencoded
    force_basic_auth: yes
    user: "{{ jenkins_user }}"
    password: "{{ jenkins_token }}"
    return_content: yes
    status_code: 200
  register: slavepage

- name: récupération de la clé contenu dans le xml
  xml:
    xmlstring: "{{slavepage.content}}"
    xpath: /jnlp/application-desc/argument
    content: text
  register: secretxml

 
La clé sera stockée dans le fichier /etc/default/jenkins-slave de l’utilisateur système qui est chargé au démarrage du service.
En voici le template:

JENKINS_USER="jenkins-slave"
JENKINS_WORKDIR=$(eval echo "~$JENKINS_USER")
JENKINS_URL={{ jenkins_url }}
JENKINS_NODENAME=$(hostname)
JENKINS_SECRET={{ jenkins_secret }}
JAVA_ARGS="-Xmx6g"

 
Ajoutez l’init script. Nous pouvons maintenant copier ces 2 fichiers:

- name: copie du fichier de paramètres de jenkins-slave
  template:
    src: jenkins-slave-default.j2
    dest: /etc/default/jenkins-slave
    owner: jenkins-slave
    group: jenkins-slave
    mode: 0600
  vars:
    jenkins_secret: "{{secretxml.matches[0].argument}}"
  register: jenkins_config

- name: Copie de l'init script jenkins-slave
  copy:
    src: jenkins-slave-init
    dest: /etc/init.d/jenkins-slave
    owner: root
    group: root
    mode: 0755

 
Et nous nous assurons que le service est bien démarré:

- name: redémarrage et activation du service jenkins-slave si besoin
  service:
    name: jenkins-slave
    enabled: yes
    state: restarted
  when: jenkins_config.changed

- name: démarrage et activation du service jenkins-slave
  service:
    name: jenkins-slave
    enabled: yes
    state: started

 
Ces étapes sont la base mais vous pouvez faire bien plus comme ajouter la création de l’utilisateur système Jenkins, ajouter votre propre autorité de certification si vous êtes sur une IP privée, et bien plus.

Voyez aussi comment accélérer Ansible et optimiser vos temps de déploiement.

 

Aucune Réponse

Avr 22 2020

Enregistrer un Esclave Jenkins par API REST

Publié par sous Jenkins

Voici comment enregistrer un noeud Jenkins automatiquement avec un appel à une API REST sur le maître.
Le plus gros du travail est de créer le code json qui décrit le nouvel esclave Jenkins. La configuration peut être légèrement différente selon les paramètres du noeud que vous souhaitez appliquer.
Pour obtenir exactement ce que vous voulez, vous pouvez créer un esclave test manuellement et capturer l’objet JSON dans l’onglet réseau des outils développeur de votre navigateur tout en cliquant sur « Sauver ». En attendant, voici un exemple, présumant que l’agent se lance via un script de démarrage:

{
   "name": "mon_esclave_jenkins",
   "nodeDescription": "mon esclave Jenkins",
   "numExecutors": "2",
   "remoteFS": "/home/jenkins",
   "labelString": "slave",
   "mode": "EXCLUSIVE",
   "": [
      "hudson.slaves.JNLPLauncher",
      "hudson.slaves.RetentionStrategy$Always"
   ],
   "launcher": {
      "stapler-class": "hudson.slaves.JNLPLauncher",
      "$class": "hudson.slaves.JNLPLauncher",
      "workDirSettings": {
         "disabled": true,
         "workDirPath": "",
         "internalDir": "remoting",
         "failIfWorkDirIsMissing": false
      },
      "tunnel": "",
      "vmargs": ""
   },
   "retentionStrategy": {
      "stapler-class": "hudson.slaves.RetentionStrategy$Always",
      "$class": "hudson.slaves.RetentionStrategy$Always"
   },
   "nodeProperties": {
      "stapler-class-bag": "true",
      "hudson-slaves-EnvironmentVariablesNodeProperty": {
         "env": [
            {
               "key": "JAVA_HOME",
               "value": "/usr/lib/jvm/java-8-openjdk-amd64"
            }
         ]
      },
      "_comment:": {
         "hudson-tools-ToolLocationNodeProperty": {
           "locations": [
               {
                  "key": "hudson.model.JDK$DescriptorImpl@JAVA-8",
                  "home": "/usr/bin/java"
               }
            ]
         }
      }
   }
}

 
Il ne reste qu’à définir les 3 variables d’environnement suivantes:

jenkins_user=mon_esclave_jenkins
jenkins_token=mon_token_jenkins
jenkins_url=https://jenkins.mondomaine.lan

 
Et faire un post du fichier JSON à l’aide d’une simple requête curl:

$ curl -L -s -o /dev/null -w "%{http_code}" -u $jenkins_user:$jenkins_token \
-H "Content-Type:application/x-www-form-urlencoded" -X POST \
-d "json=$(cat /tmp/node.json)" \
"$jenkins_url/computer/doCreateItem?name=mon_esclave_jenkins&type=hudson.slaves.DumbSlave"; \
echo
200

 
Si vous n’obtenez pas un code de réponse 200, exécutez la même chose en omettant « -o /dev/null » pour débugguer.
Certains diront que l’on peut aussi utiliser d’autres outils comme Jenkins CLI ou des plugins mais l’API REST de Jenkins fonctionne à travers les firewalls et reste assez simple à mettre en oeuvre.
Dans le prochain article, j’utiliserai cette méthode pour enregistrer un agent Jenkins avec Ansible automatiquement.

 

Aucune Réponse

Mai 17 2018

Le pilote de l’explorateur a reçu trop de datagrammes non autorisés

Publié par sous AS400

Je n’arrêtais pas de recevoir des events ID 8016 avec « bowser » en libellé dans le journal d’évènements système de Windows. Ceux-ci peuvent être générés par des serveurs IBM i (AS400):
 
« Le pilote de l’explorateur a reçu trop de datagrammes non autorisés de l’ordinateur distant AS400 vers le nom DOMAINE sur le transport NetBT_Tcpip_{0D11505D-12FC-4A5E-CC8E-8377D23692FD}. La donnée est le datagramme. Aucun nouvel événement ne sera généré jusqu’à ce que la fréquence de réinitialisation soit expirée. »
 
Voici comment s’en débarrasser:
Ouvrir System i Navigator ou Navigator for i
Naviguer dans Réseau, Serveurs, Serveurs TCP/IP
Sélectionner IBM i NetServer, cliquer sur l’onglet Actions et sélectionner Propriétés

IBM i NetServer


Dans la nouvelle fenêtre, aller dans l’onglet Avancé, cliquer sur « Prochain démarrage » et décocher « Envoyer annonces de présence »
 

Propriétés NetServer IBM i


Vous ne devriez plus recevoir de message d’erreur de datagrammes illégaux désormais.

 

Aucune Réponse

« Précédent - Suivant »